//! Module for the drawing of [`Frustum`]s.1//!2//! Camera entities are spawned with a [`Frustum`] component,3//! which describes a camera's field of vision. With this module,4//! a camera's frustum can be drawn with gizmos. This is useful5//! for debugging what a camera can see and what entities in the scene6//! will be subject to the camera's frustum culling, especially when7//! combined with drawing [`Aabb`](bevy_camera::primitives::Aabb)8//! [`gizmos`](crate::aabb).9//!10//! There are two ways to enable gizmo drawing of a [`Frustum`]:11//! 1) The [`ShowFrustumGizmo`] component can be added to individual camera12//! entities.13//! ```rust14//! # use bevy_gizmos::frustum::ShowFrustumGizmo;15//! # use bevy_camera::Camera2d;16//! # use bevy_ecs::system::Commands;17//! fn setup(mut commands: Commands) {18//! commands.spawn((Camera2d, ShowFrustumGizmo::default()));19//! }20//! ```21//! 2) Setting the [`FrustumGizmoConfigGroup`] configuration's `draw_all`22//! field to `true` will draw every frustum. Note that this will include23//! drawing `bevy_light` `SpotLight` [`Frustum`]s.24//! ```rust25//! # use bevy_ecs::prelude::*;26//! # use bevy_gizmos::prelude::*;27//! fn turn_on_frustum_gizmos(mut config: ResMut<GizmoConfigStore>) {28//! config.config_mut::<FrustumGizmoConfigGroup>().1.draw_all = true;29//! }30//! ```3132use bevy_app::{Plugin, PostUpdate};33use bevy_camera::{primitives::Frustum, visibility::VisibilitySystems};34use bevy_color::Color;35use bevy_ecs::{36component::Component,37entity::Entity,38query::Without,39reflect::ReflectComponent,40schedule::{IntoScheduleConfigs, SystemSet},41system::{Query, Res},42};43use bevy_reflect::{std_traits::ReflectDefault, Reflect, ReflectFromReflect};4445use crate::{46color_from_entity,47config::{GizmoConfigGroup, GizmoConfigStore},48gizmos::Gizmos,49AppGizmoBuilder,50};5152/// A [`Plugin`] that provides visualization of [`Frustum`]s for debugging.53pub struct FrustumGizmoPlugin;5455/// Frustum Gizmo system set. This exists in [`PostUpdate`].56#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]57pub struct FrustumGizmoSystems;5859impl Plugin for FrustumGizmoPlugin {60fn build(&self, app: &mut bevy_app::App) {61app.init_gizmo_group::<FrustumGizmoConfigGroup>()62.add_systems(63PostUpdate,64(65draw_frustum_gizmos,66draw_all_frustum_gizmos.run_if(|config: Res<GizmoConfigStore>| {67config.config::<FrustumGizmoConfigGroup>().1.draw_all68}),69)70.in_set(FrustumGizmoSystems)71.after(VisibilitySystems::UpdateFrusta),72);73}74}7576/// The [`GizmoConfigGroup`] used for debug visualizations of [`Frustum`] components on entities77#[derive(Clone, Default, Reflect, GizmoConfigGroup)]78#[reflect(Clone, Default)]79pub struct FrustumGizmoConfigGroup {80/// Draws all frusta in the scene when set to `true`.81///82/// To draw a specific entity's frustum, you can add the [`ShowFrustumGizmo`] component.83///84/// Defaults to `false`.85pub draw_all: bool,86/// The default color for frustum gizmos.87///88/// A random color is chosen per frustum if `None`.89///90/// Defaults to `None`.91pub default_color: Option<Color>,92}9394/// Add this [`Component`] to an entity to draw its [`Frustum`] component.95#[derive(Component, Reflect, Default, Debug)]96#[reflect(Component, FromReflect, Default)]97pub struct ShowFrustumGizmo {98/// The color of the frustum.99///100/// The default color from the [`FrustumGizmoConfigGroup`] resource is used if `None`,101pub color: Option<Color>,102}103104fn draw_frustum_gizmos(105query: Query<(Entity, &Frustum, &ShowFrustumGizmo)>,106mut gizmos: Gizmos<FrustumGizmoConfigGroup>,107) {108for (entity, &frustum, gizmo) in &query {109let color = gizmo110.color111.or(gizmos.config_ext.default_color)112.unwrap_or_else(|| color_from_entity(entity));113114frustum_inner(&frustum, color, &mut gizmos);115}116}117118fn draw_all_frustum_gizmos(119query: Query<(Entity, &Frustum), Without<ShowFrustumGizmo>>,120mut gizmos: Gizmos<FrustumGizmoConfigGroup>,121) {122for (entity, &frustum) in &query {123let color = gizmos124.config_ext125.default_color126.unwrap_or_else(|| color_from_entity(entity));127128frustum_inner(&frustum, color, &mut gizmos);129}130}131132fn frustum_inner(frustum: &Frustum, color: Color, gizmos: &mut Gizmos<FrustumGizmoConfigGroup>) {133let Some([tln, trn, brn, bln, tlf, trf, brf, blf]) = frustum.corners() else {134return;135};136137gizmos.linestrip(138[139tln, trn, brn, bln, // Near140tln, tlf, // Top Left Near to Far141trf, brf, blf, tlf, // Far142],143color,144);145gizmos.line(trn, trf, color); // Top Right Near to Far146gizmos.line(brn, brf, color); // Bottom Right Near to Far147gizmos.line(bln, blf, color); // Bottom Left Near to Far148}149150151