1use bevy_app::{Plugin, PostUpdate};
4use bevy_camera::{primitives::Aabb, visibility::ViewVisibility};
5use bevy_color::Color;
6use bevy_ecs::{
7 component::Component,
8 entity::Entity,
9 query::Without,
10 reflect::ReflectComponent,
11 schedule::IntoScheduleConfigs,
12 system::{Query, Res},
13};
14use bevy_reflect::{std_traits::ReflectDefault, Reflect};
15use bevy_transform::{components::GlobalTransform, TransformSystems};
16
17use crate::{
18 color_from_entity,
19 config::{GizmoConfigGroup, GizmoConfigStore},
20 gizmos::Gizmos,
21 AppGizmoBuilder,
22};
23
24pub struct AabbGizmoPlugin;
26
27impl Plugin for AabbGizmoPlugin {
28 fn build(&self, app: &mut bevy_app::App) {
29 app.init_gizmo_group::<AabbGizmoConfigGroup>().add_systems(
30 PostUpdate,
31 (
32 draw_aabbs,
33 draw_all_aabbs.run_if(|config: Res<GizmoConfigStore>| {
34 config.config::<AabbGizmoConfigGroup>().1.draw_all
35 }),
36 )
37 .after(bevy_camera::visibility::VisibilitySystems::MarkNewlyHiddenEntitiesInvisible)
38 .after(TransformSystems::Propagate),
39 );
40 }
41}
42#[derive(Clone, Default, Reflect, GizmoConfigGroup)]
44#[reflect(Clone, Default)]
45pub struct AabbGizmoConfigGroup {
46 pub draw_all: bool,
52 pub default_color: Option<Color>,
58}
59
60#[derive(Component, Reflect, Default, Debug)]
62#[reflect(Component, Default, Debug)]
63pub struct ShowAabbGizmo {
64 pub color: Option<Color>,
68}
69
70fn draw_aabbs(
71 query: Query<(
72 Entity,
73 &Aabb,
74 &GlobalTransform,
75 Option<&ViewVisibility>,
76 &ShowAabbGizmo,
77 )>,
78 mut gizmos: Gizmos<AabbGizmoConfigGroup>,
79) {
80 for (entity, &aabb, &transform, view_visibility, gizmo) in &query {
81 if !is_visible(view_visibility) {
82 continue;
83 }
84
85 let color = gizmo
86 .color
87 .or(gizmos.config_ext.default_color)
88 .unwrap_or_else(|| color_from_entity(entity));
89 gizmos.aabb_3d(aabb, transform, color);
90 }
91}
92
93fn draw_all_aabbs(
94 query: Query<
95 (Entity, &Aabb, &GlobalTransform, Option<&ViewVisibility>),
96 Without<ShowAabbGizmo>,
97 >,
98 mut gizmos: Gizmos<AabbGizmoConfigGroup>,
99) {
100 for (entity, &aabb, &transform, view_visibility) in &query {
101 if !is_visible(view_visibility) {
102 continue;
103 }
104
105 let color = gizmos
106 .config_ext
107 .default_color
108 .unwrap_or_else(|| color_from_entity(entity));
109 gizmos.aabb_3d(aabb, transform, color);
110 }
111}
112
113fn is_visible(view_visibility: Option<&ViewVisibility>) -> bool {
114 view_visibility.is_some_and(|v| v.get())
115}