1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
//! Rerun Spatial Space Views
//!
//! Space Views that show entities in a 2D or 3D spatial relationship.

// TODO(#6330): remove unwrap()
#![allow(clippy::unwrap_used)]

mod contexts;
mod eye;
mod heuristics;
mod max_image_dimension_subscriber;
mod mesh_cache;
mod mesh_loader;
mod pickable_textured_rect;
mod picking;
mod picking_ui;
mod picking_ui_pixel;
mod proc_mesh;
mod scene_bounding_boxes;
mod space_camera_3d;
mod spatial_topology;
mod transform_component_tracker;
mod ui;
mod ui_2d;
mod ui_3d;
mod view_2d;
mod view_2d_properties;
mod view_3d;
mod view_3d_properties;
mod visualizers;

pub use view_2d::SpatialSpaceView2D;
pub use view_3d::SpatialSpaceView3D;

pub(crate) use pickable_textured_rect::{PickableRectSourceData, PickableTexturedRect};

// ---

use re_space_view::DataResultQuery as _;
use re_viewer_context::{ImageDecodeCache, ViewContext, ViewerContext};

use re_renderer::RenderContext;
use re_types::{
    archetypes,
    blueprint::components::BackgroundKind,
    components::{self, Color, ImageFormat, MediaType, Resolution},
    static_assert_struct_has_fields,
};
use re_viewport_blueprint::{ViewProperty, ViewPropertyQueryError};

mod view_kind {
    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
    pub enum SpatialSpaceViewKind {
        TwoD,
        ThreeD,
    }
}

fn resolution_of_image_at(
    ctx: &ViewerContext<'_>,
    query: &re_chunk_store::LatestAtQuery,
    entity_path: &re_log_types::EntityPath,
) -> Option<Resolution> {
    // First check assumptions:
    static_assert_struct_has_fields!(archetypes::Image, format: components::ImageFormat);
    static_assert_struct_has_fields!(archetypes::EncodedImage, blob: components::Blob);

    let db = ctx.recording();

    if let Some((_, image_format)) = db.latest_at_component::<ImageFormat>(entity_path, query) {
        // Normal `Image` archetype
        return Some(Resolution::from([
            image_format.width as f32,
            image_format.height as f32,
        ]));
    } else if let Some(((_time, row_id), blob)) =
        db.latest_at_component::<re_types::components::Blob>(entity_path, query)
    {
        // `archetypes.EncodedImage`

        let media_type = db
            .latest_at_component::<MediaType>(entity_path, query)
            .map(|(_, c)| c);

        let image = ctx
            .cache
            .entry(|c: &mut ImageDecodeCache| c.entry(row_id, &blob, media_type.as_ref()));

        if let Ok(image) = image {
            return Some(Resolution::from([
                image.format.width as f32,
                image.format.height as f32,
            ]));
        }
    }

    None
}

/// Utility for querying a pinhole archetype instance.
fn query_pinhole(
    ctx: &ViewContext<'_>,
    query: &re_chunk_store::LatestAtQuery,
    data_result: &re_viewer_context::DataResult,
) -> Option<re_types::archetypes::Pinhole> {
    let results = data_result
        .latest_at_with_blueprint_resolved_data::<re_types::archetypes::Pinhole>(ctx, query);

    let image_from_camera = results.get_mono()?;

    let resolution = results.get_mono().or_else(|| {
        // If the Pinhole has no resolution, use the resolution for the image logged at the same path.
        // See https://github.com/rerun-io/rerun/issues/3852
        resolution_of_image_at(ctx.viewer_ctx, query, &data_result.entity_path)
    });

    let camera_xyz = results.get_mono();

    let image_plane_distance = Some(results.get_mono_with_fallback());

    Some(re_types::archetypes::Pinhole {
        image_from_camera,
        resolution,
        camera_xyz,
        image_plane_distance,
    })
}

/// Deprecated utility for querying a pinhole archetype instance.
///
/// This function won't handle fallbacks correctly.
///
// TODO(andreas): This is duplicated into `re_viewport`
fn query_pinhole_legacy(
    ctx: &ViewerContext<'_>,
    query: &re_chunk_store::LatestAtQuery,
    entity_path: &re_log_types::EntityPath,
) -> Option<re_types::archetypes::Pinhole> {
    let entity_db = ctx.recording();
    entity_db
        .latest_at_component::<re_types::components::PinholeProjection>(entity_path, query)
        .map(
            |(_index, image_from_camera)| re_types::archetypes::Pinhole {
                image_from_camera,
                resolution: entity_db
                    .latest_at_component(entity_path, query)
                    .map(|(_index, c)| c)
                    .or_else(|| resolution_of_image_at(ctx, query, entity_path)),
                camera_xyz: entity_db
                    .latest_at_component(entity_path, query)
                    .map(|(_index, c)| c),
                image_plane_distance: None,
            },
        )
}

pub(crate) fn configure_background(
    ctx: &ViewerContext<'_>,
    background: &ViewProperty,
    render_ctx: &RenderContext,
    view_system: &dyn re_viewer_context::ComponentFallbackProvider,
    state: &dyn re_viewer_context::SpaceViewState,
) -> Result<(Option<re_renderer::QueueableDrawData>, re_renderer::Rgba), ViewPropertyQueryError> {
    use re_renderer::renderer;

    let kind: BackgroundKind = background.component_or_fallback(ctx, view_system, state)?;

    match kind {
        BackgroundKind::GradientDark => Ok((
            Some(
                renderer::GenericSkyboxDrawData::new(
                    render_ctx,
                    renderer::GenericSkyboxType::GradientDark,
                )
                .into(),
            ),
            re_renderer::Rgba::TRANSPARENT, // All zero is slightly faster to clear usually.
        )),

        BackgroundKind::GradientBright => Ok((
            Some(
                renderer::GenericSkyboxDrawData::new(
                    render_ctx,
                    renderer::GenericSkyboxType::GradientBright,
                )
                .into(),
            ),
            re_renderer::Rgba::TRANSPARENT, // All zero is slightly faster to clear usually.
        )),

        BackgroundKind::SolidColor => {
            let color: Color = background.component_or_fallback(ctx, view_system, state)?;
            Ok((None, color.into()))
        }
    }
}