re_view_spatial 0.32.0

Views that show entities in a 2D or 3D spatial relationship.
Documentation
use re_sdk_types::Archetype as _;
use re_sdk_types::archetypes::Image;
use re_sdk_types::components::{ImageBuffer, ImageFormat, MagnificationFilter, Opacity};
use re_sdk_types::image::ImageKind;
use re_viewer_context::{
    IdentifiedViewSystem, ImageInfo, QueryContext, ViewClass as _, ViewContext,
    ViewContextCollection, ViewQuery, ViewSystemExecutionError, VisualizerExecutionOutput,
    VisualizerQueryInfo, VisualizerReportSeverity, VisualizerSystem, typed_fallback_for,
};

use super::SpatialViewVisualizerData;
use super::entity_iterator::process_archetype;
use crate::contexts::SpatialSceneVisualizerInstructionContext;
use crate::visualizers::{first_copied, textured_rect_from_image};
use crate::{PickableRectSourceData, PickableTexturedRect};

#[derive(Default)]
pub struct ImageVisualizer;

struct ImageComponentData {
    image: ImageInfo,
    opacity: Option<Opacity>,
    magnification_filter: MagnificationFilter,
}

impl IdentifiedViewSystem for ImageVisualizer {
    fn identifier() -> re_viewer_context::ViewSystemIdentifier {
        "Image".into()
    }
}

impl VisualizerSystem for ImageVisualizer {
    fn visualizer_query_info(
        &self,
        _app_options: &re_viewer_context::AppOptions,
    ) -> VisualizerQueryInfo {
        VisualizerQueryInfo::buffer_and_format::<ImageBuffer, ImageFormat>(
            &Image::descriptor_buffer(),
            &Image::descriptor_format(),
            &Image::all_components(),
        )
    }

    fn affinity(&self) -> Option<re_sdk_types::ViewClassIdentifier> {
        Some(crate::SpatialView2D::identifier())
    }

    fn execute(
        &self,
        ctx: &ViewContext<'_>,
        view_query: &ViewQuery<'_>,
        context_systems: &ViewContextCollection,
    ) -> Result<VisualizerExecutionOutput, ViewSystemExecutionError> {
        re_tracing::profile_function!();

        let mut data = SpatialViewVisualizerData::default();
        let output = VisualizerExecutionOutput::default();

        process_archetype::<Image, _, _>(
            ctx,
            view_query,
            context_systems,
            &output,
            self,
            |ctx, spatial_ctx, results| {
                Self::process_image(&mut data, ctx, results, spatial_ctx);
                Ok(())
            },
        )?;

        Ok(output
            .with_draw_data([PickableTexturedRect::to_draw_data(
                ctx.viewer_ctx.render_ctx(),
                &data.pickable_rects,
            )?])
            .with_visualizer_data(data))
    }
}

impl ImageVisualizer {
    fn process_image(
        data: &mut SpatialViewVisualizerData,
        ctx: &QueryContext<'_>,
        results: &re_view::VisualizerInstructionQueryResults<'_>,
        spatial_ctx: &SpatialSceneVisualizerInstructionContext<'_>,
    ) {
        re_tracing::profile_function!();

        let entity_path = ctx.target_entity_path;

        let all_buffers = results.iter_required(Image::descriptor_buffer().component);
        if all_buffers.is_empty() {
            return;
        }
        let all_formats = results.iter_required(Image::descriptor_format().component);
        if all_formats.is_empty() {
            return;
        }
        let all_opacities = results.iter_optional(Image::descriptor_opacity().component);
        let all_magnification_filters =
            results.iter_optional(Image::descriptor_magnification_filter().component);

        let image_data = re_query::range_zip_1x3(
            all_buffers.slice::<&[u8]>(),
            all_formats.component_slow::<ImageFormat>(),
            all_opacities.slice::<f32>(),
            all_magnification_filters.slice::<u8>(),
        )
        .filter_map(
            |((_time, row_id), buffers, formats, opacities, magnification_filters)| {
                let buffer = buffers.first()?;

                Some(ImageComponentData {
                    image: ImageInfo::from_stored_blob(
                        row_id,
                        Image::descriptor_buffer().component,
                        buffer.clone().into(),
                        first_copied(formats.as_deref())?.0,
                        ImageKind::Color,
                    ),
                    opacity: first_copied(opacities).map(Into::into),
                    magnification_filter: first_copied(magnification_filters)
                        .and_then(MagnificationFilter::from_u8)
                        .unwrap_or_default(),
                })
            },
        );

        for ImageComponentData {
            image,
            opacity,
            magnification_filter,
        } in image_data
        {
            let opacity = opacity
                .unwrap_or_else(|| typed_fallback_for(ctx, Image::descriptor_opacity().component));
            #[expect(clippy::disallowed_methods)] // This is not a hard-coded color.
            let multiplicative_tint =
                re_renderer::Rgba::from_white_alpha(opacity.0.clamp(0.0, 1.0));
            let colormap = None;

            match textured_rect_from_image(
                ctx.viewer_ctx(),
                entity_path,
                spatial_ctx,
                &image,
                colormap,
                multiplicative_tint,
                magnification_filter,
                Image::name(),
            ) {
                Ok(textured_rect) => {
                    data.add_pickable_rect(
                        PickableTexturedRect {
                            ent_path: entity_path.clone(),
                            textured_rect,
                            source_data: PickableRectSourceData::Image {
                                image,
                                depth_meter: None,
                            },
                        },
                        spatial_ctx.view_class_identifier,
                    );
                }
                Err(err) => {
                    results.report_for_component(
                        Image::descriptor_buffer().component,
                        VisualizerReportSeverity::Error,
                        re_error::format(err),
                    );
                }
            }
        }
    }
}