1use bevy_app::{Plugin, PostUpdate};
4use bevy_camera::primitives::Aabb;
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::{
16 components::{GlobalTransform, Transform},
17 TransformSystems,
18};
19
20use crate::{
21 config::{GizmoConfigGroup, GizmoConfigStore},
22 gizmos::Gizmos,
23 AppGizmoBuilder,
24};
25
26pub struct AabbGizmoPlugin;
28
29impl Plugin for AabbGizmoPlugin {
30 fn build(&self, app: &mut bevy_app::App) {
31 app.init_gizmo_group::<AabbGizmoConfigGroup>().add_systems(
32 PostUpdate,
33 (
34 draw_aabbs,
35 draw_all_aabbs.run_if(|config: Res<GizmoConfigStore>| {
36 config.config::<AabbGizmoConfigGroup>().1.draw_all
37 }),
38 )
39 .after(bevy_camera::visibility::VisibilitySystems::CalculateBounds)
40 .after(TransformSystems::Propagate),
41 );
42 }
43}
44#[derive(Clone, Default, Reflect, GizmoConfigGroup)]
46#[reflect(Clone, Default)]
47pub struct AabbGizmoConfigGroup {
48 pub draw_all: bool,
54 pub default_color: Option<Color>,
60}
61
62#[derive(Component, Reflect, Default, Debug)]
64#[reflect(Component, Default, Debug)]
65pub struct ShowAabbGizmo {
66 pub color: Option<Color>,
70}
71
72fn draw_aabbs(
73 query: Query<(Entity, &Aabb, &GlobalTransform, &ShowAabbGizmo)>,
74 mut gizmos: Gizmos<AabbGizmoConfigGroup>,
75) {
76 for (entity, &aabb, &transform, gizmo) in &query {
77 let color = gizmo
78 .color
79 .or(gizmos.config_ext.default_color)
80 .unwrap_or_else(|| color_from_entity(entity));
81 gizmos.cuboid(aabb_transform(aabb, transform), color);
82 }
83}
84
85fn draw_all_aabbs(
86 query: Query<(Entity, &Aabb, &GlobalTransform), Without<ShowAabbGizmo>>,
87 mut gizmos: Gizmos<AabbGizmoConfigGroup>,
88) {
89 for (entity, &aabb, &transform) in &query {
90 let color = gizmos
91 .config_ext
92 .default_color
93 .unwrap_or_else(|| color_from_entity(entity));
94 gizmos.cuboid(aabb_transform(aabb, transform), color);
95 }
96}
97
98fn color_from_entity(entity: Entity) -> Color {
99 Oklcha::sequential_dispersed(entity.index()).into()
100}
101
102fn aabb_transform(aabb: Aabb, transform: GlobalTransform) -> GlobalTransform {
103 transform
104 * GlobalTransform::from(
105 Transform::from_translation(aabb.center.into())
106 .with_scale((aabb.half_extents * 2.).into()),
107 )
108}