use bevy_app::{Plugin, PostUpdate};
use bevy_camera::{primitives::Frustum, visibility::VisibilitySystems};
use bevy_color::Color;
use bevy_ecs::{
component::Component,
entity::Entity,
query::Without,
reflect::ReflectComponent,
schedule::{IntoScheduleConfigs, SystemSet},
system::{Query, Res},
};
use bevy_reflect::{std_traits::ReflectDefault, Reflect, ReflectFromReflect};
use crate::{
color_from_entity,
config::{GizmoConfigGroup, GizmoConfigStore},
gizmos::Gizmos,
AppGizmoBuilder,
};
pub struct FrustumGizmoPlugin;
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
pub struct FrustumGizmoSystems;
impl Plugin for FrustumGizmoPlugin {
fn build(&self, app: &mut bevy_app::App) {
app.init_gizmo_group::<FrustumGizmoConfigGroup>()
.add_systems(
PostUpdate,
(
draw_frustum_gizmos,
draw_all_frustum_gizmos.run_if(|config: Res<GizmoConfigStore>| {
config.config::<FrustumGizmoConfigGroup>().1.draw_all
}),
)
.in_set(FrustumGizmoSystems)
.after(VisibilitySystems::UpdateFrusta),
);
}
}
#[derive(Clone, Default, Reflect, GizmoConfigGroup)]
#[reflect(Clone, Default)]
pub struct FrustumGizmoConfigGroup {
pub draw_all: bool,
pub default_color: Option<Color>,
}
#[derive(Component, Reflect, Default, Debug)]
#[reflect(Component, FromReflect, Default)]
pub struct ShowFrustumGizmo {
pub color: Option<Color>,
}
fn draw_frustum_gizmos(
query: Query<(Entity, &Frustum, &ShowFrustumGizmo)>,
mut gizmos: Gizmos<FrustumGizmoConfigGroup>,
) {
for (entity, &frustum, gizmo) in &query {
let color = gizmo
.color
.or(gizmos.config_ext.default_color)
.unwrap_or_else(|| color_from_entity(entity));
frustum_inner(&frustum, color, &mut gizmos);
}
}
fn draw_all_frustum_gizmos(
query: Query<(Entity, &Frustum), Without<ShowFrustumGizmo>>,
mut gizmos: Gizmos<FrustumGizmoConfigGroup>,
) {
for (entity, &frustum) in &query {
let color = gizmos
.config_ext
.default_color
.unwrap_or_else(|| color_from_entity(entity));
frustum_inner(&frustum, color, &mut gizmos);
}
}
fn frustum_inner(frustum: &Frustum, color: Color, gizmos: &mut Gizmos<FrustumGizmoConfigGroup>) {
let Some([tln, trn, brn, bln, tlf, trf, brf, blf]) = frustum.corners() else {
return;
};
gizmos.linestrip(
[
tln, trn, brn, bln, tln, tlf, trf, brf, blf, tlf, ],
color,
);
gizmos.line(trn, trf, color); gizmos.line(brn, brf, color); gizmos.line(bln, blf, color); }