From 938e8c962174e51551f713223ef4ef7a84f026fc Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 13:06:18 +0200 Subject: [PATCH 01/15] remove old ui scene --- crates/re_space_view_spatial/src/scene/mod.rs | 26 +---------- .../src/scene/parts/mod.rs | 43 +++++++++++++++++++ .../src/scene/picking.rs | 19 +++++--- .../src/scene/primitives.rs | 43 ------------------- crates/re_space_view_spatial/src/ui.rs | 36 +++++++++------- crates/re_space_view_spatial/src/ui_2d.rs | 7 +-- crates/re_space_view_spatial/src/ui_3d.rs | 7 +-- 7 files changed, 86 insertions(+), 95 deletions(-) diff --git a/crates/re_space_view_spatial/src/scene/mod.rs b/crates/re_space_view_spatial/src/scene/mod.rs index 3225a249b651..0cdf65ea2a88 100644 --- a/crates/re_space_view_spatial/src/scene/mod.rs +++ b/crates/re_space_view_spatial/src/scene/mod.rs @@ -5,7 +5,7 @@ mod primitives; pub use contexts::{SpatialSceneContext, TransformContext, UnreachableTransform}; pub use parts::{SpatialScenePartCollection, SpatialScenePartData}; -pub use picking::{PickingContext, PickingHitType, PickingRayHit, PickingResult}; +pub use picking::{PickableUiRect, PickingContext, PickingHitType, PickingRayHit, PickingResult}; pub use primitives::SceneSpatialPrimitives; use ahash::HashMap; @@ -14,8 +14,7 @@ use re_components::{ClassId, InstanceKey, KeypointId}; use re_data_store::{EntityPath, InstancePathHash}; use re_renderer::{Color32, Size}; use re_viewer_context::{ - auto_color, AnnotationMap, Scene, ScenePartCollection, SceneQuery, SpaceViewHighlights, - TypedScene, ViewerContext, + auto_color, AnnotationMap, Scene, SceneQuery, SpaceViewHighlights, TypedScene, ViewerContext, }; use crate::{space_camera_3d::SpaceCamera3D, SpatialSpaceViewClass}; @@ -53,20 +52,9 @@ pub struct UiLabel { pub labeled_instance: InstancePathHash, } -/// Data necessary to setup the ui [`SceneSpatial`] but of no interest to `re_renderer`. -#[derive(Default)] -pub struct SceneSpatialUiData { - pub labels: Vec, - - /// Picking any any of these rects cause the referred instance to be hovered. - /// Only use this for 2d overlays! - pub pickable_ui_rects: Vec<(egui::Rect, InstancePathHash)>, -} - pub struct SceneSpatial { pub annotation_map: AnnotationMap, pub primitives: SceneSpatialPrimitives, - pub ui: SceneSpatialUiData, // TODO(andreas): Temporary field. The hosting struct will be removed once SpatialScene is fully ported to the SpaceViewClass framework. pub scene: TypedScene, @@ -86,7 +74,6 @@ impl SceneSpatial { Self { annotation_map: Default::default(), primitives: SceneSpatialPrimitives::new(re_ctx), - ui: Default::default(), // TODO(andreas): Workaround for not having default on `Scene`. Soon not needed anyways scene: Default::default(), draw_data: Default::default(), @@ -114,15 +101,6 @@ impl SceneSpatial { scene.populate(ctx, query, &re_space_view::EmptySpaceViewState, highlights); self.primitives.any_outlines = scene.highlights.any_outlines(); - self.primitives.recalculate_bounding_box(); - - for scene_part in scene.parts.vec_mut() { - if let Some(data) = scene_part.data() { - self.ui.labels.extend(data.ui_labels.iter().cloned()); - self.primitives.bounding_box = - self.primitives.bounding_box.union(data.bounding_box); - } - } self.draw_data.extend( scene diff --git a/crates/re_space_view_spatial/src/scene/parts/mod.rs b/crates/re_space_view_spatial/src/scene/parts/mod.rs index 65f992282e94..99576a00c637 100644 --- a/crates/re_space_view_spatial/src/scene/parts/mod.rs +++ b/crates/re_space_view_spatial/src/scene/parts/mod.rs @@ -29,6 +29,8 @@ use re_viewer_context::{ use crate::{scene::Keypoints, SpatialSpaceViewClass}; +use super::UiLabel; + type SpatialSpaceViewState = EmptySpaceViewState; #[derive(Default)] @@ -70,6 +72,47 @@ impl ScenePartCollection for SpatialScenePartCollection { } } +impl SpatialScenePartCollection { + fn vec(&self) -> Vec<&dyn re_viewer_context::ScenePart> { + let Self { + points2d, + points3d, + arrows3d, + boxes2d, + boxes3d, + cameras, + lines2d, + lines3d, + meshes, + images, + } = self; + vec![ + points2d, points3d, arrows3d, boxes2d, boxes3d, cameras, lines2d, lines3d, meshes, + images, + ] + } + + pub fn calculate_bounding_box(&self) -> macaw::BoundingBox { + let mut bounding_box = macaw::BoundingBox::nothing(); + for scene_part in self.vec() { + if let Some(data) = scene_part.data() { + bounding_box = bounding_box.union(data.bounding_box); + } + } + bounding_box + } + + pub fn collect_ui_labels(&self) -> Vec { + let mut ui_labels = Vec::new(); + for scene_part in self.vec() { + if let Some(data) = scene_part.data() { + ui_labels.extend(data.ui_labels.iter().cloned()); + } + } + ui_labels + } +} + /// Computes the instance hash that should be used for picking (in turn for selecting/hover) /// /// TODO(andreas): Resolve the hash-for-picking when retrieving the picking result instead of doing it ahead of time here to speed up things. diff --git a/crates/re_space_view_spatial/src/scene/picking.rs b/crates/re_space_view_spatial/src/scene/picking.rs index b6b2f6b3e098..f9d65a92bf98 100644 --- a/crates/re_space_view_spatial/src/scene/picking.rs +++ b/crates/re_space_view_spatial/src/scene/picking.rs @@ -5,7 +5,7 @@ use re_data_store::InstancePathHash; use re_log_types::InstanceKey; use re_renderer::PickingLayerProcessor; -use super::{parts::Image, SceneSpatialUiData}; +use super::parts::Image; use crate::{eye::Eye, instance_hash_conversions::instance_path_hash_from_picking_layer_id}; #[derive(Clone, PartialEq, Eq)] @@ -108,7 +108,7 @@ impl PickingContext { gpu_readback_identifier: re_renderer::GpuReadbackIdentifier, previous_picking_result: &Option, images: &[Image], - ui_data: &SceneSpatialUiData, + ui_rects: &[PickableUiRect], ) -> PickingResult { re_tracing::profile_function!(); @@ -121,7 +121,7 @@ impl PickingContext { ); let mut rect_hits = picking_textured_rects(self, images); rect_hits.sort_by(|a, b| b.depth_offset.cmp(&a.depth_offset)); - let ui_rect_hits = picking_ui_rects(self, ui_data); + let ui_rect_hits = picking_ui_rects(self, ui_rects); let mut hits = Vec::new(); @@ -285,18 +285,23 @@ fn picking_textured_rects(context: &PickingContext, images: &[Image]) -> Vec Option { re_tracing::profile_function!(); let egui_pos = egui::pos2(context.pointer_in_space2d.x, context.pointer_in_space2d.y); - for (bbox, instance_hash) in &ui_data.pickable_ui_rects { - if bbox.contains(egui_pos) { + for ui_rect in ui_rects { + if ui_rect.rect.contains(egui_pos) { // Handle only a single ui rectangle (exit right away, ignore potential overlaps) return Some(PickingRayHit { - instance_path_hash: *instance_hash, + instance_path_hash: ui_rect.instance_hash, space_position: context.ray_in_world.origin, hit_type: PickingHitType::GuiOverlay, depth_offset: 0, diff --git a/crates/re_space_view_spatial/src/scene/primitives.rs b/crates/re_space_view_spatial/src/scene/primitives.rs index 7d3570d189a5..92d449f437f0 100644 --- a/crates/re_space_view_spatial/src/scene/primitives.rs +++ b/crates/re_space_view_spatial/src/scene/primitives.rs @@ -12,13 +12,7 @@ use super::SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES; /// In the future, this will be more limited as we're going to gpu staging data as soon as possible /// which is very slow to read. See [#594](https://github.com/rerun-io/rerun/pull/594) pub struct SceneSpatialPrimitives { - /// Estimated bounding box of all data in scene coordinates. Accumulated. - pub(super) bounding_box: macaw::BoundingBox, - - pub num_primitives: usize, - pub line_strips: LineStripSeriesBuilder, - pub any_outlines: bool, } @@ -29,49 +23,12 @@ const AXIS_COLOR_Z: Color32 = Color32::from_rgb(80, 80, 255); impl SceneSpatialPrimitives { pub fn new(re_ctx: &mut re_renderer::RenderContext) -> Self { Self { - bounding_box: macaw::BoundingBox::nothing(), - num_primitives: 0, line_strips: LineStripSeriesBuilder::new(re_ctx) .radius_boost_in_ui_points_for_outlines(SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES), any_outlines: false, } } - /// bounding box covering the rendered scene - pub fn bounding_box(&self) -> macaw::BoundingBox { - self.bounding_box - } - - /// Number of primitives. Rather arbitrary what counts as a primitive so use this only for heuristic purposes! - pub fn num_primitives(&self) -> usize { - let Self { - bounding_box: _, - num_primitives, - line_strips, - any_outlines: _, - } = &self; - - line_strips.vertices.len() + num_primitives - } - - pub fn recalculate_bounding_box(&mut self) { - re_tracing::profile_function!(); - - let Self { - bounding_box, - num_primitives: _, - line_strips, - any_outlines: _, - } = self; - - // We don't need a very accurate bounding box, so in order to save some time, - // we calculate a per batch bounding box for lines and points. - for (batch, vertex_iter) in line_strips.iter_vertices_by_batch() { - let batch_bb = macaw::BoundingBox::from_points(vertex_iter.map(|v| v.position)); - *bounding_box = bounding_box.union(batch_bb.transform_affine3(&batch.world_from_obj)); - } - } - pub fn add_axis_lines( &mut self, transform: macaw::IsoTransform, diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index 2a1b19dc3f7b..a5fcef194ff7 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -16,13 +16,13 @@ use re_viewer_context::{ use super::{ eye::Eye, - scene::{PickingHitType, PickingResult, SceneSpatialUiData}, + scene::{PickingHitType, PickingResult}, ui_2d::View2DState, ui_3d::View3DState, }; -use crate::scene::SceneSpatial; + use crate::{ - scene::UiLabelTarget, + scene::{PickableUiRect, SceneSpatial, UiLabel, UiLabelTarget}, ui_2d::view_2d, ui_3d::{view_3d, SpaceSpecs}, }; @@ -376,7 +376,7 @@ impl ViewSpatialState { space_view_id: SpaceViewId, entity_properties: &EntityPropertyMap, ) { - self.scene_bbox = scene.primitives.bounding_box(); + self.scene_bbox = scene.scene.parts.calculate_bounding_box(); if self.scene_bbox_accum.is_nothing() { self.scene_bbox_accum = self.scene_bbox; } else { @@ -386,7 +386,11 @@ impl ViewSpatialState { if self.nav_mode.is_auto() { self.nav_mode = EditableAutoValue::Auto(scene.preferred_navigation_mode(space)); } - self.scene_num_primitives = scene.primitives.num_primitives(); + self.scene_num_primitives = scene + .scene + .context + .num_3d_primitives + .load(std::sync::atomic::Ordering::Relaxed); let store = &ctx.store_db.entity_db.data_store; match *self.nav_mode.get() { @@ -518,20 +522,21 @@ fn axis_name(axis: Option) -> String { } pub fn create_labels( - scene_ui: &mut SceneSpatialUiData, + labels: &[UiLabel], ui_from_canvas: egui::emath::RectTransform, eye3d: &Eye, parent_ui: &mut egui::Ui, highlights: &SpaceViewHighlights, nav_mode: SpatialNavigationMode, -) -> Vec { +) -> (Vec, Vec) { re_tracing::profile_function!(); - let mut label_shapes = Vec::with_capacity(scene_ui.labels.len() * 2); + let mut label_shapes = Vec::with_capacity(labels.len() * 2); + let mut ui_rects = Vec::with_capacity(labels.len()); let ui_from_world_3d = eye3d.ui_from_world(*ui_from_canvas.to()); - for label in &scene_ui.labels { + for label in labels { let (wrap_width, text_anchor_pos) = match label.target { UiLabelTarget::Rect(rect) => { // TODO(#1640): 2D labels are not visible in 3D for now. @@ -609,13 +614,13 @@ pub fn create_labels( label_shapes.push(egui::Shape::rect_filled(bg_rect, 3.0, fill_color)); label_shapes.push(egui::Shape::galley(text_rect.center_top(), galley)); - scene_ui.pickable_ui_rects.push(( - ui_from_canvas.inverse().transform_rect(bg_rect), - label.labeled_instance, - )); + ui_rects.push(PickableUiRect { + rect: ui_from_canvas.inverse().transform_rect(bg_rect), + instance_hash: label.labeled_instance, + }); } - label_shapes + (label_shapes, ui_rects) } pub fn outline_config(gui_ctx: &egui::Context) -> OutlineConfig { @@ -672,6 +677,7 @@ pub fn picking( space_view_id: SpaceViewId, state: &mut ViewSpatialState, scene: &SceneSpatial, + ui_rects: &[PickableUiRect], space: &EntityPath, entity_properties: &EntityPropertyMap, ) -> egui::Response { @@ -715,7 +721,7 @@ pub fn picking( space_view_id.gpu_readback_id(), &state.previous_picking_result, &scene.scene.parts.images.images, - &scene.ui, + ui_rects, ); state.previous_picking_result = Some(picking_result.clone()); diff --git a/crates/re_space_view_spatial/src/ui_2d.rs b/crates/re_space_view_spatial/src/ui_2d.rs index 3ee337d0fd36..c2d261216792 100644 --- a/crates/re_space_view_spatial/src/ui_2d.rs +++ b/crates/re_space_view_spatial/src/ui_2d.rs @@ -224,7 +224,7 @@ pub fn view_2d( ui: &mut egui::Ui, state: &mut ViewSpatialState, space: &EntityPath, - mut scene: SceneSpatial, + scene: SceneSpatial, scene_rect_accum: Rect, space_view_id: SpaceViewId, entity_properties: &EntityPropertyMap, @@ -305,8 +305,8 @@ pub fn view_2d( let mut view_builder = ViewBuilder::new(ctx.render_ctx, target_config); // Create labels now since their shapes participate are added to scene.ui for picking. - let label_shapes = create_labels( - &mut scene.ui, + let (label_shapes, ui_rects) = create_labels( + &scene.scene.parts.collect_ui_labels(), ui_from_canvas, &eye, ui, @@ -326,6 +326,7 @@ pub fn view_2d( space_view_id, state, &scene, + &ui_rects, space, entity_properties, ); diff --git a/crates/re_space_view_spatial/src/ui_3d.rs b/crates/re_space_view_spatial/src/ui_3d.rs index 3b122c66c23f..e7740a5c518b 100644 --- a/crates/re_space_view_spatial/src/ui_3d.rs +++ b/crates/re_space_view_spatial/src/ui_3d.rs @@ -363,8 +363,8 @@ pub fn view_3d( let mut view_builder = ViewBuilder::new(ctx.render_ctx, target_config); // Create labels now since their shapes participate are added to scene.ui for picking. - let label_shapes = create_labels( - &mut scene.ui, + let (label_shapes, ui_rects) = create_labels( + &scene.scene.parts.collect_ui_labels(), RectTransform::from_to(rect, rect), &eye, ui, @@ -384,6 +384,7 @@ pub fn view_3d( space_view_id, state, &scene, + &ui_rects, space, entity_properties, ); @@ -459,7 +460,7 @@ pub fn view_3d( } if state.state_3d.show_bbox { - let bbox = scene.primitives.bounding_box(); + let bbox = state.scene_bbox_accum; if bbox.is_something() && bbox.is_finite() { let scale = bbox.size(); let translation = bbox.center(); From b823cf419cf93387ddbcea9bdf27df5dbec37d49 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 13:10:49 +0200 Subject: [PATCH 02/15] remove annotations from old scene --- crates/re_space_view_spatial/src/scene/mod.rs | 6 +----- crates/re_space_view_spatial/src/ui.rs | 8 +++++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/crates/re_space_view_spatial/src/scene/mod.rs b/crates/re_space_view_spatial/src/scene/mod.rs index 0cdf65ea2a88..5cdc7c21a42d 100644 --- a/crates/re_space_view_spatial/src/scene/mod.rs +++ b/crates/re_space_view_spatial/src/scene/mod.rs @@ -14,7 +14,7 @@ use re_components::{ClassId, InstanceKey, KeypointId}; use re_data_store::{EntityPath, InstancePathHash}; use re_renderer::{Color32, Size}; use re_viewer_context::{ - auto_color, AnnotationMap, Scene, SceneQuery, SpaceViewHighlights, TypedScene, ViewerContext, + auto_color, Scene, SceneQuery, SpaceViewHighlights, TypedScene, ViewerContext, }; use crate::{space_camera_3d::SpaceCamera3D, SpatialSpaceViewClass}; @@ -53,7 +53,6 @@ pub struct UiLabel { } pub struct SceneSpatial { - pub annotation_map: AnnotationMap, pub primitives: SceneSpatialPrimitives, // TODO(andreas): Temporary field. The hosting struct will be removed once SpatialScene is fully ported to the SpaceViewClass framework. @@ -72,7 +71,6 @@ impl EntityDepthOffsets { impl SceneSpatial { pub fn new(re_ctx: &mut re_renderer::RenderContext) -> Self { Self { - annotation_map: Default::default(), primitives: SceneSpatialPrimitives::new(re_ctx), // TODO(andreas): Workaround for not having default on `Scene`. Soon not needed anyways scene: Default::default(), @@ -89,8 +87,6 @@ impl SceneSpatial { ) { re_tracing::profile_function!(); - self.annotation_map.load(ctx, query); - // TODO(wumpf): Temporary build up of scene. This will be handled by the SpaceViewClass framework later. let mut scene = TypedScene:: { context: SpatialSceneContext::default(), diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index a5fcef194ff7..9f3258939d7b 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -825,17 +825,19 @@ pub fn picking( match ctx.cache .entry::() .entry(tensor) { - Ok(decoded_tensor) => + Ok(decoded_tensor) => { + let annotations = scene.scene.context.annotations.0.find(&instance_path.entity_path); show_zoomed_image_region( ctx.render_ctx, ui, &decoded_tensor, ctx.cache.entry::().entry(&decoded_tensor), - &scene.annotation_map.find(&instance_path.entity_path), + &annotations, decoded_tensor.meter, &tensor_name, [coords[0] as _, coords[1] as _], - ), + ); + }, Err(err) => re_log::warn_once!( "Encountered problem decoding tensor at path {tensor_name}: {err}" ), From 0a87ff8f71a1b04003616cfa6c819903b75a21c0 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 13:12:50 +0200 Subject: [PATCH 03/15] remove any_outlines from old scene --- crates/re_space_view_spatial/src/scene/mod.rs | 2 -- crates/re_space_view_spatial/src/scene/primitives.rs | 2 -- crates/re_space_view_spatial/src/ui_2d.rs | 6 ++---- crates/re_space_view_spatial/src/ui_3d.rs | 5 +++-- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/crates/re_space_view_spatial/src/scene/mod.rs b/crates/re_space_view_spatial/src/scene/mod.rs index 5cdc7c21a42d..263e609ff276 100644 --- a/crates/re_space_view_spatial/src/scene/mod.rs +++ b/crates/re_space_view_spatial/src/scene/mod.rs @@ -96,8 +96,6 @@ impl SceneSpatial { self.draw_data = scene.populate(ctx, query, &re_space_view::EmptySpaceViewState, highlights); - self.primitives.any_outlines = scene.highlights.any_outlines(); - self.draw_data.extend( scene .context diff --git a/crates/re_space_view_spatial/src/scene/primitives.rs b/crates/re_space_view_spatial/src/scene/primitives.rs index 92d449f437f0..e2c423977d67 100644 --- a/crates/re_space_view_spatial/src/scene/primitives.rs +++ b/crates/re_space_view_spatial/src/scene/primitives.rs @@ -13,7 +13,6 @@ use super::SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES; /// which is very slow to read. See [#594](https://github.com/rerun-io/rerun/pull/594) pub struct SceneSpatialPrimitives { pub line_strips: LineStripSeriesBuilder, - pub any_outlines: bool, } const AXIS_COLOR_X: Color32 = Color32::from_rgb(255, 25, 25); @@ -25,7 +24,6 @@ impl SceneSpatialPrimitives { Self { line_strips: LineStripSeriesBuilder::new(re_ctx) .radius_boost_in_ui_points_for_outlines(SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES), - any_outlines: false, } } diff --git a/crates/re_space_view_spatial/src/ui_2d.rs b/crates/re_space_view_spatial/src/ui_2d.rs index c2d261216792..260b01e330f3 100644 --- a/crates/re_space_view_spatial/src/ui_2d.rs +++ b/crates/re_space_view_spatial/src/ui_2d.rs @@ -294,10 +294,8 @@ pub fn view_2d( canvas_from_ui, &space.to_string(), state.auto_size_config(), - scene - .primitives - .any_outlines, - pinhole, + scene.scene.highlights.any_outlines(), + pinhole ) else { return response; }; diff --git a/crates/re_space_view_spatial/src/ui_3d.rs b/crates/re_space_view_spatial/src/ui_3d.rs index e7740a5c518b..a6bee89d4f28 100644 --- a/crates/re_space_view_spatial/src/ui_3d.rs +++ b/crates/re_space_view_spatial/src/ui_3d.rs @@ -355,8 +355,9 @@ pub fn view_3d( auto_size_config: state.auto_size_config(), outline_config: scene - .primitives - .any_outlines + .scene + .highlights + .any_outlines() .then(|| outline_config(ui.ctx())), }; From 867be9f476b622b275eaed30b47fed53e1e631c2 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 15:33:31 +0200 Subject: [PATCH 04/15] remove old spatial scene types --- .../re_space_view_spatial/src/axis_lines.rs | 69 +++++++++ crates/re_space_view_spatial/src/lib.rs | 3 +- .../src/scene/contexts/depth_offsets.rs | 8 +- .../scene/contexts/shared_render_builders.rs | 28 +++- crates/re_space_view_spatial/src/scene/mod.rs | 138 ++++-------------- .../src/scene/parts/cameras.rs | 9 +- .../src/scene/parts/mod.rs | 6 +- .../src/scene/primitives.rs | 87 ----------- .../src/space_view_class.rs | 10 +- crates/re_space_view_spatial/src/ui.rs | 38 +++-- crates/re_space_view_spatial/src/ui_2d.rs | 26 ++-- crates/re_space_view_spatial/src/ui_3d.rs | 114 ++++++++------- .../src/ui_renderer_bridge.rs | 5 - .../src/space_view_class.rs | 2 +- .../src/space_view_class.rs | 2 +- .../re_viewer_context/src/space_view/scene.rs | 9 +- .../src/space_view/space_view_class_impl.rs | 6 +- crates/re_viewport/src/space_view.rs | 60 +++----- 18 files changed, 277 insertions(+), 343 deletions(-) create mode 100644 crates/re_space_view_spatial/src/axis_lines.rs delete mode 100644 crates/re_space_view_spatial/src/scene/primitives.rs diff --git a/crates/re_space_view_spatial/src/axis_lines.rs b/crates/re_space_view_spatial/src/axis_lines.rs new file mode 100644 index 000000000000..bfe747d5700a --- /dev/null +++ b/crates/re_space_view_spatial/src/axis_lines.rs @@ -0,0 +1,69 @@ +use egui::Color32; +use re_data_store::EntityPath; +use re_log_types::InstanceKey; +use re_renderer::LineStripSeriesBuilder; + +const AXIS_COLOR_X: Color32 = Color32::from_rgb(255, 25, 25); +const AXIS_COLOR_Y: Color32 = Color32::from_rgb(0, 240, 0); +const AXIS_COLOR_Z: Color32 = Color32::from_rgb(80, 80, 255); + +pub fn add_axis_lines( + line_builder: &mut LineStripSeriesBuilder, + transform: macaw::IsoTransform, + ent_path: Option<&EntityPath>, + axis_length: f32, +) { + use re_renderer::renderer::LineStripFlags; + + // TODO(andreas): It would be nice if could display the semantics (left/right/up) as a tooltip on hover. + let line_radius = re_renderer::Size::new_scene(axis_length * 0.05); + let origin = transform.translation(); + + let mut line_batch = + line_builder + .batch("origin axis") + .picking_object_id(re_renderer::PickingLayerObjectId( + ent_path.map_or(0, |p| p.hash64()), + )); + let picking_instance_id = re_renderer::PickingLayerInstanceId(InstanceKey::SPLAT.0); + + line_batch + .add_segment( + origin, + origin + transform.transform_vector3(glam::Vec3::X) * axis_length, + ) + .radius(line_radius) + .color(AXIS_COLOR_X) + .flags( + LineStripFlags::FLAG_COLOR_GRADIENT + | LineStripFlags::FLAG_CAP_END_TRIANGLE + | LineStripFlags::FLAG_CAP_START_ROUND, + ) + .picking_instance_id(picking_instance_id); + line_batch + .add_segment( + origin, + origin + transform.transform_vector3(glam::Vec3::Y) * axis_length, + ) + .radius(line_radius) + .color(AXIS_COLOR_Y) + .flags( + LineStripFlags::FLAG_COLOR_GRADIENT + | LineStripFlags::FLAG_CAP_END_TRIANGLE + | LineStripFlags::FLAG_CAP_START_ROUND, + ) + .picking_instance_id(picking_instance_id); + line_batch + .add_segment( + origin, + origin + transform.transform_vector3(glam::Vec3::Z) * axis_length, + ) + .radius(line_radius) + .color(AXIS_COLOR_Z) + .flags( + LineStripFlags::FLAG_COLOR_GRADIENT + | LineStripFlags::FLAG_CAP_END_TRIANGLE + | LineStripFlags::FLAG_CAP_START_ROUND, + ) + .picking_instance_id(picking_instance_id); +} diff --git a/crates/re_space_view_spatial/src/lib.rs b/crates/re_space_view_spatial/src/lib.rs index 0b3caeb53360..c23530e294c1 100644 --- a/crates/re_space_view_spatial/src/lib.rs +++ b/crates/re_space_view_spatial/src/lib.rs @@ -2,6 +2,7 @@ //! //! Space Views that show entities in a 2D or 3D spatial relationship. +mod axis_lines; mod eye; mod instance_hash_conversions; mod mesh_cache; @@ -18,4 +19,4 @@ mod ui_renderer_bridge; pub use space_view_class::SpatialSpaceViewClass; pub use scene::{SceneSpatial, TransformContext, UnreachableTransform}; -pub use ui::{SpatialNavigationMode, ViewSpatialState}; +pub use ui::{SpatialNavigationMode, SpatialSpaceViewState}; diff --git a/crates/re_space_view_spatial/src/scene/contexts/depth_offsets.rs b/crates/re_space_view_spatial/src/scene/contexts/depth_offsets.rs index ad5b4468b977..a54dc6f37b1d 100644 --- a/crates/re_space_view_spatial/src/scene/contexts/depth_offsets.rs +++ b/crates/re_space_view_spatial/src/scene/contexts/depth_offsets.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, BTreeSet}; use nohash_hasher::IntMap; use re_components::DrawOrder; -use re_log_types::{Component, EntityPathHash}; +use re_log_types::{Component, EntityPath, EntityPathHash}; use re_viewer_context::{ArchetypeDefinition, SceneContextPart}; /// Context for creating a mapping from [`DrawOrder`] to [`re_renderer::DepthOffset`]. @@ -118,3 +118,9 @@ impl SceneContextPart for EntityDepthOffsets { .collect(); } } + +impl EntityDepthOffsets { + pub fn get(&self, ent_path: &EntityPath) -> Option { + self.per_entity.get(&ent_path.hash()).cloned() + } +} diff --git a/crates/re_space_view_spatial/src/scene/contexts/shared_render_builders.rs b/crates/re_space_view_spatial/src/scene/contexts/shared_render_builders.rs index efbde262dcec..095acf0a1dde 100644 --- a/crates/re_space_view_spatial/src/scene/contexts/shared_render_builders.rs +++ b/crates/re_space_view_spatial/src/scene/contexts/shared_render_builders.rs @@ -1,5 +1,5 @@ use parking_lot::{Mutex, MutexGuard}; -use re_renderer::{LineStripSeriesBuilder, PointCloudBuilder}; +use re_renderer::{LineStripSeriesBuilder, PointCloudBuilder, RenderContext}; use re_viewer_context::{ArchetypeDefinition, SceneContextPart}; use crate::scene::{ @@ -22,6 +22,32 @@ impl SharedRenderBuilders { pub fn points(&self) -> MutexGuard<'_, PointCloudBuilder> { self.points.as_ref().unwrap().lock() } + + pub fn queuable_draw_data( + &mut self, + render_ctx: &mut RenderContext, + ) -> Vec { + let mut result = Vec::new(); + result.extend(self.lines.take().and_then( + |l| match l.into_inner().to_draw_data(render_ctx) { + Ok(d) => Some(d.into()), + Err(err) => { + re_log::error_once!("Failed to build line strip draw data: {err}"); + None + } + }, + )); + result.extend(self.points.take().and_then( + |l| match l.into_inner().to_draw_data(render_ctx) { + Ok(d) => Some(d.into()), + Err(err) => { + re_log::error_once!("Failed to build point draw data: {err}"); + None + } + }, + )); + result + } } impl SceneContextPart for SharedRenderBuilders { diff --git a/crates/re_space_view_spatial/src/scene/mod.rs b/crates/re_space_view_spatial/src/scene/mod.rs index 263e609ff276..64efd4c56ddb 100644 --- a/crates/re_space_view_spatial/src/scene/mod.rs +++ b/crates/re_space_view_spatial/src/scene/mod.rs @@ -1,31 +1,25 @@ mod contexts; mod parts; mod picking; -mod primitives; pub use contexts::{SpatialSceneContext, TransformContext, UnreachableTransform}; pub use parts::{SpatialScenePartCollection, SpatialScenePartData}; pub use picking::{PickableUiRect, PickingContext, PickingHitType, PickingRayHit, PickingResult}; -pub use primitives::SceneSpatialPrimitives; use ahash::HashMap; use re_components::{ClassId, InstanceKey, KeypointId}; use re_data_store::{EntityPath, InstancePathHash}; use re_renderer::{Color32, Size}; -use re_viewer_context::{ - auto_color, Scene, SceneQuery, SpaceViewHighlights, TypedScene, ViewerContext, -}; +use re_viewer_context::{auto_color, TypedScene}; -use crate::{space_camera_3d::SpaceCamera3D, SpatialSpaceViewClass}; +use crate::SpatialSpaceViewClass; use super::SpatialNavigationMode; use self::contexts::SpatialSceneEntityContext; -use contexts::EntityDepthOffsets; - -const SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES: f32 = 1.5; +pub const SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES: f32 = 1.5; const SIZE_BOOST_IN_POINTS_FOR_POINT_OUTLINES: f32 = 2.5; #[derive(Clone)] @@ -52,115 +46,39 @@ pub struct UiLabel { pub labeled_instance: InstancePathHash, } -pub struct SceneSpatial { - pub primitives: SceneSpatialPrimitives, - - // TODO(andreas): Temporary field. The hosting struct will be removed once SpatialScene is fully ported to the SpaceViewClass framework. - pub scene: TypedScene, - pub draw_data: Vec, -} - +pub type SceneSpatial = TypedScene; pub type Keypoints = HashMap<(ClassId, i64), HashMap>; -impl EntityDepthOffsets { - pub fn get(&self, ent_path: &EntityPath) -> Option { - self.per_entity.get(&ent_path.hash()).cloned() - } -} - -impl SceneSpatial { - pub fn new(re_ctx: &mut re_renderer::RenderContext) -> Self { - Self { - primitives: SceneSpatialPrimitives::new(re_ctx), - // TODO(andreas): Workaround for not having default on `Scene`. Soon not needed anyways - scene: Default::default(), - draw_data: Default::default(), - } +/// Heuristic whether the default way of looking at this scene should be 2d or 3d. +pub fn preferred_navigation_mode( + scene: &SceneSpatial, + space_info_path: &EntityPath, +) -> SpatialNavigationMode { + // If there's any space cameras that are not the root, we need to go 3D, otherwise we can't display them. + if scene + .parts + .cameras + .space_cameras + .iter() + .any(|camera| &camera.ent_path != space_info_path) + { + return SpatialNavigationMode::ThreeD; } - /// Loads all 3D objects into the scene according to the given query. - pub fn load( - &mut self, - ctx: &mut ViewerContext<'_>, - query: &SceneQuery<'_>, - highlights: SpaceViewHighlights, - ) { - re_tracing::profile_function!(); - - // TODO(wumpf): Temporary build up of scene. This will be handled by the SpaceViewClass framework later. - let mut scene = TypedScene:: { - context: SpatialSceneContext::default(), - parts: SpatialScenePartCollection::default(), - highlights: Default::default(), - }; - self.draw_data = - scene.populate(ctx, query, &re_space_view::EmptySpaceViewState, highlights); - - self.draw_data.extend( - scene - .context - .shared_render_builders - .lines - .take() - .and_then(|l| match l.into_inner().to_draw_data(ctx.render_ctx) { - Ok(d) => Some(d.into()), - Err(err) => { - re_log::error_once!("Failed to build line strip draw data: {err}"); - None - } - }), - ); - self.draw_data.extend( - scene - .context - .shared_render_builders - .points - .take() - .and_then(|l| match l.into_inner().to_draw_data(ctx.render_ctx) { - Ok(d) => Some(d.into()), - Err(err) => { - re_log::error_once!("Failed to build point draw data: {err}"); - None - } - }), - ); - - self.scene = scene; + if !scene.parts.images.images.is_empty() { + return SpatialNavigationMode::TwoD; } - const CAMERA_COLOR: Color32 = Color32::from_rgb(150, 150, 150); - - pub fn space_cameras(&self) -> &[SpaceCamera3D] { - &self.scene.parts.cameras.space_cameras + if scene + .context + .num_3d_primitives + .load(std::sync::atomic::Ordering::Relaxed) + == 0 + { + return SpatialNavigationMode::TwoD; } - /// Heuristic whether the default way of looking at this scene should be 2d or 3d. - pub fn preferred_navigation_mode(&self, space_info_path: &EntityPath) -> SpatialNavigationMode { - // If there's any space cameras that are not the root, we need to go 3D, otherwise we can't display them. - if self - .space_cameras() - .iter() - .any(|camera| &camera.ent_path != space_info_path) - { - return SpatialNavigationMode::ThreeD; - } - - if !self.scene.parts.images.images.is_empty() { - return SpatialNavigationMode::TwoD; - } - - if self - .scene - .context - .num_3d_primitives - .load(std::sync::atomic::Ordering::Relaxed) - == 0 - { - return SpatialNavigationMode::TwoD; - } - - SpatialNavigationMode::ThreeD - } + SpatialNavigationMode::ThreeD } pub fn load_keypoint_connections( diff --git a/crates/re_space_view_spatial/src/scene/parts/cameras.rs b/crates/re_space_view_spatial/src/scene/parts/cameras.rs index 88466b59d6b1..99241be64758 100644 --- a/crates/re_space_view_spatial/src/scene/parts/cameras.rs +++ b/crates/re_space_view_spatial/src/scene/parts/cameras.rs @@ -11,11 +11,11 @@ use re_viewer_context::{SpaceViewHighlights, SpaceViewOutlineMasks}; use super::{instance_path_hash_for_picking, SpatialScenePartData, SpatialSpaceViewState}; use crate::{ instance_hash_conversions::picking_layer_id_from_instance_path_hash, - scene::{contexts::SpatialSceneContext, SceneSpatial}, - space_camera_3d::SpaceCamera3D, - SpatialSpaceViewClass, + scene::contexts::SpatialSceneContext, space_camera_3d::SpaceCamera3D, SpatialSpaceViewClass, }; +const CAMERA_COLOR: re_renderer::Color32 = re_renderer::Color32::from_rgb(150, 150, 150); + /// Determine the view coordinates (i.e.) the axis semantics. /// /// The recommended way to log this is on the object holding the extrinsic camera properties @@ -152,7 +152,6 @@ impl CamerasPart { ]; let radius = re_renderer::Size::new_points(1.0); - let color = SceneSpatial::CAMERA_COLOR; let num_instances = 1; // There is only ever one instance of `Transform` per entity. let instance_path_for_picking = instance_path_hash_for_picking( ent_path, @@ -171,7 +170,7 @@ impl CamerasPart { let lines = batch .add_segments(segments.into_iter()) .radius(radius) - .color(color) + .color(CAMERA_COLOR) .flags(LineStripFlags::FLAG_CAP_END_ROUND | LineStripFlags::FLAG_CAP_START_ROUND) .picking_instance_id(instance_layer_id.instance); diff --git a/crates/re_space_view_spatial/src/scene/parts/mod.rs b/crates/re_space_view_spatial/src/scene/parts/mod.rs index 99576a00c637..bf380869f84f 100644 --- a/crates/re_space_view_spatial/src/scene/parts/mod.rs +++ b/crates/re_space_view_spatial/src/scene/parts/mod.rs @@ -16,8 +16,6 @@ mod spatial_scene_part_data; pub use images::Image; pub use spatial_scene_part_data::SpatialScenePartData; -use re_space_view::EmptySpaceViewState; - use ahash::HashMap; use std::sync::Arc; @@ -27,12 +25,10 @@ use re_viewer_context::{ Annotations, DefaultColor, ResolvedAnnotationInfo, ScenePartCollection, SceneQuery, }; -use crate::{scene::Keypoints, SpatialSpaceViewClass}; +use crate::{scene::Keypoints, ui::SpatialSpaceViewState, SpatialSpaceViewClass}; use super::UiLabel; -type SpatialSpaceViewState = EmptySpaceViewState; - #[derive(Default)] pub struct SpatialScenePartCollection { pub points2d: points2d::Points2DPart, diff --git a/crates/re_space_view_spatial/src/scene/primitives.rs b/crates/re_space_view_spatial/src/scene/primitives.rs deleted file mode 100644 index e2c423977d67..000000000000 --- a/crates/re_space_view_spatial/src/scene/primitives.rs +++ /dev/null @@ -1,87 +0,0 @@ -use egui::Color32; -use re_data_store::EntityPath; -use re_log_types::InstanceKey; -use re_renderer::LineStripSeriesBuilder; - -use super::SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES; - -/// Primitives sent off to `re_renderer`. -/// (Some meta information still relevant to ui setup as well) -/// -/// TODO(andreas): Right now we're using `re_renderer` data structures for reading (bounding box). -/// In the future, this will be more limited as we're going to gpu staging data as soon as possible -/// which is very slow to read. See [#594](https://github.com/rerun-io/rerun/pull/594) -pub struct SceneSpatialPrimitives { - pub line_strips: LineStripSeriesBuilder, -} - -const AXIS_COLOR_X: Color32 = Color32::from_rgb(255, 25, 25); -const AXIS_COLOR_Y: Color32 = Color32::from_rgb(0, 240, 0); -const AXIS_COLOR_Z: Color32 = Color32::from_rgb(80, 80, 255); - -impl SceneSpatialPrimitives { - pub fn new(re_ctx: &mut re_renderer::RenderContext) -> Self { - Self { - line_strips: LineStripSeriesBuilder::new(re_ctx) - .radius_boost_in_ui_points_for_outlines(SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES), - } - } - - pub fn add_axis_lines( - &mut self, - transform: macaw::IsoTransform, - ent_path: Option<&EntityPath>, - axis_length: f32, - ) { - use re_renderer::renderer::LineStripFlags; - - // TODO(andreas): It would be nice if could display the semantics (left/right/up) as a tooltip on hover. - let line_radius = re_renderer::Size::new_scene(axis_length * 0.05); - let origin = transform.translation(); - - let mut line_batch = self.line_strips.batch("origin axis").picking_object_id( - re_renderer::PickingLayerObjectId(ent_path.map_or(0, |p| p.hash64())), - ); - let picking_instance_id = re_renderer::PickingLayerInstanceId(InstanceKey::SPLAT.0); - - line_batch - .add_segment( - origin, - origin + transform.transform_vector3(glam::Vec3::X) * axis_length, - ) - .radius(line_radius) - .color(AXIS_COLOR_X) - .flags( - LineStripFlags::FLAG_COLOR_GRADIENT - | LineStripFlags::FLAG_CAP_END_TRIANGLE - | LineStripFlags::FLAG_CAP_START_ROUND, - ) - .picking_instance_id(picking_instance_id); - line_batch - .add_segment( - origin, - origin + transform.transform_vector3(glam::Vec3::Y) * axis_length, - ) - .radius(line_radius) - .color(AXIS_COLOR_Y) - .flags( - LineStripFlags::FLAG_COLOR_GRADIENT - | LineStripFlags::FLAG_CAP_END_TRIANGLE - | LineStripFlags::FLAG_CAP_START_ROUND, - ) - .picking_instance_id(picking_instance_id); - line_batch - .add_segment( - origin, - origin + transform.transform_vector3(glam::Vec3::Z) * axis_length, - ) - .radius(line_radius) - .color(AXIS_COLOR_Z) - .flags( - LineStripFlags::FLAG_COLOR_GRADIENT - | LineStripFlags::FLAG_CAP_END_TRIANGLE - | LineStripFlags::FLAG_CAP_START_ROUND, - ) - .picking_instance_id(picking_instance_id); - } -} diff --git a/crates/re_space_view_spatial/src/space_view_class.rs b/crates/re_space_view_spatial/src/space_view_class.rs index 5f25a737f6f3..fcdeaeba1a2e 100644 --- a/crates/re_space_view_spatial/src/space_view_class.rs +++ b/crates/re_space_view_spatial/src/space_view_class.rs @@ -1,12 +1,14 @@ -use re_space_view::EmptySpaceViewState; use re_viewer_context::SpaceViewClassImpl; -use crate::scene::{SpatialSceneContext, SpatialScenePartCollection, SpatialScenePartData}; +use crate::{ + scene::{SpatialSceneContext, SpatialScenePartCollection, SpatialScenePartData}, + SpatialSpaceViewState, +}; pub struct SpatialSpaceViewClass; impl SpaceViewClassImpl for SpatialSpaceViewClass { - type SpaceViewState = EmptySpaceViewState; + type SpaceViewState = SpatialSpaceViewState; type SceneContext = SpatialSceneContext; type ScenePartCollection = SpatialScenePartCollection; type ScenePartData = SpatialScenePartData; @@ -38,7 +40,7 @@ impl SpaceViewClassImpl for SpatialSpaceViewClass { _ctx: &mut re_viewer_context::ViewerContext<'_>, _ui: &mut egui::Ui, _state: &mut Self::SpaceViewState, - _scene: &re_viewer_context::TypedScene, + _scene: &mut re_viewer_context::TypedScene, ) { // TODO(andreas) } diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index 9f3258939d7b..5de3d7ea751c 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -11,7 +11,7 @@ use re_renderer::OutlineConfig; use re_space_view::{DataBlueprintTree, ScreenshotMode}; use re_viewer_context::{ HoverHighlight, HoveredSpace, Item, SelectionHighlight, SpaceViewHighlights, SpaceViewId, - TensorDecodeCache, TensorStatsCache, UiVerbosity, ViewerContext, + SpaceViewState, TensorDecodeCache, TensorStatsCache, UiVerbosity, ViewerContext, }; use super::{ @@ -21,6 +21,7 @@ use super::{ ui_3d::View3DState, }; +use crate::scene::preferred_navigation_mode; use crate::{ scene::{PickableUiRect, SceneSpatial, UiLabel, UiLabelTarget}, ui_2d::view_2d, @@ -62,7 +63,7 @@ impl From for WidgetText { } #[derive(Clone)] -pub struct ViewSpatialState { +pub struct SpatialSpaceViewState { /// How the scene is navigated. pub nav_mode: EditableAutoValue, @@ -87,7 +88,7 @@ pub struct ViewSpatialState { auto_size_config: re_renderer::AutoSizeConfig, } -impl Default for ViewSpatialState { +impl Default for SpatialSpaceViewState { fn default() -> Self { Self { nav_mode: EditableAutoValue::Auto(SpatialNavigationMode::ThreeD), @@ -105,7 +106,17 @@ impl Default for ViewSpatialState { } } -impl ViewSpatialState { +impl SpaceViewState for SpatialSpaceViewState { + fn as_any(&self) -> &dyn std::any::Any { + self + } + + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { + self + } +} + +impl SpatialSpaceViewState { pub fn auto_size_config(&self) -> re_renderer::AutoSizeConfig { let mut config = self.auto_size_config; if config.point_radius.is_auto() { @@ -365,18 +376,16 @@ impl ViewSpatialState { }); } - // TODO(andreas): split into smaller parts, some of it shouldn't be part of the ui path and instead scene loading. - #[allow(clippy::too_many_arguments)] pub fn view_spatial( &mut self, ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, space: &EntityPath, - scene: SceneSpatial, + scene: &mut SceneSpatial, space_view_id: SpaceViewId, entity_properties: &EntityPropertyMap, ) { - self.scene_bbox = scene.scene.parts.calculate_bounding_box(); + self.scene_bbox = scene.parts.calculate_bounding_box(); if self.scene_bbox_accum.is_nothing() { self.scene_bbox_accum = self.scene_bbox; } else { @@ -384,10 +393,9 @@ impl ViewSpatialState { } if self.nav_mode.is_auto() { - self.nav_mode = EditableAutoValue::Auto(scene.preferred_navigation_mode(space)); + self.nav_mode = EditableAutoValue::Auto(preferred_navigation_mode(scene, space)); } self.scene_num_primitives = scene - .scene .context .num_3d_primitives .load(std::sync::atomic::Ordering::Relaxed); @@ -675,7 +683,7 @@ pub fn picking( eye: Eye, view_builder: &mut re_renderer::view_builder::ViewBuilder, space_view_id: SpaceViewId, - state: &mut ViewSpatialState, + state: &mut SpatialSpaceViewState, scene: &SceneSpatial, ui_rects: &[PickableUiRect], space: &EntityPath, @@ -720,7 +728,7 @@ pub fn picking( ctx.render_ctx, space_view_id.gpu_readback_id(), &state.previous_picking_result, - &scene.scene.parts.images.images, + &scene.parts.images.images, ui_rects, ); state.previous_picking_result = Some(picking_result.clone()); @@ -826,7 +834,7 @@ pub fn picking( .entry::() .entry(tensor) { Ok(decoded_tensor) => { - let annotations = scene.scene.context.annotations.0.find(&instance_path.entity_path); + let annotations = scene.context.annotations.0.find(&instance_path.entity_path); show_zoomed_image_region( ctx.render_ctx, ui, @@ -872,7 +880,9 @@ pub fn picking( pos: hovered_point, tracked_space_camera: state.state_3d.tracked_camera.clone(), point_in_space_cameras: scene - .space_cameras() + .parts + .cameras + .space_cameras .iter() .map(|cam| { ( diff --git a/crates/re_space_view_spatial/src/ui_2d.rs b/crates/re_space_view_spatial/src/ui_2d.rs index 260b01e330f3..33b25482c2d0 100644 --- a/crates/re_space_view_spatial/src/ui_2d.rs +++ b/crates/re_space_view_spatial/src/ui_2d.rs @@ -14,7 +14,7 @@ use super::{ }; use crate::{ scene::SceneSpatial, - ui::{outline_config, ViewSpatialState}, + ui::{outline_config, SpatialSpaceViewState}, ui_renderer_bridge::{fill_view_builder, ScreenBackground}, }; @@ -222,9 +222,9 @@ pub fn help_text(re_ui: &re_ui::ReUi) -> egui::WidgetText { pub fn view_2d( ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, - state: &mut ViewSpatialState, + state: &mut SpatialSpaceViewState, space: &EntityPath, - scene: SceneSpatial, + scene: &mut SceneSpatial, scene_rect_accum: Rect, space_view_id: SpaceViewId, entity_properties: &EntityPropertyMap, @@ -294,7 +294,7 @@ pub fn view_2d( canvas_from_ui, &space.to_string(), state.auto_size_config(), - scene.scene.highlights.any_outlines(), + scene.highlights.any_outlines(), pinhole ) else { return response; @@ -304,11 +304,11 @@ pub fn view_2d( // Create labels now since their shapes participate are added to scene.ui for picking. let (label_shapes, ui_rects) = create_labels( - &scene.scene.parts.collect_ui_labels(), + &scene.parts.collect_ui_labels(), ui_from_canvas, &eye, ui, - &scene.scene.highlights, + &scene.highlights, SpatialNavigationMode::TwoD, ); @@ -323,15 +323,22 @@ pub fn view_2d( &mut view_builder, space_view_id, state, - &scene, + scene, &ui_rects, space, entity_properties, ); } - // TODO(wumpf): Temporary manual inseration of drawdata. The SpaceViewClass framework will take this over. - for draw_data in scene.draw_data { + // TODO(wumpf): Temporary manual insertion of drawdata. The SpaceViewClass framework will take this over. + for draw_data in scene.todo_remove_draw_data.replace(Vec::new()) { + view_builder.queue_draw(draw_data); + } + for draw_data in scene + .context + .shared_render_builders + .queuable_draw_data(ctx.render_ctx) + { view_builder.queue_draw(draw_data); } @@ -351,7 +358,6 @@ pub fn view_2d( let command_buffer = match fill_view_builder( ctx.render_ctx, &mut view_builder, - scene.primitives, &ScreenBackground::ClearColor(ui.visuals().extreme_bg_color.into()), ) { Ok(command_buffer) => command_buffer, diff --git a/crates/re_space_view_spatial/src/ui_3d.rs b/crates/re_space_view_spatial/src/ui_3d.rs index a6bee89d4f28..2d43e9a1fa2d 100644 --- a/crates/re_space_view_spatial/src/ui_3d.rs +++ b/crates/re_space_view_spatial/src/ui_3d.rs @@ -8,7 +8,7 @@ use re_data_store::EntityPropertyMap; use re_log_types::EntityPath; use re_renderer::{ view_builder::{Projection, TargetConfiguration, ViewBuilder}, - Size, + LineStripSeriesBuilder, Size, }; use re_space_view::controls::{ DRAG_PAN3D_BUTTON, RESET_VIEW_BUTTON_TEXT, ROLL_MOUSE, ROLL_MOUSE_ALT, ROLL_MOUSE_MODIFIER, @@ -17,17 +17,15 @@ use re_space_view::controls::{ use re_viewer_context::{gpu_bridge, HoveredSpace, Item, SpaceViewId, ViewerContext}; use crate::{ - scene::SceneSpatial, + axis_lines::add_axis_lines, + scene::{SceneSpatial, SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES}, space_camera_3d::SpaceCamera3D, - ui::{create_labels, outline_config, picking, screenshot_context_menu, ViewSpatialState}, + ui::{create_labels, outline_config, picking, screenshot_context_menu, SpatialSpaceViewState}, ui_renderer_bridge::{fill_view_builder, ScreenBackground}, SpatialNavigationMode, }; -use super::{ - eye::{Eye, OrbitEye}, - scene::SceneSpatialPrimitives, -}; +use super::eye::{Eye, OrbitEye}; // --- @@ -281,15 +279,16 @@ pub fn help_text(re_ui: &re_ui::ReUi) -> egui::WidgetText { pub fn view_3d( ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, - state: &mut ViewSpatialState, + state: &mut SpatialSpaceViewState, space: &EntityPath, space_view_id: SpaceViewId, - mut scene: SceneSpatial, + scene: &mut SceneSpatial, entity_properties: &EntityPropertyMap, ) { re_tracing::profile_function!(); - let highlights = &scene.scene.highlights; + let highlights = &scene.highlights; + let space_cameras = &scene.parts.cameras.space_cameras; let (rect, mut response) = ui.allocate_at_least(ui.available_size(), egui::Sense::click_and_drag()); @@ -305,10 +304,9 @@ pub fn view_3d( Some(_) => 4.0, None => 0.0, }; - let orbit_eye = - state - .state_3d - .update_eye(&response, &state.scene_bbox_accum, scene.space_cameras()); + let orbit_eye = state + .state_3d + .update_eye(&response, &state.scene_bbox_accum, space_cameras); let did_interact_with_eye = orbit_eye.update(&response, orbit_eye_drag_threshold); let orbit_eye = *orbit_eye; @@ -321,14 +319,20 @@ pub fn view_3d( state.state_3d.camera_before_tracked_camera = None; } + let mut line_builder = LineStripSeriesBuilder::new(ctx.render_ctx) + .radius_boost_in_ui_points_for_outlines(SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES); + // TODO(andreas): This isn't part of the camera, but of the transform https://github.com/rerun-io/rerun/issues/753 - for camera in &scene.scene.parts.cameras.space_cameras { + for camera in space_cameras { let transform = camera.world_from_cam(); let axis_length = eye.approx_pixel_world_size_at(transform.translation(), rect.size()) * 32.0; - scene - .primitives - .add_axis_lines(transform, Some(&camera.ent_path), axis_length); + add_axis_lines( + &mut line_builder, + transform, + Some(&camera.ent_path), + axis_length, + ); } // Determine view port resolution and position. @@ -355,7 +359,6 @@ pub fn view_3d( auto_size_config: state.auto_size_config(), outline_config: scene - .scene .highlights .any_outlines() .then(|| outline_config(ui.ctx())), @@ -365,7 +368,7 @@ pub fn view_3d( // Create labels now since their shapes participate are added to scene.ui for picking. let (label_shapes, ui_rects) = create_labels( - &scene.scene.parts.collect_ui_labels(), + &scene.parts.collect_ui_labels(), RectTransform::from_to(rect, rect), &eye, ui, @@ -384,7 +387,7 @@ pub fn view_3d( &mut view_builder, space_view_id, state, - &scene, + scene, &ui_rects, space, entity_properties, @@ -399,7 +402,7 @@ pub fn view_3d( // While hovering an entity, focuses the camera on it. if let Some(Item::InstancePath(_, instance_path)) = ctx.hovered().first() { - if let Some(camera) = find_camera(scene.space_cameras(), &instance_path.entity_path) { + if let Some(camera) = find_camera(space_cameras, &instance_path.entity_path) { state.state_3d.camera_before_tracked_camera = state.state_3d.orbit_eye.map(|eye| eye.to_eye()); state.state_3d.interpolate_to_eye(camera); @@ -448,16 +451,20 @@ pub fn view_3d( show_projections_from_2d_space( ctx, - &mut scene, + &mut line_builder, + space_cameras, &state.state_3d.tracked_camera, &state.scene_bbox_accum, ); if state.state_3d.show_axes { let axis_length = 1.0; // The axes are also a measuring stick - scene - .primitives - .add_axis_lines(macaw::IsoTransform::IDENTITY, None, axis_length); + add_axis_lines( + &mut line_builder, + macaw::IsoTransform::IDENTITY, + None, + axis_length, + ); } if state.state_3d.show_bbox { @@ -470,9 +477,7 @@ pub fn view_3d( Default::default(), translation, ); - scene - .primitives - .line_strips + line_builder .batch("scene_bbox") .add_box_outline(bbox_from_unit_cube) .radius(Size::AUTO) @@ -491,9 +496,7 @@ pub fn view_3d( // Show center of orbit camera when interacting with camera (it's quite helpful). let half_line_length = orbit_eye.orbit_radius * 0.03; - scene - .primitives - .line_strips + line_builder .batch("center orbit orientation help") .add_segments(glam::Vec3::AXES.iter().map(|axis| { ( @@ -514,16 +517,32 @@ pub fn view_3d( } } - // TODO(wumpf): Temporary manual inseration of drawdata. The SpaceViewClass framework will take this over. - for draw_data in scene.draw_data { + // TODO(wumpf): Temporary manual insertion of drawdata. The SpaceViewClass framework will take this over. + for draw_data in scene.todo_remove_draw_data.replace(Vec::new()) { + view_builder.queue_draw(draw_data); + } + for draw_data in scene + .context + .shared_render_builders + .queuable_draw_data(ctx.render_ctx) + { view_builder.queue_draw(draw_data); } + // Commit ui induced lines. + match line_builder.to_draw_data(ctx.render_ctx) { + Ok(line_draw_data) => { + view_builder.queue_draw(line_draw_data); + } + Err(err) => { + re_log::error_once!("Failed to create draw data for lines from ui interaction: {err}"); + } + } + // Composite viewbuilder into egui. let command_buffer = match fill_view_builder( ctx.render_ctx, &mut view_builder, - scene.primitives, &ScreenBackground::GenericSkybox, ) { Ok(command_buffer) => command_buffer, @@ -547,17 +566,14 @@ pub fn view_3d( fn show_projections_from_2d_space( ctx: &mut ViewerContext<'_>, - scene: &mut SceneSpatial, + line_builder: &mut LineStripSeriesBuilder, + space_cameras: &[SpaceCamera3D], tracked_space_camera: &Option, scene_bbox_accum: &BoundingBox, ) { match ctx.selection_state().hovered_space() { HoveredSpace::TwoD { space_2d, pos } => { - if let Some(cam) = scene - .space_cameras() - .iter() - .find(|cam| &cam.ent_path == space_2d) - { + if let Some(cam) = space_cameras.iter().find(|cam| &cam.ent_path == space_2d) { if let Some(ray) = cam.unproject_as_ray(glam::vec2(pos.x, pos.y)) { // Render a thick line to the actual z value if any and a weaker one as an extension // If we don't have a z value, we only render the thick one. @@ -567,12 +583,7 @@ fn show_projections_from_2d_space( cam.picture_plane_distance }; - add_picking_ray( - &mut scene.primitives, - ray, - scene_bbox_accum, - thick_ray_length, - ); + add_picking_ray(line_builder, ray, scene_bbox_accum, thick_ray_length); } } } @@ -585,15 +596,14 @@ fn show_projections_from_2d_space( .as_ref() .map_or(true, |tracked| tracked != camera_path) { - if let Some(cam) = scene - .space_cameras() + if let Some(cam) = space_cameras .iter() .find(|cam| &cam.ent_path == camera_path) { let cam_to_pos = *pos - cam.position(); let distance = cam_to_pos.length(); let ray = macaw::Ray3::from_origin_dir(cam.position(), cam_to_pos / distance); - add_picking_ray(&mut scene.primitives, ray, scene_bbox_accum, distance); + add_picking_ray(line_builder, ray, scene_bbox_accum, distance); } } } @@ -602,12 +612,12 @@ fn show_projections_from_2d_space( } fn add_picking_ray( - primitives: &mut SceneSpatialPrimitives, + line_builder: &mut LineStripSeriesBuilder, ray: macaw::Ray3, scene_bbox_accum: &BoundingBox, thick_ray_length: f32, ) { - let mut line_batch = primitives.line_strips.batch("picking ray"); + let mut line_batch = line_builder.batch("picking ray"); let origin = ray.point_along(0.0); // No harm in making this ray _very_ long. (Infinite messes with things though!) diff --git a/crates/re_space_view_spatial/src/ui_renderer_bridge.rs b/crates/re_space_view_spatial/src/ui_renderer_bridge.rs index ec66d26d402a..32bb15bc4177 100644 --- a/crates/re_space_view_spatial/src/ui_renderer_bridge.rs +++ b/crates/re_space_view_spatial/src/ui_renderer_bridge.rs @@ -1,7 +1,5 @@ use re_renderer::{renderer::GenericSkyboxDrawData, view_builder::ViewBuilder, RenderContext}; -use super::scene::SceneSpatialPrimitives; - pub enum ScreenBackground { GenericSkybox, ClearColor(re_renderer::Rgba), @@ -10,13 +8,10 @@ pub enum ScreenBackground { pub fn fill_view_builder( render_ctx: &mut RenderContext, view_builder: &mut ViewBuilder, - primitives: SceneSpatialPrimitives, background: &ScreenBackground, ) -> anyhow::Result { re_tracing::profile_function!(); - view_builder.queue_draw(primitives.line_strips.to_draw_data(render_ctx)?); - if matches!(background, ScreenBackground::GenericSkybox) { view_builder.queue_draw(GenericSkyboxDrawData::new(render_ctx)); } diff --git a/crates/re_space_view_text/src/space_view_class.rs b/crates/re_space_view_text/src/space_view_class.rs index b6d382e9c240..32da9bb5e7b1 100644 --- a/crates/re_space_view_text/src/space_view_class.rs +++ b/crates/re_space_view_text/src/space_view_class.rs @@ -109,7 +109,7 @@ impl SpaceViewClassImpl for TextSpaceView { ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut Self::SpaceViewState, - scene: &TypedScene, + scene: &mut TypedScene, ) { let scene = &scene.parts; diff --git a/crates/re_space_view_text_box/src/space_view_class.rs b/crates/re_space_view_text_box/src/space_view_class.rs index 44f907b9182c..a27a182f50dc 100644 --- a/crates/re_space_view_text_box/src/space_view_class.rs +++ b/crates/re_space_view_text_box/src/space_view_class.rs @@ -74,7 +74,7 @@ impl SpaceViewClassImpl for TextBoxSpaceView { _ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut Self::SpaceViewState, - scene: &TypedScene, + scene: &mut TypedScene, ) { let scene = &scene.parts; diff --git a/crates/re_viewer_context/src/space_view/scene.rs b/crates/re_viewer_context/src/space_view/scene.rs index c84d8a5d9b78..617ada5fdb2c 100644 --- a/crates/re_viewer_context/src/space_view/scene.rs +++ b/crates/re_viewer_context/src/space_view/scene.rs @@ -20,8 +20,8 @@ pub trait Scene { highlights: SpaceViewHighlights, ) -> Vec; - /// Converts itself to a reference of [`std::any::Any`], which enables downcasting to concrete types. - fn as_any(&self) -> &dyn std::any::Any; + /// Converts itself to a mutable reference of [`std::any::Any`], which enables downcasting to concrete types. + fn as_any_mut(&mut self) -> &mut dyn std::any::Any; } /// Implementation of [`Scene`] for a specific [`SpaceViewClassImpl`]. @@ -29,6 +29,8 @@ pub struct TypedScene { pub context: C::SceneContext, pub parts: C::ScenePartCollection, pub highlights: SpaceViewHighlights, + + pub todo_remove_draw_data: std::cell::Cell>, } impl Default for TypedScene { @@ -37,6 +39,7 @@ impl Default for TypedScene { context: Default::default(), parts: Default::default(), highlights: Default::default(), + todo_remove_draw_data: Default::default(), } } } @@ -77,7 +80,7 @@ impl Scene for TypedScene { .collect() } - fn as_any(&self) -> &dyn std::any::Any { + fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self } } diff --git a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs index 52e412975fb8..b5959cf0af74 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs @@ -58,7 +58,7 @@ pub trait SpaceViewClassImpl: std::marker::Sized { ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut Self::SpaceViewState, - scene: &TypedScene, + scene: &mut TypedScene, ); } @@ -104,9 +104,9 @@ impl SpaceViewClass for T { ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut dyn SpaceViewState, - scene: Box, + mut scene: Box, ) { - let Some(typed_scene) = scene.as_any().downcast_ref() + let Some(typed_scene) = scene.as_any_mut().downcast_mut() else { re_log::error_once!("Unexpected space view state type. Expected {}", std::any::type_name::>()); diff --git a/crates/re_viewport/src/space_view.rs b/crates/re_viewport/src/space_view.rs index 92298c77361c..38edf1298fee 100644 --- a/crates/re_viewport/src/space_view.rs +++ b/crates/re_viewport/src/space_view.rs @@ -1,9 +1,11 @@ use re_arrow_store::Timeline; -use re_data_store::{EntityPath, EntityPropertyMap, EntityTree, InstancePath, TimeInt}; +use re_data_store::{EntityPath, EntityTree, InstancePath, TimeInt}; use re_renderer::ScreenshotProcessor; use re_space_view::{DataBlueprintTree, ScreenshotMode}; -use re_space_view_spatial::{SceneSpatial, ViewSpatialState}; -use re_viewer_context::{SpaceViewClassName, SpaceViewHighlights, SpaceViewId, ViewerContext}; +use re_space_view_spatial::{SceneSpatial, SpatialSpaceViewState}; +use re_viewer_context::{ + Scene, SpaceViewClassName, SpaceViewHighlights, SpaceViewId, ViewerContext, +}; use crate::{ space_info::SpaceInfoCollection, @@ -237,19 +239,20 @@ impl SpaceViewBlueprint { } ViewCategory::Spatial => { - let mut scene = SceneSpatial::new(ctx.render_ctx); - scene.load(ctx, &query, highlights); - view_state - .state_spatial - .update_object_property_heuristics(ctx, &mut self.data_blueprint); - view_state.ui_spatial( - ctx, - ui, - &self.space_path, - scene, - self.id, - self.data_blueprint.data_blueprints_projected(), - ); + let mut scene = SceneSpatial::default(); + let draw_data = + scene.populate(ctx, &query, &view_state.state_spatial, highlights); + scene.todo_remove_draw_data.replace(draw_data); + ui.vertical(|ui| { + view_state.state_spatial.view_spatial( + ctx, + ui, + &self.space_path, + &mut scene, + self.id, + self.data_blueprint.data_blueprints_projected(), + ); + }); } ViewCategory::Tensor => { @@ -319,34 +322,11 @@ pub struct SpaceViewState { pub state_time_series: view_time_series::ViewTimeSeriesState, pub state_bar_chart: view_bar_chart::BarChartState, - pub state_spatial: ViewSpatialState, + pub state_spatial: SpatialSpaceViewState, pub state_tensors: ahash::HashMap, } impl SpaceViewState { - // TODO(andreas): split into smaller parts, some of it shouldn't be part of the ui path and instead scene loading. - #[allow(clippy::too_many_arguments)] - fn ui_spatial( - &mut self, - ctx: &mut ViewerContext<'_>, - ui: &mut egui::Ui, - space: &EntityPath, - scene: SceneSpatial, - space_view_id: SpaceViewId, - entity_properties: &EntityPropertyMap, - ) { - ui.vertical(|ui| { - self.state_spatial.view_spatial( - ctx, - ui, - space, - scene, - space_view_id, - entity_properties, - ); - }); - } - fn ui_tensor( &mut self, ctx: &mut ViewerContext<'_>, From 5aaab97588537a1a431375d5f4f2cfed30b08983 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 15:49:58 +0200 Subject: [PATCH 05/15] make draw_data on `TypedScene` "a thing" wip --- crates/re_data_store/src/entity_properties.rs | 7 ++ .../src/data_blueprint_heuristic.rs | 15 +++ crates/re_space_view/src/lib.rs | 2 + .../src/scene/contexts/mod.rs | 6 + .../contexts/non_interactive_entities.rs | 34 ++++++ .../src/scene/parts/images.rs | 3 + .../src/space_view_class.rs | 23 ++-- crates/re_space_view_spatial/src/ui.rs | 112 +++++++++--------- crates/re_space_view_spatial/src/ui_2d.rs | 21 ++-- crates/re_space_view_spatial/src/ui_3d.rs | 5 +- .../src/space_view_class.rs | 10 +- .../src/space_view_class.rs | 5 +- .../re_viewer_context/src/space_view/scene.rs | 20 ++-- .../src/space_view/space_view_class.rs | 9 +- .../src/space_view/space_view_class_impl.rs | 42 ++++++- crates/re_viewport/src/auto_layout.rs | 32 ++--- crates/re_viewport/src/space_view.rs | 46 ++----- 17 files changed, 232 insertions(+), 160 deletions(-) create mode 100644 crates/re_space_view/src/data_blueprint_heuristic.rs create mode 100644 crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs diff --git a/crates/re_data_store/src/entity_properties.rs b/crates/re_data_store/src/entity_properties.rs index ee3a2087706f..e15169bb4c6a 100644 --- a/crates/re_data_store/src/entity_properties.rs +++ b/crates/re_data_store/src/entity_properties.rs @@ -16,10 +16,12 @@ pub struct EntityPropertyMap { #[cfg(feature = "serde")] impl EntityPropertyMap { + #[inline] pub fn get(&self, entity_path: &EntityPath) -> EntityProperties { self.props.get(entity_path).cloned().unwrap_or_default() } + #[inline] pub fn set(&mut self, entity_path: EntityPath, prop: EntityProperties) { if prop == EntityProperties::default() { self.props.remove(&entity_path); // save space @@ -27,6 +29,11 @@ impl EntityPropertyMap { self.props.insert(entity_path, prop); } } + + #[inline] + pub fn iter(&self) -> impl Iterator { + self.props.iter() + } } // ---------------------------------------------------------------------------- diff --git a/crates/re_space_view/src/data_blueprint_heuristic.rs b/crates/re_space_view/src/data_blueprint_heuristic.rs new file mode 100644 index 000000000000..c792b9f9fcbe --- /dev/null +++ b/crates/re_space_view/src/data_blueprint_heuristic.rs @@ -0,0 +1,15 @@ +use re_viewer_context::ViewerContext; + +use crate::DataBlueprintTree; + +/// Trait implemented by a [`re_viewer_context::SpaceViewState`] to update the data blueprint tree. +/// +/// TODO(wumpf/jleibs): This is an interim construct until we're able to extract the data blueprint via a query +/// and figure out how default/heuristically determined values are handled. +pub trait DataBlueprintHeuristic { + fn update_object_property_heuristics( + &self, + ctx: &mut ViewerContext<'_>, + data_blueprint: &mut DataBlueprintTree, + ); +} diff --git a/crates/re_space_view/src/lib.rs b/crates/re_space_view/src/lib.rs index 1ac9cc4cb7aa..eb99c644ae0b 100644 --- a/crates/re_space_view/src/lib.rs +++ b/crates/re_space_view/src/lib.rs @@ -4,11 +4,13 @@ pub mod controls; mod data_blueprint; +mod data_blueprint_heuristic; mod empty_scene_context; mod empty_space_view_state; mod screenshot; pub use data_blueprint::{DataBlueprintGroup, DataBlueprintTree}; +pub use data_blueprint_heuristic::DataBlueprintHeuristic; pub use empty_scene_context::EmptySceneContext; pub use empty_space_view_state::EmptySpaceViewState; pub use screenshot::ScreenshotMode; diff --git a/crates/re_space_view_spatial/src/scene/contexts/mod.rs b/crates/re_space_view_spatial/src/scene/contexts/mod.rs index 0cf396d954f1..016b2f73e0c8 100644 --- a/crates/re_space_view_spatial/src/scene/contexts/mod.rs +++ b/crates/re_space_view_spatial/src/scene/contexts/mod.rs @@ -1,5 +1,6 @@ mod annotation_context; mod depth_offsets; +mod non_interactive_entities; mod shared_render_builders; mod transform_context; @@ -16,12 +17,15 @@ use re_log_types::EntityPath; use re_renderer::DepthOffset; use re_viewer_context::{Annotations, SceneContext}; +use self::non_interactive_entities::NonInteractiveEntities; + #[derive(Default)] pub struct SpatialSceneContext { pub transforms: TransformContext, pub depth_offsets: EntityDepthOffsets, pub annotations: AnnotationSceneContext, pub shared_render_builders: SharedRenderBuilders, + pub non_interactive_entities: NonInteractiveEntities, pub num_primitives: AtomicUsize, pub num_3d_primitives: AtomicUsize, @@ -34,6 +38,7 @@ impl SceneContext for SpatialSceneContext { depth_offsets, annotations, shared_render_builders, + non_interactive_entities, num_3d_primitives: _, num_primitives: _, } = self; @@ -42,6 +47,7 @@ impl SceneContext for SpatialSceneContext { depth_offsets, annotations, shared_render_builders, + non_interactive_entities, ] } diff --git a/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs b/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs new file mode 100644 index 000000000000..6084477e3494 --- /dev/null +++ b/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs @@ -0,0 +1,34 @@ +use nohash_hasher::IntSet; +use re_log_types::EntityPathHash; +use re_viewer_context::SceneContextPart; + +/// List of all non-interactive entities for lookup during picking evaluation. +#[derive(Default)] +pub struct NonInteractiveEntities(pub IntSet); + +impl SceneContextPart for NonInteractiveEntities { + fn archetypes(&self) -> Vec { + Vec::new() + } + + fn populate( + &mut self, + ctx: &mut re_viewer_context::ViewerContext<'_>, + query: &re_viewer_context::SceneQuery<'_>, + space_view_state: &dyn re_viewer_context::SpaceViewState, + ) { + re_tracing::profile_function!(); + + self.0 = query + .entity_props_map + .iter() + .filter_map(|(entity_path, props)| { + if props.interactive { + None + } else { + Some(entity_path.hash()) + } + }) + .collect() + } +} diff --git a/crates/re_space_view_spatial/src/scene/parts/images.rs b/crates/re_space_view_spatial/src/scene/parts/images.rs index 3680ee651335..6e1bfe3be450 100644 --- a/crates/re_space_view_spatial/src/scene/parts/images.rs +++ b/crates/re_space_view_spatial/src/scene/parts/images.rs @@ -3,6 +3,7 @@ use std::collections::BTreeMap; use egui::NumExt; use itertools::Itertools as _; +use nohash_hasher::IntSet; use re_components::{ ColorRGBA, Component as _, DecodedTensor, DrawOrder, InstanceKey, Pinhole, Tensor, TensorData, TensorDataMeaning, @@ -125,6 +126,7 @@ struct ImageGrouping { pub struct ImagesPart { pub data: SpatialScenePartData, pub images: Vec, + pub depth_cloud_entities: IntSet, } impl ImagesPart { @@ -234,6 +236,7 @@ impl ImagesPart { Ok(cloud) => { self.data .extend_bounding_box(cloud.bbox(), ent_context.world_from_obj); + self.depth_cloud_entities.insert(ent_path.hash()); depth_clouds.push(cloud); return Ok(()); } diff --git a/crates/re_space_view_spatial/src/space_view_class.rs b/crates/re_space_view_spatial/src/space_view_class.rs index fcdeaeba1a2e..16d931f46bf3 100644 --- a/crates/re_space_view_spatial/src/space_view_class.rs +++ b/crates/re_space_view_spatial/src/space_view_class.rs @@ -1,4 +1,5 @@ -use re_viewer_context::SpaceViewClassImpl; +use re_log_types::EntityPath; +use re_viewer_context::{SpaceViewClassImpl, SpaceViewId}; use crate::{ scene::{SpatialSceneContext, SpatialScenePartCollection, SpatialScenePartData}, @@ -28,20 +29,22 @@ impl SpaceViewClassImpl for SpatialSpaceViewClass { fn selection_ui( &self, - _ctx: &mut re_viewer_context::ViewerContext<'_>, - _ui: &mut egui::Ui, - _state: &mut Self::SpaceViewState, + ctx: &mut re_viewer_context::ViewerContext<'_>, + ui: &mut egui::Ui, + state: &mut Self::SpaceViewState, ) { - // TODO(andreas) + state.selection_ui(ctx, ui); } fn ui( &self, - _ctx: &mut re_viewer_context::ViewerContext<'_>, - _ui: &mut egui::Ui, - _state: &mut Self::SpaceViewState, - _scene: &mut re_viewer_context::TypedScene, + ctx: &mut re_viewer_context::ViewerContext<'_>, + ui: &mut egui::Ui, + state: &mut Self::SpaceViewState, + scene: &mut re_viewer_context::TypedScene, + space_origin: &EntityPath, + space_view_id: SpaceViewId, ) { - // TODO(andreas) + state.view_spatial(ctx, ui, scene, space_origin, space_view_id); } } diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index 5de3d7ea751c..4f2335cc656a 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -2,13 +2,15 @@ use eframe::epaint::text::TextWrapping; use egui::{NumExt, WidgetText}; use macaw::BoundingBox; +use nohash_hasher::{IntMap, IntSet}; use re_components::{Pinhole, Tensor, TensorDataMeaning}; use re_data_store::{EditableAutoValue, EntityPath, EntityPropertyMap}; use re_data_ui::{item_ui, DataUi}; use re_data_ui::{show_zoomed_image_region, show_zoomed_image_region_area_outline}; use re_format::format_f32; +use re_log_types::EntityPathHash; use re_renderer::OutlineConfig; -use re_space_view::{DataBlueprintTree, ScreenshotMode}; +use re_space_view::{DataBlueprintHeuristic, DataBlueprintTree, ScreenshotMode}; use re_viewer_context::{ HoverHighlight, HoveredSpace, Item, SelectionHighlight, SpaceViewHighlights, SpaceViewId, SpaceViewState, TensorDecodeCache, TensorStatsCache, UiVerbosity, ViewerContext, @@ -116,6 +118,24 @@ impl SpaceViewState for SpatialSpaceViewState { } } +impl DataBlueprintHeuristic for SpatialSpaceViewState { + fn update_object_property_heuristics( + &self, + ctx: &mut ViewerContext<'_>, + data_blueprint: &mut DataBlueprintTree, + ) { + re_tracing::profile_function!(); + + let query = ctx.current_query(); + + let entity_paths = data_blueprint.entity_paths().clone(); // TODO(andreas): Workaround borrow checker + for entity_path in entity_paths { + self.update_pinhole_property_heuristics(ctx, data_blueprint, &query, &entity_path); + self.update_depth_cloud_property_heuristics(ctx, data_blueprint, &query, &entity_path); + } + } +} + impl SpatialSpaceViewState { pub fn auto_size_config(&self) -> re_renderer::AutoSizeConfig { let mut config = self.auto_size_config; @@ -150,22 +170,6 @@ impl SpatialSpaceViewState { heuristic0.min(heuristic1) } - pub fn update_object_property_heuristics( - &self, - ctx: &mut ViewerContext<'_>, - data_blueprint: &mut DataBlueprintTree, - ) { - re_tracing::profile_function!(); - - let query = ctx.current_query(); - - let entity_paths = data_blueprint.entity_paths().clone(); // TODO(andreas): Workaround borrow checker - for entity_path in entity_paths { - self.update_pinhole_property_heuristics(ctx, data_blueprint, &query, &entity_path); - self.update_depth_cloud_property_heuristics(ctx, data_blueprint, &query, &entity_path); - } - } - fn update_pinhole_property_heuristics( &self, ctx: &mut ViewerContext<'_>, @@ -237,30 +241,24 @@ impl SpatialSpaceViewState { Some(()) } - pub fn selection_ui( - &mut self, - ctx: &mut ViewerContext<'_>, - ui: &mut egui::Ui, - data_blueprint: &DataBlueprintTree, - space_path: &EntityPath, - space_view_id: SpaceViewId, - ) { + pub fn selection_ui(&mut self, ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui) { ctx.re_ui.selection_grid(ui, "spatial_settings_ui") .show(ui, |ui| { let auto_size_world = self.auto_size_world_heuristic(); - ctx.re_ui.grid_left_hand_label(ui, "Space root") - .on_hover_text("The origin is at the origin of this Entity. All transforms are relative to it"); - // Specify space view id only if this is actually part of the space view itself. - // (otherwise we get a somewhat broken link) - item_ui::entity_path_button(ctx, - ui, - data_blueprint - .contains_entity(space_path) - .then_some(space_view_id), - space_path, - ); - ui.end_row(); + // TODO: + // ctx.re_ui.grid_left_hand_label(ui, "Space origin") + // .on_hover_text("The origin is at the origin of this Entity. All transforms are relative to it"); + // // Specify space view id only if this is actually part of the space view itself. + // // (otherwise we get a somewhat broken link) + // item_ui::entity_path_button(ctx, + // ui, + // data_blueprint + // .contains_entity(space_path) + // .then_some(space_view_id), + // space_path, + // ); + // ui.end_row(); ctx.re_ui.grid_left_hand_label(ui, "Default size"); ui.vertical(|ui| { @@ -380,10 +378,9 @@ impl SpatialSpaceViewState { &mut self, ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, - space: &EntityPath, scene: &mut SceneSpatial, + space_origin: &EntityPath, space_view_id: SpaceViewId, - entity_properties: &EntityPropertyMap, ) { self.scene_bbox = scene.parts.calculate_bounding_box(); if self.scene_bbox_accum.is_nothing() { @@ -393,7 +390,7 @@ impl SpatialSpaceViewState { } if self.nav_mode.is_auto() { - self.nav_mode = EditableAutoValue::Auto(preferred_navigation_mode(scene, space)); + self.nav_mode = EditableAutoValue::Auto(preferred_navigation_mode(scene, space_origin)); } self.scene_num_primitives = scene .context @@ -403,17 +400,9 @@ impl SpatialSpaceViewState { let store = &ctx.store_db.entity_db.data_store; match *self.nav_mode.get() { SpatialNavigationMode::ThreeD => { - let coordinates = store.query_latest_component(space, &ctx.current_query()); + let coordinates = store.query_latest_component(space_origin, &ctx.current_query()); self.state_3d.space_specs = SpaceSpecs::from_view_coordinates(coordinates); - view_3d( - ctx, - ui, - self, - space, - space_view_id, - scene, - entity_properties, - ); + view_3d(ctx, ui, self, space_origin, space_view_id, scene); } SpatialNavigationMode::TwoD => { let scene_rect_accum = egui::Rect::from_min_max( @@ -424,11 +413,10 @@ impl SpatialSpaceViewState { ctx, ui, self, - space, scene, - scene_rect_accum, + space_origin, space_view_id, - entity_properties, + scene_rect_accum, ); } } @@ -687,7 +675,6 @@ pub fn picking( scene: &SceneSpatial, ui_rects: &[PickableUiRect], space: &EntityPath, - entity_properties: &EntityPropertyMap, ) -> egui::Response { re_tracing::profile_function!(); @@ -742,14 +729,23 @@ pub fn picking( let Some(mut instance_path) = hit.instance_path_hash.resolve(&ctx.store_db.entity_db) else { continue; }; - let ent_properties = entity_properties.get(&instance_path.entity_path); - if !ent_properties.interactive { + if !scene + .context + .non_interactive_entities + .0 + .contains(&instance_path.entity_path.hash()) + { continue; } // Special hover ui for images. + let is_depth_cloud = scene + .parts + .images + .depth_cloud_entities + .contains(&instance_path.entity_path.hash()); let picked_image_with_coords = if hit.hit_type == PickingHitType::TexturedRect - || *ent_properties.backproject_depth.get() + || is_depth_cloud { let store = &ctx.store_db.entity_db.data_store; store @@ -758,7 +754,7 @@ pub fn picking( // If we're here because of back-projection, but this wasn't actually a depth image, drop out. // (the back-projection property may be true despite this not being a depth image!) if hit.hit_type != PickingHitType::TexturedRect - && *ent_properties.backproject_depth.get() + && is_depth_cloud && tensor.meaning != TensorDataMeaning::Depth { None diff --git a/crates/re_space_view_spatial/src/ui_2d.rs b/crates/re_space_view_spatial/src/ui_2d.rs index 33b25482c2d0..d17cc80b684d 100644 --- a/crates/re_space_view_spatial/src/ui_2d.rs +++ b/crates/re_space_view_spatial/src/ui_2d.rs @@ -217,17 +217,14 @@ pub fn help_text(re_ui: &re_ui::ReUi) -> egui::WidgetText { } /// Create the outer 2D view, which consists of a scrollable region -/// TODO(andreas): Split into smaller parts, more re-use with `ui_3d` -#[allow(clippy::too_many_arguments)] pub fn view_2d( ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut SpatialSpaceViewState, - space: &EntityPath, scene: &mut SceneSpatial, - scene_rect_accum: Rect, + space_origin: &EntityPath, space_view_id: SpaceViewId, - entity_properties: &EntityPropertyMap, + scene_rect_accum: Rect, ) -> egui::Response { re_tracing::profile_function!(); @@ -246,8 +243,8 @@ pub fn view_2d( // For that we need to check if this is defined by a pinhole camera. // Note that we can't rely on the camera being part of scene.space_cameras since that requires // the camera to be added to the scene! - let pinhole = - store.query_latest_component::(space, &ctx.rec_cfg.time_ctrl.current_query()); + let pinhole = store + .query_latest_component::(space_origin, &ctx.rec_cfg.time_ctrl.current_query()); let canvas_rect = pinhole .and_then(|p| p.resolution()) .map_or(scene_rect_accum, |res| { @@ -292,7 +289,7 @@ pub fn view_2d( let Ok(target_config) = setup_target_config( &painter, canvas_from_ui, - &space.to_string(), + &space_origin.to_string(), state.auto_size_config(), scene.highlights.any_outlines(), pinhole @@ -325,13 +322,11 @@ pub fn view_2d( state, scene, &ui_rects, - space, - entity_properties, + space_origin, ); } - // TODO(wumpf): Temporary manual insertion of drawdata. The SpaceViewClass framework will take this over. - for draw_data in scene.todo_remove_draw_data.replace(Vec::new()) { + for draw_data in scene.draw_data.drain(..) { view_builder.queue_draw(draw_data); } for draw_data in scene @@ -378,7 +373,7 @@ pub fn view_2d( painter.extend(show_projections_from_3d_space( ctx, ui, - space, + space_origin, &ui_from_canvas, )); diff --git a/crates/re_space_view_spatial/src/ui_3d.rs b/crates/re_space_view_spatial/src/ui_3d.rs index 2d43e9a1fa2d..1d9616926a39 100644 --- a/crates/re_space_view_spatial/src/ui_3d.rs +++ b/crates/re_space_view_spatial/src/ui_3d.rs @@ -4,7 +4,6 @@ use glam::Affine3A; use macaw::{vec3, BoundingBox, Quat, Vec3}; use re_components::ViewCoordinates; -use re_data_store::EntityPropertyMap; use re_log_types::EntityPath; use re_renderer::{ view_builder::{Projection, TargetConfiguration, ViewBuilder}, @@ -283,7 +282,6 @@ pub fn view_3d( space: &EntityPath, space_view_id: SpaceViewId, scene: &mut SceneSpatial, - entity_properties: &EntityPropertyMap, ) { re_tracing::profile_function!(); @@ -390,7 +388,6 @@ pub fn view_3d( scene, &ui_rects, space, - entity_properties, ); } @@ -518,7 +515,7 @@ pub fn view_3d( } // TODO(wumpf): Temporary manual insertion of drawdata. The SpaceViewClass framework will take this over. - for draw_data in scene.todo_remove_draw_data.replace(Vec::new()) { + for draw_data in scene.draw_data.drain(..) { view_builder.queue_draw(draw_data); } for draw_data in scene diff --git a/crates/re_space_view_text/src/space_view_class.rs b/crates/re_space_view_text/src/space_view_class.rs index 32da9bb5e7b1..cb8b077f16b6 100644 --- a/crates/re_space_view_text/src/space_view_class.rs +++ b/crates/re_space_view_text/src/space_view_class.rs @@ -3,8 +3,8 @@ use std::collections::BTreeMap; use re_data_ui::item_ui; use re_log_types::{EntityPath, TimePoint, Timeline}; use re_viewer_context::{ - level_to_rich_text, SpaceViewClassImpl, SpaceViewClassName, SpaceViewState, TypedScene, - ViewerContext, + level_to_rich_text, SpaceViewClassImpl, SpaceViewClassName, SpaceViewId, SpaceViewState, + TypedScene, ViewerContext, }; use super::scene_part::{SceneText, TextEntry}; @@ -54,6 +54,10 @@ impl SpaceViewClassImpl for TextSpaceView { "Shows text entries over time.\nSelect the Space View for filtering options.".into() } + fn preferred_tile_aspect_ratio(&self, _state: &Self::SpaceViewState) -> Option { + Some(2.0) // Make text logs wide + } + fn selection_ui( &self, ctx: &mut ViewerContext<'_>, @@ -110,6 +114,8 @@ impl SpaceViewClassImpl for TextSpaceView { ui: &mut egui::Ui, state: &mut Self::SpaceViewState, scene: &mut TypedScene, + _space_origin: &EntityPath, + _space_view_id: SpaceViewId, ) { let scene = &scene.parts; diff --git a/crates/re_space_view_text_box/src/space_view_class.rs b/crates/re_space_view_text_box/src/space_view_class.rs index a27a182f50dc..544053cc2c1a 100644 --- a/crates/re_space_view_text_box/src/space_view_class.rs +++ b/crates/re_space_view_text_box/src/space_view_class.rs @@ -1,6 +1,7 @@ use egui::Label; use re_viewer_context::{ - SpaceViewClassImpl, SpaceViewClassName, SpaceViewState, TypedScene, ViewerContext, + external::re_log_types::EntityPath, SpaceViewClassImpl, SpaceViewClassName, SpaceViewId, + SpaceViewState, TypedScene, ViewerContext, }; use super::scene_part::SceneTextBox; @@ -75,6 +76,8 @@ impl SpaceViewClassImpl for TextBoxSpaceView { ui: &mut egui::Ui, state: &mut Self::SpaceViewState, scene: &mut TypedScene, + _space_origin: &EntityPath, + _space_view_id: SpaceViewId, ) { let scene = &scene.parts; diff --git a/crates/re_viewer_context/src/space_view/scene.rs b/crates/re_viewer_context/src/space_view/scene.rs index 617ada5fdb2c..a778ef1479a9 100644 --- a/crates/re_viewer_context/src/space_view/scene.rs +++ b/crates/re_viewer_context/src/space_view/scene.rs @@ -18,7 +18,7 @@ pub trait Scene { query: &SceneQuery<'_>, space_view_state: &dyn SpaceViewState, highlights: SpaceViewHighlights, - ) -> Vec; + ); /// Converts itself to a mutable reference of [`std::any::Any`], which enables downcasting to concrete types. fn as_any_mut(&mut self) -> &mut dyn std::any::Any; @@ -30,7 +30,12 @@ pub struct TypedScene { pub parts: C::ScenePartCollection, pub highlights: SpaceViewHighlights, - pub todo_remove_draw_data: std::cell::Cell>, + /// All draw data gathered during the last call to [`Self::populate`]. + /// + /// TODO(wumpf): Right now the ui methods control when and how to create [`re_renderer::ViewBuilder`]s. + /// In the future, we likely want to move view builder handling to `re_viewport` with + /// minimal configuration options exposed via [`crate::SpaceViewClass`]. + pub draw_data: Vec, } impl Default for TypedScene { @@ -39,7 +44,7 @@ impl Default for TypedScene { context: Default::default(), parts: Default::default(), highlights: Default::default(), - todo_remove_draw_data: Default::default(), + draw_data: Default::default(), } } } @@ -51,7 +56,7 @@ impl Scene for TypedScene { query: &SceneQuery<'_>, space_view_state: &dyn SpaceViewState, highlights: SpaceViewHighlights, - ) -> Vec { + ) { re_tracing::profile_function!(); self.highlights = highlights; @@ -62,7 +67,7 @@ impl Scene for TypedScene { else { re_log::error_once!("Unexpected space view state type. Expected {}", std::any::type_name::()); - return Vec::new(); + return; }; // TODO(andreas): Both loops are great candidates for parallelization. @@ -70,14 +75,15 @@ impl Scene for TypedScene { // TODO(andreas): Ideally, we'd pass in the result for an archetype query here. context.populate(ctx, query, state); } - self.parts + self.draw_data = self + .parts .vec_mut() .into_iter() .flat_map(|element| { // TODO(andreas): Ideally, we'd pass in the result for an archetype query here. element.populate(ctx, query, state, &self.context, &self.highlights) }) - .collect() + .collect(); } fn as_any_mut(&mut self) -> &mut dyn std::any::Any { diff --git a/crates/re_viewer_context/src/space_view/space_view_class.rs b/crates/re_viewer_context/src/space_view/space_view_class.rs index 3775e1d2fd13..85fd6d53159d 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class.rs @@ -1,6 +1,6 @@ -use re_log_types::ComponentName; +use re_log_types::{ComponentName, EntityPath}; -use crate::{Scene, ViewerContext}; +use crate::{Scene, SpaceViewId, ViewerContext}; /// First element is the primary component, all others are optional. /// @@ -49,6 +49,9 @@ pub trait SpaceViewClass { None } + /// Preferred aspect ratio for the ui tiles of this space view. + fn preferred_tile_aspect_ratio(&self, state: &dyn SpaceViewState) -> Option; + /// Executed before the scene is populated. /// /// Is only allowed to access archetypes defined by [`Self::blueprint_archetype`] @@ -74,6 +77,8 @@ pub trait SpaceViewClass { ui: &mut egui::Ui, state: &mut dyn SpaceViewState, scene: Box, + space_origin: &EntityPath, + space_view_id: SpaceViewId, ); } diff --git a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs index b5959cf0af74..b65638cc1e96 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs @@ -1,6 +1,8 @@ +use re_log_types::EntityPath; + use crate::{ - Scene, SceneContext, ScenePartCollection, SpaceViewClass, SpaceViewClassName, SpaceViewState, - ViewerContext, + Scene, SceneContext, ScenePartCollection, SpaceViewClass, SpaceViewClassName, SpaceViewId, + SpaceViewState, ViewerContext, }; use super::scene::TypedScene; @@ -39,6 +41,11 @@ pub trait SpaceViewClassImpl: std::marker::Sized { /// Help text describing how to interact with this space view in the ui. fn help_text(&self, re_ui: &re_ui::ReUi) -> egui::WidgetText; + /// Preferred aspect ratio for the ui tiles of this space view. + fn preferred_tile_aspect_ratio(&self, state: &Self::SpaceViewState) -> Option { + None + } + /// Ui shown when the user selects a space view of this class. /// /// TODO(andreas): Should this be instead implemented via a registered `data_ui` of all blueprint relevant types? @@ -59,6 +66,8 @@ pub trait SpaceViewClassImpl: std::marker::Sized { ui: &mut egui::Ui, state: &mut Self::SpaceViewState, scene: &mut TypedScene, + space_origin: &EntityPath, + space_view_id: SpaceViewId, ); } @@ -88,6 +97,10 @@ impl SpaceViewClass for T { Box::::default() } + fn preferred_tile_aspect_ratio(&self, state: &dyn SpaceViewState) -> Option { + typed_state_wrapper(state, |state| self.preferred_tile_aspect_ratio(state)) + } + #[inline] fn selection_ui( &self, @@ -95,7 +108,7 @@ impl SpaceViewClass for T { ui: &mut egui::Ui, state: &mut dyn SpaceViewState, ) { - typed_state_wrapper(state, |state| self.selection_ui(ctx, ui, state)); + typed_state_wrapper_mut(state, |state| self.selection_ui(ctx, ui, state)); } #[inline] @@ -105,6 +118,8 @@ impl SpaceViewClass for T { ui: &mut egui::Ui, state: &mut dyn SpaceViewState, mut scene: Box, + space_origin: &EntityPath, + space_view_id: SpaceViewId, ) { let Some(typed_scene) = scene.as_any_mut().downcast_mut() else { @@ -113,11 +128,13 @@ impl SpaceViewClass for T { return; }; - typed_state_wrapper(state, |state| self.ui(ctx, ui, state, typed_scene)); + typed_state_wrapper_mut(state, |state| { + self.ui(ctx, ui, state, typed_scene, space_origin, space_view_id); + }); } } -fn typed_state_wrapper( +fn typed_state_wrapper_mut( state: &mut dyn SpaceViewState, fun: F, ) { @@ -130,3 +147,18 @@ fn typed_state_wrapper( ); } } + +fn typed_state_wrapper R>( + state: &dyn SpaceViewState, + fun: F, +) -> R { + if let Some(state) = state.as_any().downcast_ref() { + fun(state) + } else { + re_log::error_once!( + "Unexpected space view state type. Expected {}", + std::any::type_name::() + ); + R::default() + } +} diff --git a/crates/re_viewport/src/auto_layout.rs b/crates/re_viewport/src/auto_layout.rs index b69226065e57..48f5df23bc7b 100644 --- a/crates/re_viewport/src/auto_layout.rs +++ b/crates/re_viewport/src/auto_layout.rs @@ -17,7 +17,7 @@ use itertools::Itertools as _; use re_data_store::{EntityPath, EntityPathPart}; use re_space_view_spatial::SpatialNavigationMode; -use re_viewer_context::SpaceViewId; +use re_viewer_context::{SpaceViewId, ViewerContext}; use super::{ space_view::{SpaceViewBlueprint, SpaceViewState}, @@ -49,6 +49,7 @@ enum SplitDirection { } pub(crate) fn tree_from_space_views( + ctx: &mut ViewerContext<'_>, viewport_size: egui::Vec2, visible: &std::collections::BTreeSet, space_views: &HashMap, @@ -66,29 +67,12 @@ pub(crate) fn tree_from_space_views( ) }) .map(|(space_view_id, space_view)| { - let aspect_ratio = match space_view.category { - ViewCategory::Spatial => { - if let Some(space_view_state) = space_view_states.get(space_view_id) { - let state_spatial = &space_view_state.state_spatial; - match *state_spatial.nav_mode.get() { - // This is the only thing where the aspect ratio makes complete sense. - SpatialNavigationMode::TwoD => { - let size = state_spatial.scene_bbox_accum.size(); - Some(size.x / size.y) - } - // 3D scenes can be pretty flexible - SpatialNavigationMode::ThreeD => None, - } - } else { - None - } - } - ViewCategory::TextBox | ViewCategory::Tensor | ViewCategory::TimeSeries => { - Some(1.0) - } // Not sure if we should do `None` here. - ViewCategory::Text => Some(2.0), // Make text logs wide - ViewCategory::BarChart => None, - }; + let aspect_ratio = space_view_states.get(space_view_id).and_then(|state| { + ctx.space_view_class_registry + .query(space_view.class) + .ok() + .and_then(|class| class.preferred_tile_aspect_ratio(state.state.as_ref())) + }); SpaceMakeInfo { id: *space_view_id, diff --git a/crates/re_viewport/src/space_view.rs b/crates/re_viewport/src/space_view.rs index 38edf1298fee..64987dcfdb0e 100644 --- a/crates/re_viewport/src/space_view.rs +++ b/crates/re_viewport/src/space_view.rs @@ -1,8 +1,7 @@ use re_arrow_store::Timeline; use re_data_store::{EntityPath, EntityTree, InstancePath, TimeInt}; use re_renderer::ScreenshotProcessor; -use re_space_view::{DataBlueprintTree, ScreenshotMode}; -use re_space_view_spatial::{SceneSpatial, SpatialSpaceViewState}; +use re_space_view::{DataBlueprintHeuristic, DataBlueprintTree, ScreenshotMode}; use re_viewer_context::{ Scene, SpaceViewClassName, SpaceViewHighlights, SpaceViewId, ViewerContext, }; @@ -154,21 +153,11 @@ impl SpaceViewBlueprint { #[allow(clippy::match_same_arms)] match self.category { - ViewCategory::Text => {} - ViewCategory::TextBox => { + ViewCategory::Text | ViewCategory::Spatial | ViewCategory::TextBox => { // migrated. } ViewCategory::TimeSeries => {} ViewCategory::BarChart => {} - ViewCategory::Spatial => { - view_state.state_spatial.selection_ui( - ctx, - ui, - &self.data_blueprint, - &self.space_path, - self.id, - ); - } ViewCategory::Tensor => { if let Some(selected_tensor) = &view_state.selected_tensor { if let Some(state_tensor) = @@ -206,10 +195,17 @@ impl SpaceViewBlueprint { }; if let Ok(space_view_class) = ctx.space_view_class_registry.query(self.class) { + space_view_class.prepare_populate(ctx, view_state.state.as_mut()); + + if let Some(heuristic) = view_state + .state + .as_ref() + .as_any() + .downcast_ref::() { - re_tracing::profile_scope!("prepare_populate", space_view_class.name()); - space_view_class.prepare_populate(ctx, view_state.state.as_mut()); + heuristic.update_object_property_heuristics(ctx, &mut self.data_blueprint); } + let mut scene = space_view_class.new_scene(); scene.populate(ctx, &query, view_state.state.as_ref(), highlights); @@ -222,7 +218,7 @@ impl SpaceViewBlueprint { } else { // Legacy handling match self.category { - ViewCategory::Text | ViewCategory::TextBox => { + ViewCategory::Text | ViewCategory::TextBox | ViewCategory::Spatial => { // migrated. } @@ -238,23 +234,6 @@ impl SpaceViewBlueprint { view_state.ui_bar_chart(ctx, ui, &scene); } - ViewCategory::Spatial => { - let mut scene = SceneSpatial::default(); - let draw_data = - scene.populate(ctx, &query, &view_state.state_spatial, highlights); - scene.todo_remove_draw_data.replace(draw_data); - ui.vertical(|ui| { - view_state.state_spatial.view_spatial( - ctx, - ui, - &self.space_path, - &mut scene, - self.id, - self.data_blueprint.data_blueprints_projected(), - ); - }); - } - ViewCategory::Tensor => { let mut scene = view_tensor::SceneTensor::default(); scene.load(ctx, &query); @@ -322,7 +301,6 @@ pub struct SpaceViewState { pub state_time_series: view_time_series::ViewTimeSeriesState, pub state_bar_chart: view_bar_chart::BarChartState, - pub state_spatial: SpatialSpaceViewState, pub state_tensors: ahash::HashMap, } From 8b63278f0bc95bddadfe8bffc3e242c5cac0a083 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 18:06:52 +0200 Subject: [PATCH 06/15] fully decouple SpatialSpaceView --- Cargo.lock | 1 - crates/re_data_store/src/entity_properties.rs | 6 ++ .../src/data_blueprint_heuristic.rs | 15 ---- crates/re_space_view/src/lib.rs | 4 +- .../src/unreachable_transform.rs | 31 ++++++++ crates/re_space_view_spatial/src/lib.rs | 6 +- .../src/scene/contexts/mod.rs | 2 +- .../contexts/non_interactive_entities.rs | 6 +- .../src/scene/contexts/transform_context.rs | 33 +------- crates/re_space_view_spatial/src/scene/mod.rs | 8 +- .../src/scene/parts/arrows3d.rs | 4 +- .../src/scene/parts/boxes2d.rs | 4 +- .../src/scene/parts/boxes3d.rs | 4 +- .../src/scene/parts/cameras.rs | 4 +- .../src/scene/parts/images.rs | 4 +- .../src/scene/parts/lines2d.rs | 4 +- .../src/scene/parts/lines3d.rs | 4 +- .../src/scene/parts/meshes.rs | 4 +- .../src/scene/parts/mod.rs | 8 +- .../src/scene/parts/points2d.rs | 4 +- .../src/scene/parts/points3d.rs | 4 +- .../src/space_view_class.rs | 28 ++++++- crates/re_space_view_spatial/src/ui.rs | 65 +++++++-------- crates/re_space_view_spatial/src/ui_2d.rs | 5 +- crates/re_space_view_spatial/src/ui_3d.rs | 6 +- crates/re_viewer/src/app.rs | 10 +-- crates/re_viewer/src/ui/selection_panel.rs | 41 ++-------- .../src/space_view/space_view_class.rs | 11 ++- .../src/space_view/space_view_class_impl.rs | 33 +++++++- .../space_view/space_view_class_registry.rs | 6 +- crates/re_viewport/Cargo.toml | 3 - crates/re_viewport/src/auto_layout.rs | 7 +- crates/re_viewport/src/lib.rs | 1 - crates/re_viewport/src/space_info.rs | 2 +- crates/re_viewport/src/space_view.rs | 79 ++++++++++--------- .../src/space_view_entity_picker.rs | 12 +-- .../re_viewport/src/space_view_heuristics.rs | 12 +-- crates/re_viewport/src/viewport.rs | 45 ++++++----- 38 files changed, 274 insertions(+), 252 deletions(-) delete mode 100644 crates/re_space_view/src/data_blueprint_heuristic.rs create mode 100644 crates/re_space_view/src/unreachable_transform.rs diff --git a/Cargo.lock b/Cargo.lock index a3983b9840b9..dcc5999d6eca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4527,7 +4527,6 @@ dependencies = [ "re_query", "re_renderer", "re_space_view", - "re_space_view_spatial", "re_tensor_ops", "re_tracing", "re_ui", diff --git a/crates/re_data_store/src/entity_properties.rs b/crates/re_data_store/src/entity_properties.rs index e15169bb4c6a..7502453d5d08 100644 --- a/crates/re_data_store/src/entity_properties.rs +++ b/crates/re_data_store/src/entity_properties.rs @@ -34,6 +34,12 @@ impl EntityPropertyMap { pub fn iter(&self) -> impl Iterator { self.props.iter() } + + /// Iterates over all paths that have a non-default value. + #[inline] + pub fn iter_non_default_entities(&self) -> impl Iterator { + self.props.keys() + } } // ---------------------------------------------------------------------------- diff --git a/crates/re_space_view/src/data_blueprint_heuristic.rs b/crates/re_space_view/src/data_blueprint_heuristic.rs deleted file mode 100644 index c792b9f9fcbe..000000000000 --- a/crates/re_space_view/src/data_blueprint_heuristic.rs +++ /dev/null @@ -1,15 +0,0 @@ -use re_viewer_context::ViewerContext; - -use crate::DataBlueprintTree; - -/// Trait implemented by a [`re_viewer_context::SpaceViewState`] to update the data blueprint tree. -/// -/// TODO(wumpf/jleibs): This is an interim construct until we're able to extract the data blueprint via a query -/// and figure out how default/heuristically determined values are handled. -pub trait DataBlueprintHeuristic { - fn update_object_property_heuristics( - &self, - ctx: &mut ViewerContext<'_>, - data_blueprint: &mut DataBlueprintTree, - ); -} diff --git a/crates/re_space_view/src/lib.rs b/crates/re_space_view/src/lib.rs index eb99c644ae0b..e77cd19e4eeb 100644 --- a/crates/re_space_view/src/lib.rs +++ b/crates/re_space_view/src/lib.rs @@ -4,13 +4,13 @@ pub mod controls; mod data_blueprint; -mod data_blueprint_heuristic; mod empty_scene_context; mod empty_space_view_state; mod screenshot; +mod unreachable_transform; pub use data_blueprint::{DataBlueprintGroup, DataBlueprintTree}; -pub use data_blueprint_heuristic::DataBlueprintHeuristic; pub use empty_scene_context::EmptySceneContext; pub use empty_space_view_state::EmptySpaceViewState; pub use screenshot::ScreenshotMode; +pub use unreachable_transform::UnreachableTransform; diff --git a/crates/re_space_view/src/unreachable_transform.rs b/crates/re_space_view/src/unreachable_transform.rs new file mode 100644 index 000000000000..4e8ac34dfcb2 --- /dev/null +++ b/crates/re_space_view/src/unreachable_transform.rs @@ -0,0 +1,31 @@ +#[derive(Clone, Copy)] +pub enum UnreachableTransform { + /// `SpaceInfoCollection` is outdated and can't find a corresponding space info for the given path. + /// + /// If at all, this should only happen for a single frame until space infos are rebuilt. + UnknownSpaceInfo, + + /// More than one pinhole camera between this and the reference space. + NestedPinholeCameras, + + /// Exiting out of a space with a pinhole camera that doesn't have a resolution is not supported. + InversePinholeCameraWithoutResolution, + + /// Unknown transform between this and the reference space. + DisconnectedSpace, +} + +impl std::fmt::Display for UnreachableTransform { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + Self::UnknownSpaceInfo => + "Can't determine transform because internal data structures are not in a valid state. Please file an issue on https://github.com/rerun-io/rerun/", + Self::NestedPinholeCameras => + "Can't display entities under nested pinhole cameras.", + Self::DisconnectedSpace => + "Can't display entities that are in an explicitly disconnected space.", + Self::InversePinholeCameraWithoutResolution => + "Can't display entities that would require inverting a pinhole camera without a specified resolution.", + }) + } +} diff --git a/crates/re_space_view_spatial/src/lib.rs b/crates/re_space_view_spatial/src/lib.rs index c23530e294c1..e4f0700110bf 100644 --- a/crates/re_space_view_spatial/src/lib.rs +++ b/crates/re_space_view_spatial/src/lib.rs @@ -15,8 +15,4 @@ mod ui_2d; mod ui_3d; mod ui_renderer_bridge; -// TODO(andreas) should only make the main type public -pub use space_view_class::SpatialSpaceViewClass; - -pub use scene::{SceneSpatial, TransformContext, UnreachableTransform}; -pub use ui::{SpatialNavigationMode, SpatialSpaceViewState}; +pub use space_view_class::SpatialSpaceView; diff --git a/crates/re_space_view_spatial/src/scene/contexts/mod.rs b/crates/re_space_view_spatial/src/scene/contexts/mod.rs index 016b2f73e0c8..732652d6d048 100644 --- a/crates/re_space_view_spatial/src/scene/contexts/mod.rs +++ b/crates/re_space_view_spatial/src/scene/contexts/mod.rs @@ -9,7 +9,7 @@ use std::sync::atomic::AtomicUsize; pub use annotation_context::AnnotationSceneContext; pub use depth_offsets::EntityDepthOffsets; pub use shared_render_builders::SharedRenderBuilders; -pub use transform_context::{TransformContext, UnreachableTransform}; +pub use transform_context::TransformContext; // ----------------------------------------------------------------------------- diff --git a/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs b/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs index 6084477e3494..bfe3a16e9f46 100644 --- a/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs +++ b/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs @@ -13,9 +13,9 @@ impl SceneContextPart for NonInteractiveEntities { fn populate( &mut self, - ctx: &mut re_viewer_context::ViewerContext<'_>, + _ctx: &mut re_viewer_context::ViewerContext<'_>, query: &re_viewer_context::SceneQuery<'_>, - space_view_state: &dyn re_viewer_context::SpaceViewState, + _space_view_state: &dyn re_viewer_context::SpaceViewState, ) { re_tracing::profile_function!(); @@ -29,6 +29,6 @@ impl SceneContextPart for NonInteractiveEntities { Some(entity_path.hash()) } }) - .collect() + .collect(); } } diff --git a/crates/re_space_view_spatial/src/scene/contexts/transform_context.rs b/crates/re_space_view_spatial/src/scene/contexts/transform_context.rs index d3a0dcd8d286..ed2931adcc3c 100644 --- a/crates/re_space_view_spatial/src/scene/contexts/transform_context.rs +++ b/crates/re_space_view_spatial/src/scene/contexts/transform_context.rs @@ -4,6 +4,7 @@ use re_arrow_store::LatestAtQuery; use re_components::{DisconnectedSpace, Pinhole, Transform3D}; use re_data_store::{EntityPath, EntityPropertyMap, EntityTree}; use re_log_types::Component; +use re_space_view::UnreachableTransform; use re_viewer_context::{ArchetypeDefinition, SceneContextPart}; #[derive(Clone)] @@ -51,38 +52,6 @@ impl Default for TransformContext { } } -#[derive(Clone, Copy)] -pub enum UnreachableTransform { - /// `SpaceInfoCollection` is outdated and can't find a corresponding space info for the given path. - /// - /// If at all, this should only happen for a single frame until space infos are rebuilt. - UnknownSpaceInfo, - - /// More than one pinhole camera between this and the reference space. - NestedPinholeCameras, - - /// Exiting out of a space with a pinhole camera that doesn't have a resolution is not supported. - InversePinholeCameraWithoutResolution, - - /// Unknown transform between this and the reference space. - DisconnectedSpace, -} - -impl std::fmt::Display for UnreachableTransform { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.write_str(match self { - Self::UnknownSpaceInfo => - "Can't determine transform because internal data structures are not in a valid state. Please file an issue on https://github.com/rerun-io/rerun/", - Self::NestedPinholeCameras => - "Can't display entities under nested pinhole cameras.", - Self::DisconnectedSpace => - "Can't display entities that are in an explicitly disconnected space.", - Self::InversePinholeCameraWithoutResolution => - "Can't display entities that would require inverting a pinhole camera without a specified resolution.", - }) - } -} - impl SceneContextPart for TransformContext { fn archetypes(&self) -> Vec { vec![ diff --git a/crates/re_space_view_spatial/src/scene/mod.rs b/crates/re_space_view_spatial/src/scene/mod.rs index 64efd4c56ddb..63bd4fe4d629 100644 --- a/crates/re_space_view_spatial/src/scene/mod.rs +++ b/crates/re_space_view_spatial/src/scene/mod.rs @@ -2,7 +2,7 @@ mod contexts; mod parts; mod picking; -pub use contexts::{SpatialSceneContext, TransformContext, UnreachableTransform}; +pub use contexts::{SpatialSceneContext, TransformContext}; pub use parts::{SpatialScenePartCollection, SpatialScenePartData}; pub use picking::{PickableUiRect, PickingContext, PickingHitType, PickingRayHit, PickingResult}; @@ -13,9 +13,7 @@ use re_data_store::{EntityPath, InstancePathHash}; use re_renderer::{Color32, Size}; use re_viewer_context::{auto_color, TypedScene}; -use crate::SpatialSpaceViewClass; - -use super::SpatialNavigationMode; +use crate::{ui::SpatialNavigationMode, SpatialSpaceView}; use self::contexts::SpatialSceneEntityContext; @@ -46,7 +44,7 @@ pub struct UiLabel { pub labeled_instance: InstancePathHash, } -pub type SceneSpatial = TypedScene; +pub type SceneSpatial = TypedScene; pub type Keypoints = HashMap<(ClassId, i64), HashMap>; /// Heuristic whether the default way of looking at this scene should be 2d or 3d. diff --git a/crates/re_space_view_spatial/src/scene/parts/arrows3d.rs b/crates/re_space_view_spatial/src/scene/parts/arrows3d.rs index 42d5ed4126d4..ac41ef95ea53 100644 --- a/crates/re_space_view_spatial/src/scene/parts/arrows3d.rs +++ b/crates/re_space_view_spatial/src/scene/parts/arrows3d.rs @@ -12,7 +12,7 @@ use crate::{ contexts::{SpatialSceneContext, SpatialSceneEntityContext}, parts::entity_iterator::process_entity_views, }, - SpatialSpaceViewClass, + SpatialSpaceView, }; #[derive(Default)] @@ -93,7 +93,7 @@ impl Arrows3DPart { } } -impl ScenePart for Arrows3DPart { +impl ScenePart for Arrows3DPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![ Arrow3D::name(), diff --git a/crates/re_space_view_spatial/src/scene/parts/boxes2d.rs b/crates/re_space_view_spatial/src/scene/parts/boxes2d.rs index 540b49bf0af0..c5c6c9075120 100644 --- a/crates/re_space_view_spatial/src/scene/parts/boxes2d.rs +++ b/crates/re_space_view_spatial/src/scene/parts/boxes2d.rs @@ -16,7 +16,7 @@ use crate::{ parts::entity_iterator::process_entity_views, UiLabel, UiLabelTarget, }, - SpatialSpaceViewClass, + SpatialSpaceView, }; #[derive(Default)] @@ -111,7 +111,7 @@ impl Boxes2DPart { } } -impl ScenePart for Boxes2DPart { +impl ScenePart for Boxes2DPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![ Rect2D::name(), diff --git a/crates/re_space_view_spatial/src/scene/parts/boxes3d.rs b/crates/re_space_view_spatial/src/scene/parts/boxes3d.rs index d9b9cc38ae54..07549cfd090e 100644 --- a/crates/re_space_view_spatial/src/scene/parts/boxes3d.rs +++ b/crates/re_space_view_spatial/src/scene/parts/boxes3d.rs @@ -14,7 +14,7 @@ use crate::{ parts::entity_iterator::process_entity_views, UiLabel, UiLabelTarget, }, - SpatialSpaceViewClass, + SpatialSpaceView, }; use super::{ @@ -107,7 +107,7 @@ impl Boxes3DPart { } } -impl ScenePart for Boxes3DPart { +impl ScenePart for Boxes3DPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![ Box3D::name(), diff --git a/crates/re_space_view_spatial/src/scene/parts/cameras.rs b/crates/re_space_view_spatial/src/scene/parts/cameras.rs index 99241be64758..bbcdde211f0b 100644 --- a/crates/re_space_view_spatial/src/scene/parts/cameras.rs +++ b/crates/re_space_view_spatial/src/scene/parts/cameras.rs @@ -11,7 +11,7 @@ use re_viewer_context::{SpaceViewHighlights, SpaceViewOutlineMasks}; use super::{instance_path_hash_for_picking, SpatialScenePartData, SpatialSpaceViewState}; use crate::{ instance_hash_conversions::picking_layer_id_from_instance_path_hash, - scene::contexts::SpatialSceneContext, space_camera_3d::SpaceCamera3D, SpatialSpaceViewClass, + scene::contexts::SpatialSceneContext, space_camera_3d::SpaceCamera3D, SpatialSpaceView, }; const CAMERA_COLOR: re_renderer::Color32 = re_renderer::Color32::from_rgb(150, 150, 150); @@ -184,7 +184,7 @@ impl CamerasPart { } } -impl ScenePart for CamerasPart { +impl ScenePart for CamerasPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![Pinhole::name(),] } diff --git a/crates/re_space_view_spatial/src/scene/parts/images.rs b/crates/re_space_view_spatial/src/scene/parts/images.rs index 6e1bfe3be450..63f552c376b9 100644 --- a/crates/re_space_view_spatial/src/scene/parts/images.rs +++ b/crates/re_space_view_spatial/src/scene/parts/images.rs @@ -28,7 +28,7 @@ use crate::{ parts::entity_iterator::process_entity_views, SIZE_BOOST_IN_POINTS_FOR_POINT_OUTLINES, }, - SpatialSpaceViewClass, + SpatialSpaceView, }; use super::{SpatialScenePartData, SpatialSpaceViewState}; @@ -409,7 +409,7 @@ impl ImagesPart { } } -impl ScenePart for ImagesPart { +impl ScenePart for ImagesPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![ Tensor::name(), diff --git a/crates/re_space_view_spatial/src/scene/parts/lines2d.rs b/crates/re_space_view_spatial/src/scene/parts/lines2d.rs index c68d08a7ad43..b4742de8d85a 100644 --- a/crates/re_space_view_spatial/src/scene/parts/lines2d.rs +++ b/crates/re_space_view_spatial/src/scene/parts/lines2d.rs @@ -11,7 +11,7 @@ use crate::{ contexts::{SpatialSceneContext, SpatialSceneEntityContext}, parts::entity_iterator::process_entity_views, }, - SpatialSpaceViewClass, + SpatialSpaceView, }; use super::{instance_key_to_picking_id, SpatialScenePartData, SpatialSpaceViewState}; @@ -81,7 +81,7 @@ impl Lines2DPart { } } -impl ScenePart for Lines2DPart { +impl ScenePart for Lines2DPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![ LineStrip2D::name(), diff --git a/crates/re_space_view_spatial/src/scene/parts/lines3d.rs b/crates/re_space_view_spatial/src/scene/parts/lines3d.rs index 9a0564f4f1be..b03669ea2126 100644 --- a/crates/re_space_view_spatial/src/scene/parts/lines3d.rs +++ b/crates/re_space_view_spatial/src/scene/parts/lines3d.rs @@ -11,7 +11,7 @@ use crate::{ contexts::{SpatialSceneContext, SpatialSceneEntityContext}, parts::entity_iterator::process_entity_views, }, - SpatialSpaceViewClass, + SpatialSpaceView, }; use super::{instance_key_to_picking_id, SpatialScenePartData, SpatialSpaceViewState}; @@ -81,7 +81,7 @@ impl Lines3DPart { } } -impl ScenePart for Lines3DPart { +impl ScenePart for Lines3DPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![ LineStrip3D::name(), diff --git a/crates/re_space_view_spatial/src/scene/parts/meshes.rs b/crates/re_space_view_spatial/src/scene/parts/meshes.rs index ca39860307e3..7eac5d29eac2 100644 --- a/crates/re_space_view_spatial/src/scene/parts/meshes.rs +++ b/crates/re_space_view_spatial/src/scene/parts/meshes.rs @@ -12,7 +12,7 @@ use crate::scene::{ contexts::{SpatialSceneContext, SpatialSceneEntityContext}, parts::entity_iterator::process_entity_views, }; -use crate::SpatialSpaceViewClass; +use crate::SpatialSpaceView; use super::{instance_path_hash_for_picking, SpatialScenePartData, SpatialSpaceViewState}; @@ -70,7 +70,7 @@ impl MeshPart { } } -impl ScenePart for MeshPart { +impl ScenePart for MeshPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![Mesh3D::name(), InstanceKey::name(), ColorRGBA::name()] } diff --git a/crates/re_space_view_spatial/src/scene/parts/mod.rs b/crates/re_space_view_spatial/src/scene/parts/mod.rs index bf380869f84f..5de4f0d35a14 100644 --- a/crates/re_space_view_spatial/src/scene/parts/mod.rs +++ b/crates/re_space_view_spatial/src/scene/parts/mod.rs @@ -25,7 +25,7 @@ use re_viewer_context::{ Annotations, DefaultColor, ResolvedAnnotationInfo, ScenePartCollection, SceneQuery, }; -use crate::{scene::Keypoints, ui::SpatialSpaceViewState, SpatialSpaceViewClass}; +use crate::{scene::Keypoints, ui::SpatialSpaceViewState, SpatialSpaceView}; use super::UiLabel; @@ -43,8 +43,8 @@ pub struct SpatialScenePartCollection { pub images: images::ImagesPart, } -impl ScenePartCollection for SpatialScenePartCollection { - fn vec_mut(&mut self) -> Vec<&mut dyn re_viewer_context::ScenePart> { +impl ScenePartCollection for SpatialScenePartCollection { + fn vec_mut(&mut self) -> Vec<&mut dyn re_viewer_context::ScenePart> { let Self { points2d, points3d, @@ -69,7 +69,7 @@ impl ScenePartCollection for SpatialScenePartCollection { } impl SpatialScenePartCollection { - fn vec(&self) -> Vec<&dyn re_viewer_context::ScenePart> { + fn vec(&self) -> Vec<&dyn re_viewer_context::ScenePart> { let Self { points2d, points3d, diff --git a/crates/re_space_view_spatial/src/scene/parts/points2d.rs b/crates/re_space_view_spatial/src/scene/parts/points2d.rs index 3fdd571b3415..19241a8d08a7 100644 --- a/crates/re_space_view_spatial/src/scene/parts/points2d.rs +++ b/crates/re_space_view_spatial/src/scene/parts/points2d.rs @@ -15,7 +15,7 @@ use crate::{ parts::entity_iterator::process_entity_views, UiLabel, UiLabelTarget, }, - SpatialSpaceViewClass, + SpatialSpaceView, }; use super::{ @@ -179,7 +179,7 @@ impl Points2DPart { } } -impl ScenePart for Points2DPart { +impl ScenePart for Points2DPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![ Point2D::name(), diff --git a/crates/re_space_view_spatial/src/scene/parts/points3d.rs b/crates/re_space_view_spatial/src/scene/parts/points3d.rs index 476ce9585bfe..184b8851007b 100644 --- a/crates/re_space_view_spatial/src/scene/parts/points3d.rs +++ b/crates/re_space_view_spatial/src/scene/parts/points3d.rs @@ -15,7 +15,7 @@ use crate::{ parts::entity_iterator::process_entity_views, UiLabel, UiLabelTarget, }, - SpatialSpaceViewClass, + SpatialSpaceView, }; use super::{ @@ -177,7 +177,7 @@ impl Points3DPart { } } -impl ScenePart for Points3DPart { +impl ScenePart for Points3DPart { fn archetype(&self) -> ArchetypeDefinition { vec1::vec1![ Point3D::name(), diff --git a/crates/re_space_view_spatial/src/space_view_class.rs b/crates/re_space_view_spatial/src/space_view_class.rs index 16d931f46bf3..4b49fb8f4b11 100644 --- a/crates/re_space_view_spatial/src/space_view_class.rs +++ b/crates/re_space_view_spatial/src/space_view_class.rs @@ -3,12 +3,13 @@ use re_viewer_context::{SpaceViewClassImpl, SpaceViewId}; use crate::{ scene::{SpatialSceneContext, SpatialScenePartCollection, SpatialScenePartData}, - SpatialSpaceViewState, + ui::{SpatialNavigationMode, SpatialSpaceViewState}, }; -pub struct SpatialSpaceViewClass; +#[derive(Default)] +pub struct SpatialSpaceView; -impl SpaceViewClassImpl for SpatialSpaceViewClass { +impl SpaceViewClassImpl for SpatialSpaceView { type SpaceViewState = SpatialSpaceViewState; type SceneContext = SpatialSceneContext; type ScenePartCollection = SpatialScenePartCollection; @@ -23,10 +24,29 @@ impl SpaceViewClassImpl for SpatialSpaceViewClass { } fn help_text(&self, _re_ui: &re_ui::ReUi) -> egui::WidgetText { - // TODO(andreas) + // TODO: "todo".into() } + fn preferred_tile_aspect_ratio(&self, state: &Self::SpaceViewState) -> Option { + match state.nav_mode.get() { + SpatialNavigationMode::TwoD => { + let size = state.scene_bbox_accum.size(); + Some(size.x / size.y) + } + SpatialNavigationMode::ThreeD => None, + } + } + + fn prepare_populate( + &self, + ctx: &mut re_viewer_context::ViewerContext<'_>, + state: &Self::SpaceViewState, + entity_properties: &mut re_data_store::EntityPropertyMap, + ) { + state.update_object_property_heuristics(ctx, entity_properties); + } + fn selection_ui( &self, ctx: &mut re_viewer_context::ViewerContext<'_>, diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index 4f2335cc656a..f8859f96198a 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -1,16 +1,15 @@ use eframe::epaint::text::TextWrapping; use egui::{NumExt, WidgetText}; +use itertools::Itertools as _; use macaw::BoundingBox; -use nohash_hasher::{IntMap, IntSet}; use re_components::{Pinhole, Tensor, TensorDataMeaning}; -use re_data_store::{EditableAutoValue, EntityPath, EntityPropertyMap}; +use re_data_store::{EditableAutoValue, EntityPath}; use re_data_ui::{item_ui, DataUi}; use re_data_ui::{show_zoomed_image_region, show_zoomed_image_region_area_outline}; use re_format::format_f32; -use re_log_types::EntityPathHash; use re_renderer::OutlineConfig; -use re_space_view::{DataBlueprintHeuristic, DataBlueprintTree, ScreenshotMode}; +use re_space_view::ScreenshotMode; use re_viewer_context::{ HoverHighlight, HoveredSpace, Item, SelectionHighlight, SpaceViewHighlights, SpaceViewId, SpaceViewState, TensorDecodeCache, TensorStatsCache, UiVerbosity, ViewerContext, @@ -118,24 +117,6 @@ impl SpaceViewState for SpatialSpaceViewState { } } -impl DataBlueprintHeuristic for SpatialSpaceViewState { - fn update_object_property_heuristics( - &self, - ctx: &mut ViewerContext<'_>, - data_blueprint: &mut DataBlueprintTree, - ) { - re_tracing::profile_function!(); - - let query = ctx.current_query(); - - let entity_paths = data_blueprint.entity_paths().clone(); // TODO(andreas): Workaround borrow checker - for entity_path in entity_paths { - self.update_pinhole_property_heuristics(ctx, data_blueprint, &query, &entity_path); - self.update_depth_cloud_property_heuristics(ctx, data_blueprint, &query, &entity_path); - } - } -} - impl SpatialSpaceViewState { pub fn auto_size_config(&self) -> re_renderer::AutoSizeConfig { let mut config = self.auto_size_config; @@ -148,6 +129,30 @@ impl SpatialSpaceViewState { config } + pub fn update_object_property_heuristics( + &self, + ctx: &mut ViewerContext<'_>, + entity_properties: &mut re_data_store::EntityPropertyMap, + ) { + re_tracing::profile_function!(); + + let query = ctx.current_query(); + + let entity_paths = entity_properties + .iter_non_default_entities() + .cloned() + .collect_vec(); // TODO(andreas): Workaround borrow checker + for entity_path in entity_paths { + self.update_pinhole_property_heuristics(ctx, &query, &entity_path, entity_properties); + self.update_depth_cloud_property_heuristics( + ctx, + &query, + &entity_path, + entity_properties, + ); + } + } + fn auto_size_world_heuristic(&self) -> f32 { if self.scene_bbox_accum.is_nothing() || self.scene_bbox_accum.is_nan() { return 0.01; @@ -173,16 +178,16 @@ impl SpatialSpaceViewState { fn update_pinhole_property_heuristics( &self, ctx: &mut ViewerContext<'_>, - data_blueprint: &mut DataBlueprintTree, query: &re_arrow_store::LatestAtQuery, entity_path: &EntityPath, + entity_properties: &mut re_data_store::EntityPropertyMap, ) { let store = &ctx.store_db.entity_db.data_store; if store .query_latest_component::(entity_path, query) .is_some() { - let mut properties = data_blueprint.data_blueprints_individual().get(entity_path); + let mut properties = entity_properties.get(entity_path); if properties.pinhole_image_plane_distance.is_auto() { let scene_size = self.scene_bbox_accum.size().length(); let default_image_plane_distance = if scene_size.is_finite() && scene_size > 0.0 { @@ -192,9 +197,7 @@ impl SpatialSpaceViewState { }; properties.pinhole_image_plane_distance = EditableAutoValue::Auto(default_image_plane_distance); - data_blueprint - .data_blueprints_individual() - .set(entity_path.clone(), properties); + entity_properties.set(entity_path.clone(), properties); } } } @@ -202,14 +205,14 @@ impl SpatialSpaceViewState { fn update_depth_cloud_property_heuristics( &self, ctx: &mut ViewerContext<'_>, - data_blueprint: &mut DataBlueprintTree, query: &re_arrow_store::LatestAtQuery, entity_path: &EntityPath, + entity_properties: &mut re_data_store::EntityPropertyMap, ) -> Option<()> { let store = &ctx.store_db.entity_db.data_store; let tensor = store.query_latest_component::(entity_path, query)?; - let mut properties = data_blueprint.data_blueprints_individual().get(entity_path); + let mut properties = entity_properties.get(entity_path); if properties.backproject_depth.is_auto() { properties.backproject_depth = EditableAutoValue::Auto( tensor.meaning == TensorDataMeaning::Depth @@ -233,9 +236,7 @@ impl SpatialSpaceViewState { properties.backproject_radius_scale = EditableAutoValue::Auto(1.0); } - data_blueprint - .data_blueprints_individual() - .set(entity_path.clone(), properties); + entity_properties.set(entity_path.clone(), properties); } Some(()) diff --git a/crates/re_space_view_spatial/src/ui_2d.rs b/crates/re_space_view_spatial/src/ui_2d.rs index d17cc80b684d..a999fbde597d 100644 --- a/crates/re_space_view_spatial/src/ui_2d.rs +++ b/crates/re_space_view_spatial/src/ui_2d.rs @@ -2,7 +2,7 @@ use eframe::emath::RectTransform; use egui::{pos2, vec2, Align2, Color32, NumExt as _, Pos2, Rect, ScrollArea, Shape, Vec2}; use macaw::IsoTransform; use re_components::Pinhole; -use re_data_store::{EntityPath, EntityPropertyMap}; +use re_data_store::EntityPath; use re_renderer::view_builder::{TargetConfiguration, ViewBuilder}; use re_space_view::controls::{DRAG_PAN2D_BUTTON, RESET_VIEW_BUTTON_TEXT, ZOOM_SCROLL_MODIFIER}; use re_viewer_context::{gpu_bridge, HoveredSpace, SpaceViewId, ViewerContext}; @@ -10,11 +10,10 @@ use re_viewer_context::{gpu_bridge, HoveredSpace, SpaceViewId, ViewerContext}; use super::{ eye::Eye, ui::{create_labels, picking, screenshot_context_menu}, - SpatialNavigationMode, }; use crate::{ scene::SceneSpatial, - ui::{outline_config, SpatialSpaceViewState}, + ui::{outline_config, SpatialNavigationMode, SpatialSpaceViewState}, ui_renderer_bridge::{fill_view_builder, ScreenBackground}, }; diff --git a/crates/re_space_view_spatial/src/ui_3d.rs b/crates/re_space_view_spatial/src/ui_3d.rs index 1d9616926a39..37afdfefe85f 100644 --- a/crates/re_space_view_spatial/src/ui_3d.rs +++ b/crates/re_space_view_spatial/src/ui_3d.rs @@ -19,9 +19,11 @@ use crate::{ axis_lines::add_axis_lines, scene::{SceneSpatial, SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES}, space_camera_3d::SpaceCamera3D, - ui::{create_labels, outline_config, picking, screenshot_context_menu, SpatialSpaceViewState}, + ui::{ + create_labels, outline_config, picking, screenshot_context_menu, SpatialNavigationMode, + SpatialSpaceViewState, + }, ui_renderer_bridge::{fill_view_builder, ScreenBackground}, - SpatialNavigationMode, }; use super::eye::{Eye, OrbitEye}; diff --git a/crates/re_viewer/src/app.rs b/crates/re_viewer/src/app.rs index ec06f6cb1f53..fc1dc92c7b54 100644 --- a/crates/re_viewer/src/app.rs +++ b/crates/re_viewer/src/app.rs @@ -127,8 +127,9 @@ pub struct App { fn populate_space_view_class_registry_with_builtin( space_view_class_registry: &mut SpaceViewClassRegistry, ) -> Result<(), SpaceViewClassRegistryError> { - space_view_class_registry.add(re_space_view_text::TextSpaceView::default())?; - space_view_class_registry.add(re_space_view_text_box::TextBoxSpaceView::default())?; + space_view_class_registry.add::()?; + space_view_class_registry.add::()?; + space_view_class_registry.add::()?; Ok(()) } @@ -215,11 +216,10 @@ impl App { } /// Adds a new space view class to the viewer. - pub fn add_space_view_class( + pub fn add_space_view_class( &mut self, - space_view_class: impl SpaceViewClass + 'static, ) -> Result<(), SpaceViewClassRegistryError> { - self.space_view_class_registry.add(space_view_class) + self.space_view_class_registry.add::() } /// Creates a promise with the specified name that will run `f` on a background diff --git a/crates/re_viewer/src/ui/selection_panel.rs b/crates/re_viewer/src/ui/selection_panel.rs index 4cfb0876ed20..b76b6d097484 100644 --- a/crates/re_viewer/src/ui/selection_panel.rs +++ b/crates/re_viewer/src/ui/selection_panel.rs @@ -5,7 +5,7 @@ use re_data_store::{ColorMapper, Colormap, EditableAutoValue, EntityPath, Entity use re_data_ui::{item_ui, DataUi}; use re_log_types::TimeType; use re_viewer_context::{Item, SpaceViewId, UiVerbosity, ViewerContext}; -use re_viewport::{SpaceViewState, SpatialNavigationMode, Viewport, ViewportState}; +use re_viewport::{Viewport, ViewportState}; use crate::ui::Blueprint; @@ -279,22 +279,10 @@ fn blueprint_ui( }); // TODO(emilk): show the values of this specific instance (e.g. point in the point cloud)! } else { - let space_view_state = viewport_state.space_view_state( - ctx.space_view_class_registry, - space_view.id, - space_view.class, - ); - // splat - the whole entity let data_blueprint = space_view.data_blueprint.data_blueprints_individual(); let mut props = data_blueprint.get(&instance_path.entity_path); - entity_props_ui( - ctx, - ui, - Some(&instance_path.entity_path), - &mut props, - space_view_state, - ); + entity_props_ui(ctx, ui, Some(&instance_path.entity_path), &mut props); data_blueprint.set(instance_path.entity_path.clone(), props); } } @@ -309,19 +297,7 @@ fn blueprint_ui( .data_blueprint .group_mut(*data_blueprint_group_handle) { - let space_view_state = viewport_state.space_view_state( - ctx.space_view_class_registry, - space_view.id, - space_view.class, - ); - - entity_props_ui( - ctx, - ui, - None, - &mut group.properties_individual, - space_view_state, - ); + entity_props_ui(ctx, ui, None, &mut group.properties_individual); } else { ctx.selection_state_mut().clear_current(); } @@ -367,7 +343,6 @@ fn entity_props_ui( ui: &mut egui::Ui, entity_path: Option<&EntityPath>, entity_props: &mut EntityProperties, - view_state: &SpaceViewState, ) { ui.checkbox(&mut entity_props.visible, "Visible"); ui.checkbox(&mut entity_props.interactive, "Interactive") @@ -403,11 +378,11 @@ fn entity_props_ui( } ui.end_row(); - if *view_state.state_spatial.nav_mode.get() == SpatialNavigationMode::ThreeD { - if let Some(entity_path) = entity_path { - pinhole_props_ui(ctx, ui, entity_path, entity_props); - depth_props_ui(ctx, ui, entity_path, entity_props); - } + // TODO(wumpf): It would be nice to only show pinhole & depth properties in the context of a 3D view. + // if *view_state.state_spatial.nav_mode.get() == SpatialNavigationMode::ThreeD { + if let Some(entity_path) = entity_path { + pinhole_props_ui(ctx, ui, entity_path, entity_props); + depth_props_ui(ctx, ui, entity_path, entity_props); } }); } diff --git a/crates/re_viewer_context/src/space_view/space_view_class.rs b/crates/re_viewer_context/src/space_view/space_view_class.rs index 85fd6d53159d..2d880d9bc68c 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class.rs @@ -1,3 +1,4 @@ +use re_data_store::EntityPropertyMap; use re_log_types::{ComponentName, EntityPath}; use crate::{Scene, SpaceViewId, ViewerContext}; @@ -52,10 +53,16 @@ pub trait SpaceViewClass { /// Preferred aspect ratio for the ui tiles of this space view. fn preferred_tile_aspect_ratio(&self, state: &dyn SpaceViewState) -> Option; - /// Executed before the scene is populated. + /// Executed before the scene is populated, can be use for heuristic & state updates before populating the scene. /// /// Is only allowed to access archetypes defined by [`Self::blueprint_archetype`] - fn prepare_populate(&self, _ctx: &mut ViewerContext<'_>, _state: &mut dyn SpaceViewState) {} + /// Passed entity properties are individual properties without propagated values. + fn prepare_populate( + &self, + ctx: &mut ViewerContext<'_>, + state: &mut dyn SpaceViewState, + entity_properties: &mut EntityPropertyMap, + ); /// Ui shown when the user selects a space view of this class. /// diff --git a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs index b65638cc1e96..1dae7454278a 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs @@ -1,3 +1,4 @@ +use re_data_store::EntityPropertyMap; use re_log_types::EntityPath; use crate::{ @@ -42,10 +43,22 @@ pub trait SpaceViewClassImpl: std::marker::Sized { fn help_text(&self, re_ui: &re_ui::ReUi) -> egui::WidgetText; /// Preferred aspect ratio for the ui tiles of this space view. - fn preferred_tile_aspect_ratio(&self, state: &Self::SpaceViewState) -> Option { + fn preferred_tile_aspect_ratio(&self, _state: &Self::SpaceViewState) -> Option { None } + /// Executed before the scene is populated, can be use for heuristic & state updates before populating the scene. + /// + /// Is only allowed to access archetypes defined by [`Self::blueprint_archetype`]. + /// Passed entity properties are individual properties without propagated values. + fn prepare_populate( + &self, + _ctx: &mut ViewerContext<'_>, + _state: &Self::SpaceViewState, + _entity_properties: &mut re_data_store::EntityPropertyMap, + ) { + } + /// Ui shown when the user selects a space view of this class. /// /// TODO(andreas): Should this be instead implemented via a registered `data_ui` of all blueprint relevant types? @@ -101,6 +114,17 @@ impl SpaceViewClass for T { typed_state_wrapper(state, |state| self.preferred_tile_aspect_ratio(state)) } + fn prepare_populate( + &self, + ctx: &mut ViewerContext<'_>, + state: &mut dyn SpaceViewState, + entity_properties: &mut EntityPropertyMap, + ) { + typed_state_wrapper_mut(state, |state| { + self.prepare_populate(ctx, state, entity_properties); + }); + } + #[inline] fn selection_ui( &self, @@ -134,17 +158,18 @@ impl SpaceViewClass for T { } } -fn typed_state_wrapper_mut( +fn typed_state_wrapper_mut R>( state: &mut dyn SpaceViewState, fun: F, -) { +) -> R { if let Some(state) = state.as_any_mut().downcast_mut() { - fun(state); + fun(state) } else { re_log::error_once!( "Unexpected space view state type. Expected {}", std::any::type_name::() ); + R::default() } } diff --git a/crates/re_viewer_context/src/space_view/space_view_class_registry.rs b/crates/re_viewer_context/src/space_view/space_view_class_registry.rs index 0b54a2eebff2..32708ed8f0c3 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class_registry.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class_registry.rs @@ -21,10 +21,10 @@ impl SpaceViewClassRegistry { /// Adds a new space view type. /// /// Fails if a space view type with the same name was already registered. - pub fn add( + pub fn add( &mut self, - space_view_type: impl SpaceViewClass + 'static, ) -> Result<(), SpaceViewClassRegistryError> { + let space_view_type = T::default(); let type_name = space_view_type.name(); if self .0 @@ -38,7 +38,7 @@ impl SpaceViewClassRegistry { } /// Queries a space view type by name. - pub fn query( + pub fn get( &self, name: SpaceViewClassName, ) -> Result<&dyn SpaceViewClass, SpaceViewClassRegistryError> { diff --git a/crates/re_viewport/Cargo.toml b/crates/re_viewport/Cargo.toml index 5d759ea0172d..508813ebd293 100644 --- a/crates/re_viewport/Cargo.toml +++ b/crates/re_viewport/Cargo.toml @@ -36,9 +36,6 @@ re_ui.workspace = true re_viewer_context.workspace = true re_space_view.workspace = true -# TODO(andreas): Temporary until traitification of spatial view is done. -re_space_view_spatial.workspace = true - ahash.workspace = true anyhow.workspace = true arrow2.workspace = true diff --git a/crates/re_viewport/src/auto_layout.rs b/crates/re_viewport/src/auto_layout.rs index 48f5df23bc7b..a6149813fe14 100644 --- a/crates/re_viewport/src/auto_layout.rs +++ b/crates/re_viewport/src/auto_layout.rs @@ -16,7 +16,6 @@ use egui::Vec2; use itertools::Itertools as _; use re_data_store::{EntityPath, EntityPathPart}; -use re_space_view_spatial::SpatialNavigationMode; use re_viewer_context::{SpaceViewId, ViewerContext}; use super::{ @@ -61,7 +60,7 @@ pub(crate) fn tree_from_space_views( // Sort for determinism: .sorted_by_key(|(space_view_id, space_view)| { ( - &space_view.space_path, + &space_view.space_origin, &space_view.display_name, *space_view_id, ) @@ -69,14 +68,14 @@ pub(crate) fn tree_from_space_views( .map(|(space_view_id, space_view)| { let aspect_ratio = space_view_states.get(space_view_id).and_then(|state| { ctx.space_view_class_registry - .query(space_view.class) + .get(space_view.class) .ok() .and_then(|class| class.preferred_tile_aspect_ratio(state.state.as_ref())) }); SpaceMakeInfo { id: *space_view_id, - path: space_view.space_path.clone(), + path: space_view.space_origin.clone(), category: space_view.category, aspect_ratio, } diff --git a/crates/re_viewport/src/lib.rs b/crates/re_viewport/src/lib.rs index 9bcfd5a2d2ce..6f079bc9b796 100644 --- a/crates/re_viewport/src/lib.rs +++ b/crates/re_viewport/src/lib.rs @@ -16,7 +16,6 @@ mod viewport; pub mod blueprint_components; -pub use re_space_view_spatial::SpatialNavigationMode; // TODO(andreas): Remove, have two kinds of space views instead. pub use space_info::SpaceInfoCollection; pub use space_view::{SpaceViewBlueprint, SpaceViewState}; pub use view_category::ViewCategory; diff --git a/crates/re_viewport/src/space_info.rs b/crates/re_viewport/src/space_info.rs index fab17160ffb9..df0e03bc3773 100644 --- a/crates/re_viewport/src/space_info.rs +++ b/crates/re_viewport/src/space_info.rs @@ -1,10 +1,10 @@ use nohash_hasher::IntSet; +use re_space_view::UnreachableTransform; use std::collections::BTreeMap; use re_arrow_store::{LatestAtQuery, TimeInt, Timeline}; use re_components::{DisconnectedSpace, Pinhole, Transform3D}; use re_data_store::{store_db::EntityDb, EntityPath, EntityTree}; -use re_space_view_spatial::UnreachableTransform; /// Transform connecting two space paths. #[derive(Clone, Debug)] diff --git a/crates/re_viewport/src/space_view.rs b/crates/re_viewport/src/space_view.rs index 64987dcfdb0e..20d004ac69f2 100644 --- a/crates/re_viewport/src/space_view.rs +++ b/crates/re_viewport/src/space_view.rs @@ -1,10 +1,8 @@ use re_arrow_store::Timeline; use re_data_store::{EntityPath, EntityTree, InstancePath, TimeInt}; use re_renderer::ScreenshotProcessor; -use re_space_view::{DataBlueprintHeuristic, DataBlueprintTree, ScreenshotMode}; -use re_viewer_context::{ - Scene, SpaceViewClassName, SpaceViewHighlights, SpaceViewId, ViewerContext, -}; +use re_space_view::{DataBlueprintTree, ScreenshotMode}; +use re_viewer_context::{SpaceViewClassName, SpaceViewHighlights, SpaceViewId, ViewerContext}; use crate::{ space_info::SpaceInfoCollection, @@ -27,7 +25,7 @@ pub struct SpaceViewBlueprint { /// The transform at this path forms the reference point for all scene->world transforms in this space view. /// I.e. the position of this entity path in space forms the origin of the coordinate system in this space view. /// Furthermore, this is the primary indicator for heuristics on what entities we show in this space view. - pub space_path: EntityPath, + pub space_origin: EntityPath, /// The data blueprint tree, has blueprint settings for all blueprint groups and entities in this spaceview. /// It determines which entities are part of the spaceview. @@ -67,7 +65,7 @@ impl SpaceViewBlueprint { display_name, class: space_view_class, id: SpaceViewId::random(), - space_path: space_path.clone(), + space_origin: space_path.clone(), data_blueprint: data_blueprint_tree, category, entities_determined_by_user: false, @@ -84,9 +82,11 @@ impl SpaceViewBlueprint { if !self.entities_determined_by_user { // Add entities that have been logged since we were created let queries_entities = - default_queried_entities(ctx, &self.space_path, spaces_info, self.category); - self.data_blueprint - .insert_entities_according_to_hierarchy(queries_entities.iter(), &self.space_path); + default_queried_entities(ctx, &self.space_origin, spaces_info, self.category); + self.data_blueprint.insert_entities_according_to_hierarchy( + queries_entities.iter(), + &self.space_origin, + ); } while ScreenshotProcessor::next_readback_result( @@ -145,7 +145,7 @@ impl SpaceViewBlueprint { ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, ) { - if let Ok(space_view_class) = ctx.space_view_class_registry.query(self.class) { + if let Ok(space_view_class) = ctx.space_view_class_registry.get(self.class) { re_tracing::profile_scope!("selection_ui", space_view_class.name()); space_view_class.selection_ui(ctx, ui, view_state.state.as_mut()); } else { @@ -186,37 +186,42 @@ impl SpaceViewBlueprint { return; } - let query = re_viewer_context::SceneQuery { - space_origin: &self.space_path, - entity_paths: self.data_blueprint.entity_paths(), - timeline: *ctx.rec_cfg.time_ctrl.timeline(), - latest_at, - entity_props_map: self.data_blueprint.data_blueprints_projected(), - }; - - if let Ok(space_view_class) = ctx.space_view_class_registry.query(self.class) { - space_view_class.prepare_populate(ctx, view_state.state.as_mut()); - - if let Some(heuristic) = view_state - .state - .as_ref() - .as_any() - .downcast_ref::() - { - heuristic.update_object_property_heuristics(ctx, &mut self.data_blueprint); - } + if let Ok(space_view_class) = ctx.space_view_class_registry.get(self.class) { + space_view_class.prepare_populate( + ctx, + view_state.state.as_mut(), + self.data_blueprint.data_blueprints_individual(), + ); + + let query = re_viewer_context::SceneQuery { + space_origin: &self.space_origin, + entity_paths: self.data_blueprint.entity_paths(), + timeline: *ctx.rec_cfg.time_ctrl.timeline(), + latest_at, + entity_props_map: self.data_blueprint.data_blueprints_projected(), + }; let mut scene = space_view_class.new_scene(); scene.populate(ctx, &query, view_state.state.as_ref(), highlights); - // TODO(andreas): Pass scene to renderer. - // TODO(andreas): Setup re_renderer view. - { - re_tracing::profile_scope!("ui", space_view_class.name()); - space_view_class.ui(ctx, ui, view_state.state.as_mut(), scene); - } + space_view_class.ui( + ctx, + ui, + view_state.state.as_mut(), + scene, + &self.space_origin, + self.id, + ); } else { // Legacy handling + let query = re_viewer_context::SceneQuery { + space_origin: &self.space_origin, + entity_paths: self.data_blueprint.entity_paths(), + timeline: *ctx.rec_cfg.time_ctrl.timeline(), + latest_at, + entity_props_map: self.data_blueprint.data_blueprints_projected(), + }; + match self.category { ViewCategory::Text | ViewCategory::TextBox | ViewCategory::Spatial => { // migrated. @@ -274,7 +279,7 @@ impl SpaceViewBlueprint { if entity_categories.contains(self.category) && !self.data_blueprint.contains_entity(entity_path) && spaces_info - .is_reachable_by_transform(entity_path, &self.space_path) + .is_reachable_by_transform(entity_path, &self.space_origin) .is_ok() { entities.push(entity_path.clone()); @@ -283,7 +288,7 @@ impl SpaceViewBlueprint { if !entities.is_empty() { self.data_blueprint - .insert_entities_according_to_hierarchy(entities.iter(), &self.space_path); + .insert_entities_according_to_hierarchy(entities.iter(), &self.space_origin); self.entities_determined_by_user = true; } } diff --git a/crates/re_viewport/src/space_view_entity_picker.rs b/crates/re_viewport/src/space_view_entity_picker.rs index e9e143a95f48..89e35aec2a83 100644 --- a/crates/re_viewport/src/space_view_entity_picker.rs +++ b/crates/re_viewport/src/space_view_entity_picker.rs @@ -120,7 +120,7 @@ fn add_entities_tree_ui( ); } else { let level = tree.path.len(); - let default_open = space_view.space_path.is_descendant_of(&tree.path) + let default_open = space_view.space_origin.is_descendant_of(&tree.path) || tree.children.len() <= 3 || level < 2; egui::collapsing_header::CollapsingState::load_with_default_open( @@ -142,8 +142,8 @@ fn add_entities_tree_ui( .body(|ui| { for (path_comp, child_tree) in tree.children.iter().sorted_by_key(|(_, child_tree)| { // Put descendants of the space path always first - let put_first = child_tree.path == space_view.space_path - || child_tree.path.is_descendant_of(&space_view.space_path); + let put_first = child_tree.path == space_view.space_origin + || child_tree.path.is_descendant_of(&space_view.space_origin); !put_first }) { add_entities_tree_ui( @@ -180,7 +180,7 @@ fn add_entities_line_ui( let add_info = entities_add_info.get(entity_path).unwrap(); ui.add_enabled_ui(add_info.can_add_self_or_descendant.is_compatible(), |ui| { - let widget_text = if entity_path == &space_view.space_path { + let widget_text = if entity_path == &space_view.space_origin { egui::RichText::new(name).strong() } else { egui::RichText::new(name) @@ -192,7 +192,7 @@ fn add_entities_line_ui( &InstancePath::entity_splat(entity_path.clone()), widget_text, ); - if entity_path == &space_view.space_path { + if entity_path == &space_view.space_origin { response.highlight(); } }); @@ -309,7 +309,7 @@ fn create_entity_add_info( tree.visit_children_recursively(&mut |entity_path| { let categories = categorize_entity_path(Timeline::log_time(), ctx.store_db, entity_path); let can_add: CanAddToSpaceView = if categories.contains(space_view.category) { - match spaces_info.is_reachable_by_transform(entity_path, &space_view.space_path) { + match spaces_info.is_reachable_by_transform(entity_path, &space_view.space_origin) { Ok(()) => CanAddToSpaceView::Compatible { already_added: space_view.data_blueprint.contains_entity(entity_path), }, diff --git a/crates/re_viewport/src/space_view_heuristics.rs b/crates/re_viewport/src/space_view_heuristics.rs index 0e129bfd2cf2..8e7a8c79ad25 100644 --- a/crates/re_viewport/src/space_view_heuristics.rs +++ b/crates/re_viewport/src/space_view_heuristics.rs @@ -94,7 +94,7 @@ fn is_interesting_space_view_not_at_root( query: &LatestAtQuery, ) -> bool { // Consider children of the root interesting, *unless* a root with the same category was already considered interesting! - if candidate.space_path.len() == 1 + if candidate.space_origin.len() == 1 && !categories_with_interesting_roots.contains(candidate.category) { return true; @@ -106,10 +106,10 @@ fn is_interesting_space_view_not_at_root( // .. an pinhole transform, we'd like to see the world from this camera's pov as well! if candidate.category == ViewCategory::Spatial && (store - .query_latest_component::(&candidate.space_path, query) + .query_latest_component::(&candidate.space_origin, query) .is_some() || store - .query_latest_component::(&candidate.space_path, query) + .query_latest_component::(&candidate.space_origin, query) .is_some()) { return true; @@ -141,7 +141,7 @@ fn default_created_space_views_from_candidates( let categories_with_interesting_roots = candidates .iter() .filter_map(|space_view_candidate| { - (space_view_candidate.space_path.is_root() + (space_view_candidate.space_origin.is_root() && is_interesting_space_view_at_root(store, space_view_candidate, &query)) .then_some(space_view_candidate.category) }) @@ -152,7 +152,7 @@ fn default_created_space_views_from_candidates( // Main pass through all candidates. // We first check if a candidate is "interesting" and then split it up/modify it further if required. for candidate in candidates { - if candidate.space_path.is_root() { + if candidate.space_origin.is_root() { if !categories_with_interesting_roots.contains(candidate.category) { continue; } @@ -237,7 +237,7 @@ fn default_created_space_views_from_candidates( let mut space_view = SpaceViewBlueprint::new( candidate.class, candidate.category, - &candidate.space_path, + &candidate.space_origin, &entities, ); space_view.entities_determined_by_user = true; // Suppress auto adding of entities. diff --git a/crates/re_viewport/src/viewport.rs b/crates/re_viewport/src/viewport.rs index 3209a4297632..b7b203318ead 100644 --- a/crates/re_viewport/src/viewport.rs +++ b/crates/re_viewport/src/viewport.rs @@ -114,7 +114,10 @@ impl Viewport { .space_views .keys() .sorted_by_key(|space_view_id| { - (&self.space_views[space_view_id].space_path, *space_view_id) + ( + &self.space_views[space_view_id].space_origin, + *space_view_id, + ) }) .copied() .collect_vec(); @@ -384,7 +387,7 @@ impl Viewport { fn should_auto_add_space_view(&self, space_view_candidate: &SpaceViewBlueprint) -> bool { for existing_view in self.space_views.values() { - if existing_view.space_path == space_view_candidate.space_path { + if existing_view.space_origin == space_view_candidate.space_origin { if existing_view.entities_determined_by_user { // Since the user edited a space view with the same space path, we can't be sure our new one isn't redundant. // So let's skip that. @@ -445,6 +448,7 @@ impl Viewport { .entry(visible_space_views.clone()) .or_insert_with(|| { super::auto_layout::tree_from_space_views( + ctx, ui.available_size(), &visible_space_views, &self.space_views, @@ -479,10 +483,9 @@ impl Viewport { for space_view in all_possible_space_views(ctx, spaces_info) .into_iter() - .sorted_by_key(|space_view| space_view.space_path.to_string()) + .sorted_by_key(|space_view| space_view.space_origin.to_string()) { - let icon = if let Ok(class) = ctx.space_view_class_registry.query(space_view.class) - { + let icon = if let Ok(class) = ctx.space_view_class_registry.get(space_view.class) { class.icon() } else { // TODO(andreas): Error handling if class is not found once categories are gone. @@ -494,10 +497,10 @@ impl Viewport { .selectable_label_with_icon( ui, icon, - if space_view.space_path.is_root() { + if space_view.space_origin.is_root() { space_view.display_name.clone() } else { - space_view.space_path.to_string() + space_view.space_origin.to_string() }, false, ) @@ -549,7 +552,7 @@ impl ViewportState { self.space_view_states .entry(space_view_id) .or_insert_with(|| { - let state = if let Ok(state) = space_view_class_registry.query(space_view_class) { + let state = if let Ok(state) = space_view_class_registry.get(space_view_class) { state.new_state() } else { // TODO(andreas): Enable this once categories are gone. @@ -564,7 +567,6 @@ impl ViewportState { selected_tensor: Default::default(), state_time_series: Default::default(), state_bar_chart: Default::default(), - state_spatial: Default::default(), state_tensors: Default::default(), } }) @@ -760,7 +762,6 @@ impl<'a, 'b> egui_tiles::Behavior for TabViewer<'a, 'b> { let space_view_id = *space_view_id; let Some(space_view) = self.space_views.get(&space_view_id) else { return; }; - let Some(space_view_state) = self.viewport_state.space_view_states.get(&space_view_id) else { return; }; let num_space_views = tiles.tiles.values().filter(|tile| tile.is_pane()).count(); @@ -793,7 +794,7 @@ impl<'a, 'b> egui_tiles::Behavior for TabViewer<'a, 'b> { } // Show help last, since not all space views have help text - help_text_ui(ui, self.ctx.re_ui, space_view, space_view_state); + help_text_ui(self.ctx, ui, space_view); } // Styling: @@ -822,16 +823,24 @@ impl<'a, 'b> egui_tiles::Behavior for TabViewer<'a, 'b> { } fn help_text_ui( + ctx: &ViewerContext<'_>, ui: &mut egui::Ui, - re_ui: &re_ui::ReUi, space_view_blueprint: &SpaceViewBlueprint, - space_view_state: &SpaceViewState, ) { - let help_text = match space_view_blueprint.category { - ViewCategory::TimeSeries => Some(crate::view_time_series::help_text(re_ui)), - ViewCategory::BarChart => Some(crate::view_bar_chart::help_text(re_ui)), - ViewCategory::Spatial => Some(space_view_state.state_spatial.help_text(re_ui)), - ViewCategory::TextBox | ViewCategory::Text | ViewCategory::Tensor => None, + let help_text = if let Ok(class) = ctx + .space_view_class_registry + .get(space_view_blueprint.class) + { + Some(class.help_text(ctx.re_ui)) + } else { + match space_view_blueprint.category { + ViewCategory::TimeSeries => Some(crate::view_time_series::help_text(ctx.re_ui)), + ViewCategory::BarChart => Some(crate::view_bar_chart::help_text(ctx.re_ui)), + ViewCategory::TextBox + | ViewCategory::Text + | ViewCategory::Tensor + | ViewCategory::Spatial => None, + } }; if let Some(help_text) = help_text { From 9d24ac8d0152b570689e2dd506c2a42214224f7d Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 18:19:30 +0200 Subject: [PATCH 07/15] fix up help text and ui for space origin --- .../src/space_view_class.rs | 9 +++--- crates/re_space_view_spatial/src/ui.rs | 29 ++++++++++--------- .../src/space_view_class.rs | 4 ++- .../src/space_view_class.rs | 4 ++- .../src/space_view/space_view_class.rs | 4 ++- .../src/space_view/space_view_class_impl.rs | 14 ++++++--- crates/re_viewport/src/space_view.rs | 8 ++++- crates/re_viewport/src/viewport.rs | 6 ++-- 8 files changed, 50 insertions(+), 28 deletions(-) diff --git a/crates/re_space_view_spatial/src/space_view_class.rs b/crates/re_space_view_spatial/src/space_view_class.rs index 4b49fb8f4b11..213d53956702 100644 --- a/crates/re_space_view_spatial/src/space_view_class.rs +++ b/crates/re_space_view_spatial/src/space_view_class.rs @@ -23,9 +23,8 @@ impl SpaceViewClassImpl for SpatialSpaceView { &re_ui::icons::SPACE_VIEW_3D } - fn help_text(&self, _re_ui: &re_ui::ReUi) -> egui::WidgetText { - // TODO: - "todo".into() + fn help_text(&self, re_ui: &re_ui::ReUi, state: &Self::SpaceViewState) -> egui::WidgetText { + state.help_text(re_ui) } fn preferred_tile_aspect_ratio(&self, state: &Self::SpaceViewState) -> Option { @@ -52,8 +51,10 @@ impl SpaceViewClassImpl for SpatialSpaceView { ctx: &mut re_viewer_context::ViewerContext<'_>, ui: &mut egui::Ui, state: &mut Self::SpaceViewState, + space_origin: &EntityPath, + space_view_id: SpaceViewId, ) { - state.selection_ui(ctx, ui); + state.selection_ui(ctx, ui, space_origin, space_view_id); } fn ui( diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index f8859f96198a..1d73981c29bc 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -242,24 +242,25 @@ impl SpatialSpaceViewState { Some(()) } - pub fn selection_ui(&mut self, ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui) { + pub fn selection_ui( + &mut self, + ctx: &mut ViewerContext<'_>, + ui: &mut egui::Ui, + space_origin: &EntityPath, + space_view_id: SpaceViewId, + ) { ctx.re_ui.selection_grid(ui, "spatial_settings_ui") .show(ui, |ui| { let auto_size_world = self.auto_size_world_heuristic(); - // TODO: - // ctx.re_ui.grid_left_hand_label(ui, "Space origin") - // .on_hover_text("The origin is at the origin of this Entity. All transforms are relative to it"); - // // Specify space view id only if this is actually part of the space view itself. - // // (otherwise we get a somewhat broken link) - // item_ui::entity_path_button(ctx, - // ui, - // data_blueprint - // .contains_entity(space_path) - // .then_some(space_view_id), - // space_path, - // ); - // ui.end_row(); + ctx.re_ui.grid_left_hand_label(ui, "Space origin") + .on_hover_text("The origin is at the origin of this Entity. All transforms are relative to it"); + item_ui::entity_path_button(ctx, + ui, + Some(space_view_id), + space_origin, + ); + ui.end_row(); ctx.re_ui.grid_left_hand_label(ui, "Default size"); ui.vertical(|ui| { diff --git a/crates/re_space_view_text/src/space_view_class.rs b/crates/re_space_view_text/src/space_view_class.rs index cb8b077f16b6..af1ad6761521 100644 --- a/crates/re_space_view_text/src/space_view_class.rs +++ b/crates/re_space_view_text/src/space_view_class.rs @@ -50,7 +50,7 @@ impl SpaceViewClassImpl for TextSpaceView { &re_ui::icons::SPACE_VIEW_TEXTBOX } - fn help_text(&self, _re_ui: &re_ui::ReUi) -> egui::WidgetText { + fn help_text(&self, _re_ui: &re_ui::ReUi, _state: &Self::SpaceViewState) -> egui::WidgetText { "Shows text entries over time.\nSelect the Space View for filtering options.".into() } @@ -63,6 +63,8 @@ impl SpaceViewClassImpl for TextSpaceView { ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut Self::SpaceViewState, + _space_origin: &EntityPath, + _space_view_id: SpaceViewId, ) { let ViewTextFilters { col_timelines, diff --git a/crates/re_space_view_text_box/src/space_view_class.rs b/crates/re_space_view_text_box/src/space_view_class.rs index 544053cc2c1a..1cabf262c505 100644 --- a/crates/re_space_view_text_box/src/space_view_class.rs +++ b/crates/re_space_view_text_box/src/space_view_class.rs @@ -49,7 +49,7 @@ impl SpaceViewClassImpl for TextBoxSpaceView { &re_ui::icons::SPACE_VIEW_TEXTBOX } - fn help_text(&self, _re_ui: &re_ui::ReUi) -> egui::WidgetText { + fn help_text(&self, _re_ui: &re_ui::ReUi, _state: &Self::SpaceViewState) -> egui::WidgetText { "Displays text from a text entry components.".into() } @@ -58,6 +58,8 @@ impl SpaceViewClassImpl for TextBoxSpaceView { ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut Self::SpaceViewState, + _space_origin: &EntityPath, + _space_view_id: SpaceViewId, ) { ctx.re_ui.selection_grid(ui, "text_config").show(ui, |ui| { ctx.re_ui.grid_left_hand_label(ui, "Text style"); diff --git a/crates/re_viewer_context/src/space_view/space_view_class.rs b/crates/re_viewer_context/src/space_view/space_view_class.rs index 2d880d9bc68c..93b25b238f55 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class.rs @@ -30,7 +30,7 @@ pub trait SpaceViewClass { fn icon(&self) -> &'static re_ui::Icon; /// Help text describing how to interact with this space view in the ui. - fn help_text(&self, re_ui: &re_ui::ReUi) -> egui::WidgetText; + fn help_text(&self, re_ui: &re_ui::ReUi, state: &dyn SpaceViewState) -> egui::WidgetText; /// Called once for every new space view instance of this class. /// @@ -72,6 +72,8 @@ pub trait SpaceViewClass { ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut dyn SpaceViewState, + space_origin: &EntityPath, + space_view_id: SpaceViewId, ); /// Draws the ui for this space view type and handles ui events. diff --git a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs index 1dae7454278a..039739b7f0ff 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs @@ -40,7 +40,7 @@ pub trait SpaceViewClassImpl: std::marker::Sized { fn icon(&self) -> &'static re_ui::Icon; /// Help text describing how to interact with this space view in the ui. - fn help_text(&self, re_ui: &re_ui::ReUi) -> egui::WidgetText; + fn help_text(&self, re_ui: &re_ui::ReUi, state: &Self::SpaceViewState) -> egui::WidgetText; /// Preferred aspect ratio for the ui tiles of this space view. fn preferred_tile_aspect_ratio(&self, _state: &Self::SpaceViewState) -> Option { @@ -67,6 +67,8 @@ pub trait SpaceViewClassImpl: std::marker::Sized { ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut Self::SpaceViewState, + space_origin: &EntityPath, + space_view_id: SpaceViewId, ); /// Draws the ui for this space view class and handles ui events. @@ -96,8 +98,8 @@ impl SpaceViewClass for T { } #[inline] - fn help_text(&self, re_ui: &re_ui::ReUi) -> egui::WidgetText { - self.help_text(re_ui) + fn help_text(&self, re_ui: &re_ui::ReUi, state: &dyn SpaceViewState) -> egui::WidgetText { + typed_state_wrapper(state, |state| self.help_text(re_ui, state)) } #[inline] @@ -131,8 +133,12 @@ impl SpaceViewClass for T { ctx: &mut ViewerContext<'_>, ui: &mut egui::Ui, state: &mut dyn SpaceViewState, + space_origin: &EntityPath, + space_view_id: SpaceViewId, ) { - typed_state_wrapper_mut(state, |state| self.selection_ui(ctx, ui, state)); + typed_state_wrapper_mut(state, |state| { + self.selection_ui(ctx, ui, state, space_origin, space_view_id); + }); } #[inline] diff --git a/crates/re_viewport/src/space_view.rs b/crates/re_viewport/src/space_view.rs index 20d004ac69f2..dafb495df9d7 100644 --- a/crates/re_viewport/src/space_view.rs +++ b/crates/re_viewport/src/space_view.rs @@ -147,7 +147,13 @@ impl SpaceViewBlueprint { ) { if let Ok(space_view_class) = ctx.space_view_class_registry.get(self.class) { re_tracing::profile_scope!("selection_ui", space_view_class.name()); - space_view_class.selection_ui(ctx, ui, view_state.state.as_mut()); + space_view_class.selection_ui( + ctx, + ui, + view_state.state.as_mut(), + &self.space_origin, + self.id, + ); } else { // Legacy handling diff --git a/crates/re_viewport/src/viewport.rs b/crates/re_viewport/src/viewport.rs index b7b203318ead..7f9462ad95db 100644 --- a/crates/re_viewport/src/viewport.rs +++ b/crates/re_viewport/src/viewport.rs @@ -762,6 +762,7 @@ impl<'a, 'b> egui_tiles::Behavior for TabViewer<'a, 'b> { let space_view_id = *space_view_id; let Some(space_view) = self.space_views.get(&space_view_id) else { return; }; + let Some(space_view_state) = self.viewport_state.space_view_states.get(&space_view_id) else { return; }; let num_space_views = tiles.tiles.values().filter(|tile| tile.is_pane()).count(); @@ -794,7 +795,7 @@ impl<'a, 'b> egui_tiles::Behavior for TabViewer<'a, 'b> { } // Show help last, since not all space views have help text - help_text_ui(self.ctx, ui, space_view); + help_text_ui(self.ctx, ui, space_view, space_view_state); } // Styling: @@ -826,12 +827,13 @@ fn help_text_ui( ctx: &ViewerContext<'_>, ui: &mut egui::Ui, space_view_blueprint: &SpaceViewBlueprint, + space_view_state: &SpaceViewState, ) { let help_text = if let Ok(class) = ctx .space_view_class_registry .get(space_view_blueprint.class) { - Some(class.help_text(ctx.re_ui)) + Some(class.help_text(ctx.re_ui, space_view_state.state.as_ref())) } else { match space_view_blueprint.category { ViewCategory::TimeSeries => Some(crate::view_time_series::help_text(ctx.re_ui)), From e0904ad3ca9dbc99eebe3a8c68e960f71d33e8ab Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 18:33:11 +0200 Subject: [PATCH 08/15] doc fix --- .../src/space_view/space_view_class.rs | 4 +--- .../src/space_view/space_view_class_impl.rs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/crates/re_viewer_context/src/space_view/space_view_class.rs b/crates/re_viewer_context/src/space_view/space_view_class.rs index 93b25b238f55..aa73918c5aae 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class.rs @@ -46,9 +46,7 @@ pub trait SpaceViewClass { /// Optional archetype of the Space View's blueprint properties. /// /// Blueprint components that only apply to the space view itself, not to the entities it displays. - fn blueprint_archetype(&self) -> Option { - None - } + fn blueprint_archetype(&self) -> Option; /// Preferred aspect ratio for the ui tiles of this space view. fn preferred_tile_aspect_ratio(&self, state: &dyn SpaceViewState) -> Option; diff --git a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs index 039739b7f0ff..49aca554a320 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs @@ -2,8 +2,8 @@ use re_data_store::EntityPropertyMap; use re_log_types::EntityPath; use crate::{ - Scene, SceneContext, ScenePartCollection, SpaceViewClass, SpaceViewClassName, SpaceViewId, - SpaceViewState, ViewerContext, + ArchetypeDefinition, Scene, SceneContext, ScenePartCollection, SpaceViewClass, + SpaceViewClassName, SpaceViewId, SpaceViewState, ViewerContext, }; use super::scene::TypedScene; @@ -47,6 +47,13 @@ pub trait SpaceViewClassImpl: std::marker::Sized { None } + /// Optional archetype of the Space View's blueprint properties. + /// + /// Blueprint components that only apply to the space view itself, not to the entities it displays. + fn blueprint_archetype(&self) -> Option { + None + } + /// Executed before the scene is populated, can be use for heuristic & state updates before populating the scene. /// /// Is only allowed to access archetypes defined by [`Self::blueprint_archetype`]. @@ -116,6 +123,10 @@ impl SpaceViewClass for T { typed_state_wrapper(state, |state| self.preferred_tile_aspect_ratio(state)) } + fn blueprint_archetype(&self) -> Option { + self.blueprint_archetype() + } + fn prepare_populate( &self, ctx: &mut ViewerContext<'_>, From cb71864747426123e53910c86d9af8b9748c3db5 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 18:37:41 +0200 Subject: [PATCH 09/15] remove old ui_renderer_bridge --- crates/re_space_view_spatial/src/lib.rs | 1 - crates/re_space_view_spatial/src/ui_2d.rs | 20 ++++++------- crates/re_space_view_spatial/src/ui_3d.rs | 8 ++---- .../src/ui_renderer_bridge.rs | 28 ------------------- 4 files changed, 11 insertions(+), 46 deletions(-) delete mode 100644 crates/re_space_view_spatial/src/ui_renderer_bridge.rs diff --git a/crates/re_space_view_spatial/src/lib.rs b/crates/re_space_view_spatial/src/lib.rs index e4f0700110bf..447b6e77e77e 100644 --- a/crates/re_space_view_spatial/src/lib.rs +++ b/crates/re_space_view_spatial/src/lib.rs @@ -13,6 +13,5 @@ mod space_view_class; mod ui; mod ui_2d; mod ui_3d; -mod ui_renderer_bridge; pub use space_view_class::SpatialSpaceView; diff --git a/crates/re_space_view_spatial/src/ui_2d.rs b/crates/re_space_view_spatial/src/ui_2d.rs index a999fbde597d..b1aaa2cdaf19 100644 --- a/crates/re_space_view_spatial/src/ui_2d.rs +++ b/crates/re_space_view_spatial/src/ui_2d.rs @@ -14,7 +14,6 @@ use super::{ use crate::{ scene::SceneSpatial, ui::{outline_config, SpatialNavigationMode, SpatialSpaceViewState}, - ui_renderer_bridge::{fill_view_builder, ScreenBackground}, }; // --- @@ -349,17 +348,14 @@ pub fn view_2d( // Draw a re_renderer driven view. // Camera & projection are configured to ingest space coordinates directly. { - let command_buffer = match fill_view_builder( - ctx.render_ctx, - &mut view_builder, - &ScreenBackground::ClearColor(ui.visuals().extreme_bg_color.into()), - ) { - Ok(command_buffer) => command_buffer, - Err(err) => { - re_log::error_once!("Failed to fill view builder: {err}"); - return response; - } - }; + let command_buffer = + match view_builder.draw(ctx.render_ctx, ui.visuals().extreme_bg_color.into()) { + Ok(command_buffer) => command_buffer, + Err(err) => { + re_log::error_once!("Failed to fill view builder: {err}"); + return response; + } + }; painter.add(gpu_bridge::renderer_paint_callback( ctx.render_ctx, command_buffer, diff --git a/crates/re_space_view_spatial/src/ui_3d.rs b/crates/re_space_view_spatial/src/ui_3d.rs index 37afdfefe85f..90eebfc691f6 100644 --- a/crates/re_space_view_spatial/src/ui_3d.rs +++ b/crates/re_space_view_spatial/src/ui_3d.rs @@ -23,7 +23,6 @@ use crate::{ create_labels, outline_config, picking, screenshot_context_menu, SpatialNavigationMode, SpatialSpaceViewState, }, - ui_renderer_bridge::{fill_view_builder, ScreenBackground}, }; use super::eye::{Eye, OrbitEye}; @@ -539,11 +538,10 @@ pub fn view_3d( } // Composite viewbuilder into egui. - let command_buffer = match fill_view_builder( + view_builder.queue_draw(re_renderer::renderer::GenericSkyboxDrawData::new( ctx.render_ctx, - &mut view_builder, - &ScreenBackground::GenericSkybox, - ) { + )); + let command_buffer = match view_builder.draw(ctx.render_ctx, re_renderer::Rgba::TRANSPARENT) { Ok(command_buffer) => command_buffer, Err(err) => { re_log::error_once!("Failed to fill view builder: {err}"); diff --git a/crates/re_space_view_spatial/src/ui_renderer_bridge.rs b/crates/re_space_view_spatial/src/ui_renderer_bridge.rs deleted file mode 100644 index 32bb15bc4177..000000000000 --- a/crates/re_space_view_spatial/src/ui_renderer_bridge.rs +++ /dev/null @@ -1,28 +0,0 @@ -use re_renderer::{renderer::GenericSkyboxDrawData, view_builder::ViewBuilder, RenderContext}; - -pub enum ScreenBackground { - GenericSkybox, - ClearColor(re_renderer::Rgba), -} - -pub fn fill_view_builder( - render_ctx: &mut RenderContext, - view_builder: &mut ViewBuilder, - background: &ScreenBackground, -) -> anyhow::Result { - re_tracing::profile_function!(); - - if matches!(background, ScreenBackground::GenericSkybox) { - view_builder.queue_draw(GenericSkyboxDrawData::new(render_ctx)); - } - - let command_buffer = view_builder.draw( - render_ctx, - match background { - ScreenBackground::GenericSkybox => re_renderer::Rgba::TRANSPARENT, - ScreenBackground::ClearColor(c) => *c, - }, - )?; - - Ok(command_buffer) -} From b94bfaa82e014ba9a4e77b464cc3ceb00a248b41 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 18:41:18 +0200 Subject: [PATCH 10/15] fix picking skipping everything but interactive object --- crates/re_space_view_spatial/src/ui.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index 1d73981c29bc..b72b1809a51f 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -731,7 +731,7 @@ pub fn picking( let Some(mut instance_path) = hit.instance_path_hash.resolve(&ctx.store_db.entity_db) else { continue; }; - if !scene + if scene .context .non_interactive_entities .0 From 23b1a126fcbefc3d20d70a7d25eefa5df556afcd Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 18:53:53 +0200 Subject: [PATCH 11/15] fix entity property heuristics not being applied --- crates/re_data_store/src/entity_properties.rs | 6 ----- .../src/space_view_class.rs | 4 +++- crates/re_space_view_spatial/src/ui.rs | 24 +++++-------------- .../src/space_view/space_view_class.rs | 2 ++ .../src/space_view/space_view_class_impl.rs | 5 +++- crates/re_viewport/src/space_view.rs | 1 + 6 files changed, 16 insertions(+), 26 deletions(-) diff --git a/crates/re_data_store/src/entity_properties.rs b/crates/re_data_store/src/entity_properties.rs index 7502453d5d08..e15169bb4c6a 100644 --- a/crates/re_data_store/src/entity_properties.rs +++ b/crates/re_data_store/src/entity_properties.rs @@ -34,12 +34,6 @@ impl EntityPropertyMap { pub fn iter(&self) -> impl Iterator { self.props.iter() } - - /// Iterates over all paths that have a non-default value. - #[inline] - pub fn iter_non_default_entities(&self) -> impl Iterator { - self.props.keys() - } } // ---------------------------------------------------------------------------- diff --git a/crates/re_space_view_spatial/src/space_view_class.rs b/crates/re_space_view_spatial/src/space_view_class.rs index 213d53956702..4584a75102fd 100644 --- a/crates/re_space_view_spatial/src/space_view_class.rs +++ b/crates/re_space_view_spatial/src/space_view_class.rs @@ -1,3 +1,4 @@ +use nohash_hasher::IntSet; use re_log_types::EntityPath; use re_viewer_context::{SpaceViewClassImpl, SpaceViewId}; @@ -41,9 +42,10 @@ impl SpaceViewClassImpl for SpatialSpaceView { &self, ctx: &mut re_viewer_context::ViewerContext<'_>, state: &Self::SpaceViewState, + entity_paths: &IntSet, entity_properties: &mut re_data_store::EntityPropertyMap, ) { - state.update_object_property_heuristics(ctx, entity_properties); + state.update_object_property_heuristics(ctx, entity_paths, entity_properties); } fn selection_ui( diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index b72b1809a51f..6aa97a8caca6 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -1,8 +1,8 @@ use eframe::epaint::text::TextWrapping; use egui::{NumExt, WidgetText}; -use itertools::Itertools as _; use macaw::BoundingBox; +use nohash_hasher::IntSet; use re_components::{Pinhole, Tensor, TensorDataMeaning}; use re_data_store::{EditableAutoValue, EntityPath}; use re_data_ui::{item_ui, DataUi}; @@ -132,24 +132,14 @@ impl SpatialSpaceViewState { pub fn update_object_property_heuristics( &self, ctx: &mut ViewerContext<'_>, + entity_paths: &IntSet, entity_properties: &mut re_data_store::EntityPropertyMap, ) { re_tracing::profile_function!(); - let query = ctx.current_query(); - - let entity_paths = entity_properties - .iter_non_default_entities() - .cloned() - .collect_vec(); // TODO(andreas): Workaround borrow checker for entity_path in entity_paths { - self.update_pinhole_property_heuristics(ctx, &query, &entity_path, entity_properties); - self.update_depth_cloud_property_heuristics( - ctx, - &query, - &entity_path, - entity_properties, - ); + self.update_pinhole_property_heuristics(ctx, &entity_path, entity_properties); + self.update_depth_cloud_property_heuristics(ctx, &entity_path, entity_properties); } } @@ -178,13 +168,12 @@ impl SpatialSpaceViewState { fn update_pinhole_property_heuristics( &self, ctx: &mut ViewerContext<'_>, - query: &re_arrow_store::LatestAtQuery, entity_path: &EntityPath, entity_properties: &mut re_data_store::EntityPropertyMap, ) { let store = &ctx.store_db.entity_db.data_store; if store - .query_latest_component::(entity_path, query) + .query_latest_component::(entity_path, &ctx.current_query()) .is_some() { let mut properties = entity_properties.get(entity_path); @@ -205,12 +194,11 @@ impl SpatialSpaceViewState { fn update_depth_cloud_property_heuristics( &self, ctx: &mut ViewerContext<'_>, - query: &re_arrow_store::LatestAtQuery, entity_path: &EntityPath, entity_properties: &mut re_data_store::EntityPropertyMap, ) -> Option<()> { let store = &ctx.store_db.entity_db.data_store; - let tensor = store.query_latest_component::(entity_path, query)?; + let tensor = store.query_latest_component::(entity_path, &ctx.current_query())?; let mut properties = entity_properties.get(entity_path); if properties.backproject_depth.is_auto() { diff --git a/crates/re_viewer_context/src/space_view/space_view_class.rs b/crates/re_viewer_context/src/space_view/space_view_class.rs index aa73918c5aae..5502d5445bb8 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class.rs @@ -1,3 +1,4 @@ +use nohash_hasher::IntSet; use re_data_store::EntityPropertyMap; use re_log_types::{ComponentName, EntityPath}; @@ -59,6 +60,7 @@ pub trait SpaceViewClass { &self, ctx: &mut ViewerContext<'_>, state: &mut dyn SpaceViewState, + entity_paths: &IntSet, entity_properties: &mut EntityPropertyMap, ); diff --git a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs index 49aca554a320..9fe2045817ef 100644 --- a/crates/re_viewer_context/src/space_view/space_view_class_impl.rs +++ b/crates/re_viewer_context/src/space_view/space_view_class_impl.rs @@ -1,3 +1,4 @@ +use nohash_hasher::IntSet; use re_data_store::EntityPropertyMap; use re_log_types::EntityPath; @@ -62,6 +63,7 @@ pub trait SpaceViewClassImpl: std::marker::Sized { &self, _ctx: &mut ViewerContext<'_>, _state: &Self::SpaceViewState, + _entity_paths: &IntSet, _entity_properties: &mut re_data_store::EntityPropertyMap, ) { } @@ -131,10 +133,11 @@ impl SpaceViewClass for T { &self, ctx: &mut ViewerContext<'_>, state: &mut dyn SpaceViewState, + entity_paths: &IntSet, entity_properties: &mut EntityPropertyMap, ) { typed_state_wrapper_mut(state, |state| { - self.prepare_populate(ctx, state, entity_properties); + self.prepare_populate(ctx, state, entity_paths, entity_properties); }); } diff --git a/crates/re_viewport/src/space_view.rs b/crates/re_viewport/src/space_view.rs index dafb495df9d7..e4a50cd90c39 100644 --- a/crates/re_viewport/src/space_view.rs +++ b/crates/re_viewport/src/space_view.rs @@ -196,6 +196,7 @@ impl SpaceViewBlueprint { space_view_class.prepare_populate( ctx, view_state.state.as_mut(), + &self.data_blueprint.entity_paths().clone(), // Clone to workaround borrow checker. self.data_blueprint.data_blueprints_individual(), ); From 4ba818ceb84db168c2f7ad3238bfe96eb58f0f4f Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 18:58:32 +0200 Subject: [PATCH 12/15] fix bounding box for depth clouds --- crates/re_renderer/examples/depth_cloud.rs | 2 +- crates/re_renderer/src/renderer/depth_cloud.rs | 4 ++-- crates/re_space_view_spatial/src/scene/parts/images.rs | 4 ++-- crates/re_space_view_spatial/src/ui.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/re_renderer/examples/depth_cloud.rs b/crates/re_renderer/examples/depth_cloud.rs index f67ae6e50089..4d73f8b5369a 100644 --- a/crates/re_renderer/examples/depth_cloud.rs +++ b/crates/re_renderer/examples/depth_cloud.rs @@ -167,7 +167,7 @@ impl RenderDepthClouds { .. } = self; - let world_from_obj = glam::Mat4::from_scale(glam::Vec3::splat(*scale)); + let world_from_obj = glam::Affine3A::from_scale(glam::Vec3::splat(*scale)); let depth_cloud_draw_data = DepthCloudDrawData::new( re_ctx, diff --git a/crates/re_renderer/src/renderer/depth_cloud.rs b/crates/re_renderer/src/renderer/depth_cloud.rs index 14887326b9ac..3b2ea2bb6552 100644 --- a/crates/re_renderer/src/renderer/depth_cloud.rs +++ b/crates/re_renderer/src/renderer/depth_cloud.rs @@ -102,7 +102,7 @@ mod gpu_data { pub struct DepthCloud { /// The extrinsics of the camera used for the projection. - pub world_from_obj: glam::Mat4, + pub world_from_obj: glam::Affine3A, /// The intrinsics of the camera used for the projection. /// @@ -159,7 +159,7 @@ impl DepthCloud { for corner in corners { let depth = corner.z; let pos_in_obj = ((corner.truncate() - offset) * depth / focal_length).extend(depth); - let pos_in_world = self.world_from_obj.project_point3(pos_in_obj); + let pos_in_world = self.world_from_obj.transform_point3(pos_in_obj); bbox.extend(pos_in_world); } diff --git a/crates/re_space_view_spatial/src/scene/parts/images.rs b/crates/re_space_view_spatial/src/scene/parts/images.rs index 63f552c376b9..8f305386b3a8 100644 --- a/crates/re_space_view_spatial/src/scene/parts/images.rs +++ b/crates/re_space_view_spatial/src/scene/parts/images.rs @@ -235,7 +235,7 @@ impl ImagesPart { ) { Ok(cloud) => { self.data - .extend_bounding_box(cloud.bbox(), ent_context.world_from_obj); + .extend_bounding_box(cloud.bbox(), cloud.world_from_obj); self.depth_cloud_entities.insert(ent_path.hash()); depth_clouds.push(cloud); return Ok(()); @@ -395,7 +395,7 @@ impl ImagesPart { }; Ok(DepthCloud { - world_from_obj: world_from_obj.into(), + world_from_obj, depth_camera_intrinsics: intrinsics.image_from_cam.into(), world_depth_from_texture_depth, point_radius_from_world_depth, diff --git a/crates/re_space_view_spatial/src/ui.rs b/crates/re_space_view_spatial/src/ui.rs index 6aa97a8caca6..d1faf3a76f50 100644 --- a/crates/re_space_view_spatial/src/ui.rs +++ b/crates/re_space_view_spatial/src/ui.rs @@ -138,8 +138,8 @@ impl SpatialSpaceViewState { re_tracing::profile_function!(); for entity_path in entity_paths { - self.update_pinhole_property_heuristics(ctx, &entity_path, entity_properties); - self.update_depth_cloud_property_heuristics(ctx, &entity_path, entity_properties); + self.update_pinhole_property_heuristics(ctx, entity_path, entity_properties); + self.update_depth_cloud_property_heuristics(ctx, entity_path, entity_properties); } } From 7a5d7a63b162c7b519c72ee4c3cdf4f113310b1a Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Mon, 5 Jun 2023 19:07:57 +0200 Subject: [PATCH 13/15] lint fix --- crates/re_space_view_spatial/src/scene/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/re_space_view_spatial/src/scene/mod.rs b/crates/re_space_view_spatial/src/scene/mod.rs index 63bd4fe4d629..9858e306e4ad 100644 --- a/crates/re_space_view_spatial/src/scene/mod.rs +++ b/crates/re_space_view_spatial/src/scene/mod.rs @@ -44,7 +44,10 @@ pub struct UiLabel { pub labeled_instance: InstancePathHash, } +/// Type alias for spatial scenes. pub type SceneSpatial = TypedScene; + +/// Collection of keypoints for annotation context. pub type Keypoints = HashMap<(ClassId, i64), HashMap>; /// Heuristic whether the default way of looking at this scene should be 2d or 3d. From 34cc532f8b4fec3a09145f048f2a7d6c12d59c48 Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 7 Jun 2023 09:06:30 +0200 Subject: [PATCH 14/15] rename to UnreachableTransformReason --- crates/re_space_view/src/lib.rs | 4 ++-- ...ransform.rs => unreachable_transform_reason.rs} | 4 ++-- .../src/scene/contexts/transform_context.rs | 12 ++++++------ crates/re_viewport/src/space_info.rs | 14 +++++++------- 4 files changed, 17 insertions(+), 17 deletions(-) rename crates/re_space_view/src/{unreachable_transform.rs => unreachable_transform_reason.rs} (93%) diff --git a/crates/re_space_view/src/lib.rs b/crates/re_space_view/src/lib.rs index e77cd19e4eeb..fbbc98031fbc 100644 --- a/crates/re_space_view/src/lib.rs +++ b/crates/re_space_view/src/lib.rs @@ -7,10 +7,10 @@ mod data_blueprint; mod empty_scene_context; mod empty_space_view_state; mod screenshot; -mod unreachable_transform; +mod unreachable_transform_reason; pub use data_blueprint::{DataBlueprintGroup, DataBlueprintTree}; pub use empty_scene_context::EmptySceneContext; pub use empty_space_view_state::EmptySpaceViewState; pub use screenshot::ScreenshotMode; -pub use unreachable_transform::UnreachableTransform; +pub use unreachable_transform_reason::UnreachableTransformReason; diff --git a/crates/re_space_view/src/unreachable_transform.rs b/crates/re_space_view/src/unreachable_transform_reason.rs similarity index 93% rename from crates/re_space_view/src/unreachable_transform.rs rename to crates/re_space_view/src/unreachable_transform_reason.rs index 4e8ac34dfcb2..0557520754fb 100644 --- a/crates/re_space_view/src/unreachable_transform.rs +++ b/crates/re_space_view/src/unreachable_transform_reason.rs @@ -1,5 +1,5 @@ #[derive(Clone, Copy)] -pub enum UnreachableTransform { +pub enum UnreachableTransformReason { /// `SpaceInfoCollection` is outdated and can't find a corresponding space info for the given path. /// /// If at all, this should only happen for a single frame until space infos are rebuilt. @@ -15,7 +15,7 @@ pub enum UnreachableTransform { DisconnectedSpace, } -impl std::fmt::Display for UnreachableTransform { +impl std::fmt::Display for UnreachableTransformReason { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_str(match self { Self::UnknownSpaceInfo => diff --git a/crates/re_space_view_spatial/src/scene/contexts/transform_context.rs b/crates/re_space_view_spatial/src/scene/contexts/transform_context.rs index ed2931adcc3c..6ada0456a3a2 100644 --- a/crates/re_space_view_spatial/src/scene/contexts/transform_context.rs +++ b/crates/re_space_view_spatial/src/scene/contexts/transform_context.rs @@ -4,7 +4,7 @@ use re_arrow_store::LatestAtQuery; use re_components::{DisconnectedSpace, Pinhole, Transform3D}; use re_data_store::{EntityPath, EntityPropertyMap, EntityTree}; use re_log_types::Component; -use re_space_view::UnreachableTransform; +use re_space_view::UnreachableTransformReason; use re_viewer_context::{ArchetypeDefinition, SceneContextPart}; #[derive(Clone)] @@ -35,10 +35,10 @@ pub struct TransformContext { transform_per_entity: IntMap, /// All unreachable descendant paths of `reference_path`. - unreachable_descendants: Vec<(EntityPath, UnreachableTransform)>, + unreachable_descendants: Vec<(EntityPath, UnreachableTransformReason)>, /// The first parent of reference_path that is no longer reachable. - first_unreachable_parent: Option<(EntityPath, UnreachableTransform)>, + first_unreachable_parent: Option<(EntityPath, UnreachableTransformReason)>, } impl Default for TransformContext { @@ -238,11 +238,11 @@ fn transform_at( query: &LatestAtQuery, pinhole_image_plane_distance: impl Fn(&EntityPath) -> f32, encountered_pinhole: &mut Option, -) -> Result, UnreachableTransform> { +) -> Result, UnreachableTransformReason> { let pinhole = store.query_latest_component::(entity_path, query); if pinhole.is_some() { if encountered_pinhole.is_some() { - return Err(UnreachableTransform::NestedPinholeCameras); + return Err(UnreachableTransformReason::NestedPinholeCameras); } else { *encountered_pinhole = Some(entity_path.clone()); } @@ -291,7 +291,7 @@ fn transform_at( .query_latest_component::(entity_path, query) .is_some() { - Err(UnreachableTransform::DisconnectedSpace) + Err(UnreachableTransformReason::DisconnectedSpace) } else { Ok(None) } diff --git a/crates/re_viewport/src/space_info.rs b/crates/re_viewport/src/space_info.rs index df0e03bc3773..5d1032f624b1 100644 --- a/crates/re_viewport/src/space_info.rs +++ b/crates/re_viewport/src/space_info.rs @@ -1,5 +1,5 @@ use nohash_hasher::IntSet; -use re_space_view::UnreachableTransform; +use re_space_view::UnreachableTransformReason; use std::collections::BTreeMap; use re_arrow_store::{LatestAtQuery, TimeInt, Timeline}; @@ -228,7 +228,7 @@ impl SpaceInfoCollection { &self, from: &EntityPath, to_reference: &EntityPath, - ) -> Result<(), UnreachableTransform> { + ) -> Result<(), UnreachableTransformReason> { re_tracing::profile_function!(); // Get closest space infos for the given entity paths. @@ -257,18 +257,18 @@ impl SpaceInfoCollection { // Matches the connectedness requirements in `inverse_transform_at`/`transform_at` in `transform_cache.rs` match connection { SpaceInfoConnection::Disconnected => { - Err(UnreachableTransform::DisconnectedSpace) + Err(UnreachableTransformReason::DisconnectedSpace) } SpaceInfoConnection::Connected { pinhole: Some(pinhole), .. } => { if encountered_pinhole { - Err(UnreachableTransform::NestedPinholeCameras) + Err(UnreachableTransformReason::NestedPinholeCameras) } else { encountered_pinhole = true; if pinhole.resolution.is_none() && !walk_up_from { - Err(UnreachableTransform::InversePinholeCameraWithoutResolution) + Err(UnreachableTransformReason::InversePinholeCameraWithoutResolution) } else { Ok(()) } @@ -280,7 +280,7 @@ impl SpaceInfoCollection { let Some(parent_space) = self.spaces.get(parent_path) else { re_log::warn_once!("{} not part of space infos", parent_path); - return Err(UnreachableTransform::UnknownSpaceInfo); + return Err(UnreachableTransformReason::UnknownSpaceInfo); }; if walk_up_from { @@ -294,7 +294,7 @@ impl SpaceInfoCollection { from, to_reference ); - return Err(UnreachableTransform::UnknownSpaceInfo); + return Err(UnreachableTransformReason::UnknownSpaceInfo); } } From c9127f54eff92802c26496c8f486b78959343b8c Mon Sep 17 00:00:00 2001 From: Andreas Reich Date: Wed, 7 Jun 2023 09:13:55 +0200 Subject: [PATCH 15/15] todo comment fixes --- .../src/scene/contexts/non_interactive_entities.rs | 2 ++ crates/re_space_view_spatial/src/ui_3d.rs | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs b/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs index bfe3a16e9f46..3550f36217a2 100644 --- a/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs +++ b/crates/re_space_view_spatial/src/scene/contexts/non_interactive_entities.rs @@ -3,6 +3,8 @@ use re_log_types::EntityPathHash; use re_viewer_context::SceneContextPart; /// List of all non-interactive entities for lookup during picking evaluation. +/// +/// TODO(wumpf/jleibs): This is a temporary solution until the picking code can query propagated blueprint properties directly. #[derive(Default)] pub struct NonInteractiveEntities(pub IntSet); diff --git a/crates/re_space_view_spatial/src/ui_3d.rs b/crates/re_space_view_spatial/src/ui_3d.rs index 90eebfc691f6..8fafd88f4104 100644 --- a/crates/re_space_view_spatial/src/ui_3d.rs +++ b/crates/re_space_view_spatial/src/ui_3d.rs @@ -515,7 +515,6 @@ pub fn view_3d( } } - // TODO(wumpf): Temporary manual insertion of drawdata. The SpaceViewClass framework will take this over. for draw_data in scene.draw_data.drain(..) { view_builder.queue_draw(draw_data); }