use crate::{interaction::*, site::DrawingMarker};
use bevy::color::palettes::css as Colors;
use bevy::render::view::RenderLayers;
use bevy_mod_outline::{
ComputedOutline, OutlineMode, OutlineRenderLayers, OutlineStencil, OutlineVolume,
};
use rmf_site_camera::*;
use rmf_site_format::{
DoorType, FiducialMarker, FloorMarker, LiftCabin, LightKind, LocationTags, MeasurementMarker,
ModelMarker, PhysicalCameraProperties, PrimitiveShape, WallMarker,
};
use smallvec::SmallVec;
#[derive(Component)]
pub enum OutlineVisualization {
Ordinary,
Anchor { body: Entity },
}
impl Default for OutlineVisualization {
fn default() -> Self {
OutlineVisualization::Ordinary
}
}
impl OutlineVisualization {
pub fn color(&self, hovered: &Hovered, selected: &Selected) -> Option<Color> {
match self {
OutlineVisualization::Ordinary => {
if !hovered.cue() && !selected.cue() {
None
} else if hovered.cue() && selected.cue() {
Some(Color::srgb(1.0, 0.0, 0.3))
} else if selected.cue() {
Some(Color::srgb(1.0, 0.3, 1.0))
} else
{
Some(Colors::WHITE.into())
}
}
OutlineVisualization::Anchor { .. } => {
if hovered.is_hovered {
Some(Colors::WHITE.into())
} else {
Some(Colors::BLACK.into())
}
}
}
}
pub fn layers(
&self,
hovered: &Hovered,
selected: &Selected,
layer: Option<&RenderLayers>,
) -> OutlineRenderLayers {
match self {
OutlineVisualization::Ordinary => {
if hovered.cue() {
OutlineRenderLayers(RenderLayers::layer(HOVERED_OUTLINE_LAYER))
} else if selected.cue() {
OutlineRenderLayers(RenderLayers::layer(SELECTED_OUTLINE_LAYER))
} else {
OutlineRenderLayers(RenderLayers::none())
}
}
OutlineVisualization::Anchor { .. } => {
OutlineRenderLayers(layer.cloned().unwrap_or(RenderLayers::none()))
}
}
}
pub fn depth(&self) -> OutlineMode {
OutlineMode::ExtrudeFlat
}
pub fn root(&self) -> Option<Entity> {
match self {
OutlineVisualization::Ordinary => None,
OutlineVisualization::Anchor { body } => Some(*body),
}
}
}
#[derive(Component)]
pub struct SuppressOutline;
pub fn add_outline_visualization(
mut commands: Commands,
new_entities: Query<
Entity,
Or<(
Added<WallMarker>,
Added<DoorType>,
Added<LiftCabin<Entity>>,
Added<MeasurementMarker>,
Added<FiducialMarker>,
Added<FloorMarker>,
Added<DrawingMarker>,
Added<ModelMarker>,
Added<PhysicalCameraProperties>,
Added<LightKind>,
Added<LocationTags>,
Added<PrimitiveShape>,
)>,
>,
) {
for e in &new_entities {
commands
.entity(e)
.insert(OutlineVisualization::default())
.insert(Selectable::new(e));
}
}
pub fn update_outline_visualization(
mut commands: Commands,
outlinable: Query<
(
Entity,
&Hovered,
&Selected,
&OutlineVisualization,
Option<&SuppressOutline>,
Option<&RenderLayers>,
),
Or<(
Changed<Hovered>,
Changed<Selected>,
Changed<SuppressOutline>,
Changed<ComputedVisualCue>,
)>,
>,
descendants: Query<(Option<&Children>, Option<&ComputedVisualCue>)>,
) {
for (e, hovered, selected, vis, suppress, layer) in &outlinable {
let color = if suppress.is_some() {
None
} else {
vis.color(hovered, selected)
};
let layers = vis.layers(hovered, selected, layer);
let depth = vis.depth();
let root = vis.root().unwrap_or(e);
let mut queue: SmallVec<[Entity; 10]> = SmallVec::new();
queue.push(root);
while let Some(top) = queue.pop() {
if let Ok((children, cue)) = descendants.get(top) {
if let Some(cue) = cue {
if !cue.allow_outline {
continue;
}
}
if let Some(color) = color {
commands
.entity(top)
.insert((
OutlineVolume {
visible: true,
width: 3.0,
colour: color,
},
OutlineStencil::default(),
ComputedOutline::default(),
))
.insert(depth.clone())
.insert(layers.clone());
} else {
commands
.entity(top)
.remove::<OutlineVolume>()
.remove::<OutlineStencil>()
.remove::<ComputedOutline>()
.remove::<OutlineMode>()
.remove::<OutlineRenderLayers>();
}
if let Some(children) = children {
for child in children {
queue.push(*child);
}
}
}
}
}
}