use re_sdk_types::{archetypes, components, datatypes};
use re_viewer_context::{
ColormapWithRange, FallbackProviderRegistry, ImageInfo, ImageStatsCache, QueryContext,
TensorStats, TensorStatsAccessor, TensorStatsCache, VideoStreamCache,
auto_color_for_entity_path,
};
pub fn type_fallbacks(registry: &mut FallbackProviderRegistry) {
registry.register_type_fallback_provider::<components::Color>(|ctx| {
auto_color_for_entity_path(ctx.target_entity_path)
});
registry
.register_type_fallback_provider::<components::Opacity>(|_| components::Opacity::from(1.0));
registry.register_type_fallback_provider(|_| archetypes::Pinhole::DEFAULT_CAMERA_XYZ);
registry.register_type_fallback_provider(|ctx| {
re_viewer_context::resolution_of_image_at(
ctx.viewer_ctx(),
&ctx.query,
ctx.target_entity_path,
)
.unwrap_or_else(|| components::Resolution::from([0.0, 0.0]))
});
}
pub fn archetype_field_fallbacks(registry: &mut FallbackProviderRegistry) {
registry.register_component_fallback_provider(
archetypes::BarChart::descriptor_abscissa().component,
|ctx| {
if let Some(((_time, _row_id), tensor)) = ctx
.recording()
.latest_at_component::<components::TensorData>(
ctx.target_entity_path,
&ctx.query,
archetypes::BarChart::descriptor_values().component,
)
&& tensor.is_vector()
{
let shape = tensor.shape();
if let Some(&length) = shape.first() {
#[expect(clippy::cast_possible_wrap)]
let indices: Vec<i64> = (0..length as i64).collect();
let tensor_data = datatypes::TensorData::new(
vec![length],
datatypes::TensorBuffer::I64(indices.into()),
);
return components::TensorData(tensor_data);
}
}
let tensor_data =
datatypes::TensorData::new(vec![0u64], datatypes::TensorBuffer::I64(vec![].into()));
components::TensorData(tensor_data)
},
);
registry.register_component_fallback_provider(
archetypes::BarChart::descriptor_widths().component,
|_| components::Length::from(1.0),
);
registry.register_component_fallback_provider(
archetypes::GraphNodes::descriptor_show_labels().component,
|_| components::ShowLabels::from(true),
);
registry.register_component_fallback_provider(
archetypes::GraphNodes::descriptor_radii().component,
|_| components::Radius::from(4.0),
);
registry.register_component_fallback_provider(
archetypes::GeoLineStrings::descriptor_radii().component,
|_| components::Radius::new_ui_points(2.0),
);
registry.register_component_fallback_provider(
archetypes::GeoPoints::descriptor_radii().component,
|_| components::Radius::new_ui_points(5.0),
);
registry.register_component_fallback_provider(
archetypes::Arrows2D::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_LINES2D,
);
registry.register_component_fallback_provider(
archetypes::Arrows2D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Arrows2D::descriptor_vectors().component,
archetypes::Arrows2D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::LineStrips2D::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_LINES2D,
);
registry.register_component_fallback_provider(
archetypes::LineStrips2D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::LineStrips2D::descriptor_strips().component,
archetypes::LineStrips2D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::Points2D::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_LINES2D,
);
registry.register_component_fallback_provider(
archetypes::Points2D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Points2D::descriptor_positions().component,
archetypes::Points2D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::Arrows3D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Arrows3D::descriptor_vectors().component,
archetypes::Arrows3D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::LineStrips3D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::LineStrips3D::descriptor_strips().component,
archetypes::LineStrips3D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::Points3D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Points3D::descriptor_positions().component,
archetypes::Points3D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::Boxes2D::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_SHAPE_2D,
);
registry.register_component_fallback_provider(
archetypes::Boxes2D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Boxes2D::descriptor_half_sizes().component,
archetypes::Boxes2D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::Boxes3D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Boxes3D::descriptor_half_sizes().component,
archetypes::Boxes3D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::Capsules3D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Capsules3D::descriptor_radii().component,
archetypes::Capsules3D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::CoordinateFrame::descriptor_frame().component,
|ctx| components::TransformFrameId::from_entity_path(ctx.target_entity_path),
);
registry.register_component_fallback_provider(
archetypes::Cylinders3D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Cylinders3D::descriptor_radii().component,
archetypes::Cylinders3D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::Ellipses2D::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_SHAPE_2D,
);
registry.register_component_fallback_provider(
archetypes::Ellipses2D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Ellipses2D::descriptor_half_sizes().component,
archetypes::Ellipses2D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::Ellipsoids3D::descriptor_show_labels().component,
|ctx| {
show_labels_fallback(
ctx,
archetypes::Ellipsoids3D::descriptor_half_sizes().component,
archetypes::Ellipsoids3D::descriptor_labels().component,
)
},
);
registry.register_component_fallback_provider(
archetypes::DepthImage::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_DEPTH_IMAGE,
);
registry.register_component_fallback_provider(
archetypes::DepthImage::descriptor_colormap().component,
|_| ColormapWithRange::DEFAULT_DEPTH_COLORMAP,
);
registry.register_component_fallback_provider(
archetypes::DepthImage::descriptor_meter().component,
|ctx| {
let is_float_image = ctx
.recording()
.latest_at_component::<components::ImageFormat>(
ctx.target_entity_path,
&ctx.query,
archetypes::DepthImage::descriptor_format().component,
)
.is_some_and(|(_index, format)| format.is_float());
components::DepthMeter::from(if is_float_image { 1.0 } else { 1000.0 })
},
);
registry.register_component_fallback_provider(
archetypes::DepthImage::descriptor_depth_range().component,
|ctx| {
if let Some(((_time, buffer_row_id), image_buffer)) = ctx
.recording()
.latest_at_component::<components::ImageBuffer>(
ctx.target_entity_path,
&ctx.query,
archetypes::DepthImage::descriptor_buffer().component,
) {
if let Some((_, format)) = ctx
.recording()
.latest_at_component::<components::ImageFormat>(
ctx.target_entity_path,
&ctx.query,
archetypes::DepthImage::descriptor_format().component,
)
{
let image = ImageInfo::from_stored_blob(
buffer_row_id,
archetypes::DepthImage::descriptor_buffer().component,
image_buffer.0,
format.0,
re_sdk_types::image::ImageKind::Depth,
);
let cache = ctx.store_ctx().caches;
let image_stats =
cache.memoizer_read_or_compute::<ImageStatsCache, _, _>(&image);
let default_range =
ColormapWithRange::default_range_for_depth_images(&image_stats);
return [default_range[0] as f64, default_range[1] as f64].into();
}
}
components::ValueRange::from([0.0, f64::MAX])
},
);
registry.register_component_fallback_provider(
archetypes::EncodedDepthImage::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_DEPTH_IMAGE,
);
registry.register_component_fallback_provider(
archetypes::EncodedDepthImage::descriptor_colormap().component,
|_| ColormapWithRange::DEFAULT_DEPTH_COLORMAP,
);
registry.register_component_fallback_provider(
archetypes::EncodedDepthImage::descriptor_meter().component,
|_| components::DepthMeter::from(1000.0),
);
registry.register_component_fallback_provider(
archetypes::EncodedDepthImage::descriptor_depth_range().component,
|ctx| {
let blob_component = archetypes::EncodedDepthImage::descriptor_blob().component;
if ctx
.recording()
.latest_at_component::<components::Blob>(
ctx.target_entity_path,
&ctx.query,
blob_component,
)
.is_some()
{
let video = ctx.store_ctx().caches.memoizer(|c: &mut VideoStreamCache| {
c.entry(
ctx.recording(),
ctx.target_entity_path,
ctx.query.timeline(),
ctx.viewer_ctx().app_options().video_decoder_settings(),
blob_component,
&|| {
let media_type = ctx
.recording()
.latest_at_component::<components::MediaType>(
ctx.target_entity_path,
&ctx.query,
archetypes::EncodedDepthImage::descriptor_media_type()
.component,
)
.map(|(_, c)| c.to_string());
Ok(re_video::VideoCodec::ImageSequence(media_type))
},
)
});
if let Ok(video) = video
&& let Some(bit_depth) = video
.read_arc()
.video_descr()
.encoding_details
.as_ref()
.and_then(|d| d.bit_depth)
{
let max = (1u64 << bit_depth) - 1;
return [0.0, max as f64].into();
}
}
components::ValueRange::from([0.0, 65535.0])
},
);
registry.register_component_fallback_provider(
archetypes::EncodedImage::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_IMAGE,
);
registry.register_component_fallback_provider(
archetypes::Image::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_IMAGE,
);
registry.register_component_fallback_provider(
archetypes::GridMap::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_IMAGE,
);
registry.register_component_fallback_provider(
archetypes::GridMap::descriptor_cell_size().component,
|_| components::CellSize::from(0.01),
);
registry.register_component_fallback_provider(
archetypes::SegmentationImage::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_SEGMENTATION_IMAGE,
);
registry.register_component_fallback_provider(
archetypes::VideoFrameReference::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_VIDEO,
);
registry.register_component_fallback_provider(
archetypes::VideoStream::descriptor_draw_order().component,
|_| components::DrawOrder::DEFAULT_VIDEO,
);
registry.register_component_fallback_provider(
archetypes::Tensor::descriptor_value_range().component,
|ctx| {
if let Some(((_time, row_id), tensor)) = ctx
.recording()
.latest_at_component::<components::TensorData>(
ctx.target_entity_path,
&ctx.query,
archetypes::Tensor::descriptor_data().component,
)
{
let tensor_cache_key = re_log_types::hash::Hash64::hash(row_id);
let tensor_stats = ctx
.store_ctx()
.memoizer_read_or_compute::<TensorStatsCache, _, _>(&TensorStatsAccessor {
tensor_cache_key,
tensor: &tensor,
});
tensor_data_range_heuristic(&tensor_stats, tensor.dtype())
} else {
components::ValueRange::new(0.0, 1.0)
}
},
);
registry.register_component_fallback_provider(
archetypes::TextDocument::descriptor_media_type().component,
|_| components::MediaType::plain_text(),
);
registry.register_component_fallback_provider(
archetypes::Transform3D::descriptor_child_frame().component,
|ctx| components::TransformFrameId::from_entity_path(ctx.target_entity_path),
);
registry.register_component_fallback_provider(
archetypes::Transform3D::descriptor_parent_frame().component,
|ctx| {
components::TransformFrameId::from_entity_path(
&ctx.target_entity_path
.parent()
.unwrap_or_else(re_log_types::EntityPath::root),
)
},
);
registry.register_component_fallback_provider(
archetypes::Pinhole::descriptor_color().component,
|ctx| components::Color::from(ctx.viewer_ctx().tokens().frustum_color),
);
registry.register_component_fallback_provider(
archetypes::Pinhole::descriptor_line_width().component,
|_| components::Radius::new_ui_points(1.),
);
registry.register_component_fallback_provider(
archetypes::Pinhole::descriptor_child_frame().component,
|ctx| components::TransformFrameId::from_entity_path(ctx.target_entity_path),
);
registry.register_component_fallback_provider(
archetypes::Pinhole::descriptor_parent_frame().component,
|ctx| {
components::TransformFrameId::from_entity_path(
&ctx.target_entity_path
.parent()
.unwrap_or_else(re_log_types::EntityPath::root),
)
},
);
registry.register_component_fallback_provider(
archetypes::SeriesLines::descriptor_widths().component,
|_| components::StrokeWidth::from(0.75),
);
registry.register_component_fallback_provider(
archetypes::SeriesPoints::descriptor_marker_sizes().component,
|_| {
components::MarkerSize::from(3.0)
},
);
}
const MAX_NUM_LABELS_PER_ENTITY: usize = 30;
fn show_labels_fallback(
ctx: &QueryContext<'_>,
instance_count_component: re_sdk_types::ComponentIdentifier,
text_component: re_sdk_types::ComponentIdentifier,
) -> components::ShowLabels {
let results = ctx.recording().latest_at(
&ctx.query,
ctx.target_entity_path,
[instance_count_component, text_component],
);
let num_instances = results
.component_batch_raw(instance_count_component)
.map_or(0, |array| array.len());
let num_labels = results
.component_batch_raw(text_component)
.map_or(0, |array| array.len());
components::ShowLabels::from(num_labels == 1 || num_instances < MAX_NUM_LABELS_PER_ENTITY)
}
fn tensor_data_range_heuristic(
tensor_stats: &TensorStats,
data_type: re_sdk_types::tensor_data::TensorDataType,
) -> components::ValueRange {
let (min, max) = re_viewer_context::gpu_bridge::data_range_heuristic(
tensor_stats.finite_range,
data_type.is_float(),
);
components::ValueRange::new(min, max)
}