use bevy_app::{Plugin, PostUpdate};
use bevy_camera::{primitives::Aabb, visibility::ViewVisibility};
use bevy_color::Color;
use bevy_ecs::{
component::Component,
entity::Entity,
query::Without,
reflect::ReflectComponent,
schedule::IntoScheduleConfigs,
system::{Query, Res},
};
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_transform::{components::GlobalTransform, TransformSystems};
use crate::{
color_from_entity,
config::{GizmoConfigGroup, GizmoConfigStore},
gizmos::Gizmos,
AppGizmoBuilder,
};
pub struct AabbGizmoPlugin;
impl Plugin for AabbGizmoPlugin {
fn build(&self, app: &mut bevy_app::App) {
app.init_gizmo_group::<AabbGizmoConfigGroup>().add_systems(
PostUpdate,
(
draw_aabbs,
draw_all_aabbs.run_if(|config: Res<GizmoConfigStore>| {
config.config::<AabbGizmoConfigGroup>().1.draw_all
}),
)
.after(bevy_camera::visibility::VisibilitySystems::MarkNewlyHiddenEntitiesInvisible)
.after(TransformSystems::Propagate),
);
}
}
#[derive(Clone, Default, Reflect, GizmoConfigGroup)]
#[reflect(Clone, Default)]
pub struct AabbGizmoConfigGroup {
pub draw_all: bool,
pub default_color: Option<Color>,
}
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component, Default, Debug)]
pub struct ShowAabbGizmo {
pub color: Option<Color>,
}
fn draw_aabbs(
query: Query<(
Entity,
&Aabb,
&GlobalTransform,
Option<&ViewVisibility>,
&ShowAabbGizmo,
)>,
mut gizmos: Gizmos<AabbGizmoConfigGroup>,
) {
for (entity, &aabb, &transform, view_visibility, gizmo) in &query {
if !is_visible(view_visibility) {
continue;
}
let color = gizmo
.color
.or(gizmos.config_ext.default_color)
.unwrap_or_else(|| color_from_entity(entity));
gizmos.aabb_3d(aabb, transform, color);
}
}
fn draw_all_aabbs(
query: Query<
(Entity, &Aabb, &GlobalTransform, Option<&ViewVisibility>),
Without<ShowAabbGizmo>,
>,
mut gizmos: Gizmos<AabbGizmoConfigGroup>,
) {
for (entity, &aabb, &transform, view_visibility) in &query {
if !is_visible(view_visibility) {
continue;
}
let color = gizmos
.config_ext
.default_color
.unwrap_or_else(|| color_from_entity(entity));
gizmos.aabb_3d(aabb, transform, color);
}
}
fn is_visible(view_visibility: Option<&ViewVisibility>) -> bool {
view_visibility.is_some_and(|v| v.get())
}