1use bevy_app::{Plugin, PostUpdate};
4use bevy_camera::{primitives::Aabb, visibility::ViewVisibility};
5use bevy_color::{Color, Oklcha};
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 config::{GizmoConfigGroup, GizmoConfigStore},
19 gizmos::Gizmos,
20 AppGizmoBuilder,
21};
22
23pub struct AabbGizmoPlugin;
25
26impl Plugin for AabbGizmoPlugin {
27 fn build(&self, app: &mut bevy_app::App) {
28 app.init_gizmo_group::<AabbGizmoConfigGroup>().add_systems(
29 PostUpdate,
30 (
31 draw_aabbs,
32 draw_all_aabbs.run_if(|config: Res<GizmoConfigStore>| {
33 config.config::<AabbGizmoConfigGroup>().1.draw_all
34 }),
35 )
36 .after(bevy_camera::visibility::VisibilitySystems::MarkNewlyHiddenEntitiesInvisible)
37 .after(TransformSystems::Propagate),
38 );
39 }
40}
41#[derive(Clone, Default, Reflect, GizmoConfigGroup)]
43#[reflect(Clone, Default)]
44pub struct AabbGizmoConfigGroup {
45 pub draw_all: bool,
51 pub default_color: Option<Color>,
57}
58
59#[derive(Component, Reflect, Default, Debug)]
61#[reflect(Component, Default, Debug)]
62pub struct ShowAabbGizmo {
63 pub color: Option<Color>,
67}
68
69fn draw_aabbs(
70 query: Query<(
71 Entity,
72 &Aabb,
73 &GlobalTransform,
74 Option<&ViewVisibility>,
75 &ShowAabbGizmo,
76 )>,
77 mut gizmos: Gizmos<AabbGizmoConfigGroup>,
78) {
79 for (entity, &aabb, &transform, view_visibility, gizmo) in &query {
80 if !is_visible(view_visibility) {
81 continue;
82 }
83
84 let color = gizmo
85 .color
86 .or(gizmos.config_ext.default_color)
87 .unwrap_or_else(|| color_from_entity(entity));
88 gizmos.aabb_3d(aabb, transform, color);
89 }
90}
91
92fn draw_all_aabbs(
93 query: Query<
94 (Entity, &Aabb, &GlobalTransform, Option<&ViewVisibility>),
95 Without<ShowAabbGizmo>,
96 >,
97 mut gizmos: Gizmos<AabbGizmoConfigGroup>,
98) {
99 for (entity, &aabb, &transform, view_visibility) in &query {
100 if !is_visible(view_visibility) {
101 continue;
102 }
103
104 let color = gizmos
105 .config_ext
106 .default_color
107 .unwrap_or_else(|| color_from_entity(entity));
108 gizmos.aabb_3d(aabb, transform, color);
109 }
110}
111
112fn is_visible(view_visibility: Option<&ViewVisibility>) -> bool {
113 view_visibility.is_some_and(|v| v.get())
114}
115
116fn color_from_entity(entity: Entity) -> Color {
117 Oklcha::sequential_dispersed(entity.index_u32()).into()
118}