use egui::Color32;
use re_data_store::EntityPath;
use re_log_types::{component_types::InstanceKey, EntityPathHash};
use re_renderer::{
renderer::{DepthClouds, MeshInstance},
LineStripSeriesBuilder, PointCloudBuilder,
};
use crate::misc::instance_hash_conversions::picking_layer_id_from_instance_path_hash;
use super::MeshSource;
pub struct SceneSpatialPrimitives {
pub(super) bounding_box: macaw::BoundingBox,
pub textured_rectangles_ids: Vec<EntityPathHash>,
pub textured_rectangles: Vec<re_renderer::renderer::TexturedRect>,
pub line_strips: LineStripSeriesBuilder,
pub points: PointCloudBuilder,
pub meshes: Vec<MeshSource>,
pub depth_clouds: DepthClouds,
pub any_outlines: bool,
}
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);
const SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES: f32 = 1.5;
const SIZE_BOOST_IN_POINTS_FOR_POINT_OUTLINES: f32 = 2.5;
impl SceneSpatialPrimitives {
pub fn new(re_ctx: &mut re_renderer::RenderContext) -> Self {
Self {
bounding_box: macaw::BoundingBox::nothing(),
textured_rectangles_ids: Default::default(),
textured_rectangles: Default::default(),
line_strips: LineStripSeriesBuilder::new(re_ctx)
.radius_boost_in_ui_points_for_outlines(SIZE_BOOST_IN_POINTS_FOR_LINE_OUTLINES),
points: PointCloudBuilder::new(re_ctx)
.radius_boost_in_ui_points_for_outlines(SIZE_BOOST_IN_POINTS_FOR_POINT_OUTLINES),
meshes: Default::default(),
depth_clouds: DepthClouds {
clouds: Default::default(),
radius_boost_in_ui_points_for_outlines: SIZE_BOOST_IN_POINTS_FOR_POINT_OUTLINES,
},
any_outlines: false,
}
}
pub fn bounding_box(&self) -> macaw::BoundingBox {
self.bounding_box
}
pub fn num_primitives(&self) -> usize {
let Self {
bounding_box: _,
textured_rectangles,
textured_rectangles_ids: _,
line_strips,
points,
meshes,
depth_clouds,
any_outlines: _,
} = &self;
textured_rectangles.len()
+ line_strips.vertices.len()
+ points.vertices.len()
+ meshes.len()
+ depth_clouds.clouds.len()
}
pub fn recalculate_bounding_box(&mut self) {
crate::profile_function!();
let Self {
bounding_box,
textured_rectangles_ids: _,
textured_rectangles,
line_strips,
points,
meshes,
depth_clouds,
any_outlines: _,
} = self;
*bounding_box = macaw::BoundingBox::nothing();
for rect in textured_rectangles {
bounding_box.extend(rect.top_left_corner_position);
bounding_box.extend(rect.top_left_corner_position + rect.extent_u);
bounding_box.extend(rect.top_left_corner_position + rect.extent_v);
bounding_box.extend(rect.top_left_corner_position + rect.extent_v + rect.extent_u);
}
for (batch, vertex_iter) in points.iter_vertices_by_batch() {
if let Some(transform) = macaw::IsoTransform::from_mat4(&batch.world_from_obj) {
let batch_bb = macaw::BoundingBox::from_points(vertex_iter.map(|v| v.position));
*bounding_box = bounding_box.union(batch_bb.transform_affine3(&transform.into()));
}
}
for (batch, vertex_iter) in line_strips.iter_vertices_by_batch() {
if let Some(transform) = macaw::IsoTransform::from_mat4(&batch.world_from_obj) {
let batch_bb = macaw::BoundingBox::from_points(vertex_iter.map(|v| v.position));
*bounding_box = bounding_box.union(batch_bb.transform_affine3(&transform.into()));
}
}
for mesh in meshes {
*bounding_box =
bounding_box.union(mesh.mesh.bbox().transform_affine3(&mesh.world_from_mesh));
}
for cloud in &depth_clouds.clouds {
*bounding_box = bounding_box.union(cloud.bbox());
}
}
pub fn mesh_instances(&self) -> Vec<MeshInstance> {
crate::profile_function!();
self.meshes
.iter()
.flat_map(|mesh| {
let (scale, rotation, translation) =
mesh.world_from_mesh.to_scale_rotation_translation();
let base_transform =
glam::Affine3A::from_scale_rotation_translation(scale, rotation, translation);
mesh.mesh
.mesh_instances
.iter()
.map(move |mesh_instance| MeshInstance {
gpu_mesh: mesh_instance.gpu_mesh.clone(),
world_from_mesh: base_transform * mesh_instance.world_from_mesh,
outline_mask_ids: mesh.outline_mask_ids,
picking_layer_id: picking_layer_id_from_instance_path_hash(
mesh.picking_instance_hash,
),
..Default::default()
})
})
.collect()
}
pub fn add_axis_lines(
&mut self,
transform: macaw::IsoTransform,
ent_path: Option<&EntityPath>,
axis_length: f32,
) {
use re_renderer::renderer::LineStripFlags;
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::CAP_END_TRIANGLE | LineStripFlags::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::CAP_END_TRIANGLE | LineStripFlags::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::CAP_END_TRIANGLE | LineStripFlags::CAP_START_ROUND)
.picking_instance_id(picking_instance_id);
}
}