Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Configurations for Gizmos #10342

Merged
merged 38 commits into from
Jan 18, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
b9281b3
allow for multiple gizmo configs
jeliag Oct 11, 2023
a750293
improved examples & renamed types
jeliag Oct 11, 2023
8c1232c
return early if gizmos are disabled
jeliag Oct 11, 2023
24b937d
cargo fmt
jeliag Oct 11, 2023
bc3e45b
store gizmo configs in a central resource
jeliag Oct 12, 2023
1b4e077
fix import
jeliag Oct 12, 2023
326947a
clean up
jeliag Oct 12, 2023
f2b0966
remove RenderPlugin settings example
jeliag Oct 12, 2023
a511fb9
fix prelude
jeliag Oct 12, 2023
6654177
fix examples
jeliag Oct 12, 2023
71d1b80
unify GizmoConfig and CustomGizmoConfig storage
jeliag Oct 12, 2023
76e7fb6
fix comments
jeliag Oct 12, 2023
1f41f4c
fix system param impl
jeliag Oct 12, 2023
a87b3d4
improve examples
jeliag Oct 12, 2023
9b5e6b6
remove old derive
jeliag Oct 12, 2023
08938fb
improve examples
jeliag Oct 28, 2023
4adff6b
improve config store api and remove unsafe
jeliag Nov 2, 2023
ed1ca6e
make config available through gizmos system param
jeliag Nov 2, 2023
77c29ef
cargo fmt & fix doc
jeliag Nov 2, 2023
a82fb30
Merge branch 'main' into gizmo-multiconfig-store
jeliag Nov 6, 2023
299d94c
fix trait bounds & derives
jeliag Nov 6, 2023
1294aa9
remove explicit generic parameter
jeliag Nov 6, 2023
bc48e75
use type id instead of type path as key
jeliag Nov 6, 2023
6df43d0
clean gizmos impl & remove indirection
jeliag Nov 6, 2023
1b32086
fix typo
jeliag Nov 6, 2023
9c676a8
add GizmoMeshConfig
jeliag Nov 11, 2023
c6b3724
Merge branch 'main' into gizmo-multiconfig-store
jeliag Nov 13, 2023
8b0ba05
move aabb gizmos to a separate plugin
jeliag Nov 13, 2023
9804ec9
adding derive macro for GizmoConfigGroup
jeliag Nov 19, 2023
0fa12b8
Merge branch 'main' into gizmo-multiconfig-store
jeliag Nov 19, 2023
2ff66cf
fix doc links
jeliag Nov 19, 2023
cdbedc5
fix generics in doc link
jeliag Nov 19, 2023
0b75397
Merge branch 'main' into gizmo-multiconfig-store
jeliag Nov 22, 2023
7a463dd
renamed to AabbGizmoConfigGroup
jeliag Nov 22, 2023
c3f7e88
fix doc links
jeliag Nov 22, 2023
f9cc35b
add missing safety comments
jeliag Nov 23, 2023
694b7c5
rename config getters
jeliag Nov 23, 2023
c61e1eb
Merge branch 'main' into gizmo-multiconfig-store
jeliag Jan 18, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
161 changes: 161 additions & 0 deletions crates/bevy_gizmos/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
//! A module for the [`GizmoConfig<T>`] [`Resource`].

use core::panic;
use std::{
any::Any,
ops::{Deref, DerefMut},
};

use bevy_ecs::{component::Component, system::Resource};
use bevy_reflect::{Reflect, TypePath};
use bevy_render::{color::Color, view::RenderLayers};
use bevy_utils::HashMap;

/// A trait used for custom gizmo configs.
///
/// Here you can store additional configuration for you gizmos not covered by [`GizmoConfig`]
///
/// Make sure to derive [`Default`] + [`Reflect`], and register in the app using `app.init_gizmo_config::<T>()`
pub trait CustomGizmoConfig: 'static + Send + Sync + Any + Reflect + TypePath + Default {}
jeliag marked this conversation as resolved.
Show resolved Hide resolved
jeliag marked this conversation as resolved.
Show resolved Hide resolved

/// The default gizmo config.
#[derive(Default, Reflect)]
pub struct DefaultGizmoConfig;
impl CustomGizmoConfig for DefaultGizmoConfig {}
jeliag marked this conversation as resolved.
Show resolved Hide resolved

/// A [`Resource`] storing [`GizmoConfig`] and [`CustomGizmoConfig`] structs
///
/// Use `app.init_gizmo_config::<T>()` to register a custom config.
#[derive(Resource, Default)]
pub struct GizmoConfigStore {
// INVARIANT: store must map TypeId::of::<T>() to correct type T
jeliag marked this conversation as resolved.
Show resolved Hide resolved
store: HashMap<&'static str, (GizmoConfig, Box<dyn Reflect>)>,
jeliag marked this conversation as resolved.
Show resolved Hide resolved
}

impl GizmoConfigStore {
/// Returns [`GizmoConfig`] and `&dyn` [`CustomGizmoConfig`] associated with [`TypePath`] of a [`CustomGizmoConfig`]
pub fn get_dyn(&self, config_type_path: &str) -> (&GizmoConfig, &dyn Reflect) {
let Some((config, ext)) = self.store.get(config_type_path) else {
panic!("Requested config {} does not exist in `GizmoConfigStore`! Did you forget to add it using `app.init_gizmo_config<T>()`?", config_type_path);
};
(config, ext.deref())
}

/// Returns [`GizmoConfig`] and [`CustomGizmoConfig`] associated with a [`CustomGizmoConfig`] `T`
pub fn get<T: CustomGizmoConfig>(&self) -> (&GizmoConfig, &T) {
let (config, ext) = self.get_dyn(T::type_path());
// hash map invariant guarantees that `&dyn CustomGizmoConfig` is of correct type T
let ext = ext.as_any().downcast_ref().unwrap();
(config, ext)
}

/// Returns mutable [`GizmoConfig`] and `&dyn` [`CustomGizmoConfig`] associated with [`TypePath`] of a [`CustomGizmoConfig`]
pub fn get_mut_dyn(&mut self, config_type_path: &str) -> (&mut GizmoConfig, &mut dyn Reflect) {
let Some((config, ext)) = self.store.get_mut(config_type_path) else {
panic!("Requested config {} does not exist in `GizmoConfigStore`! Did you forget to add it using `app.init_gizmo_config<T>()`?", config_type_path);
};
(config, ext.deref_mut())
}

/// Returns mutable [`GizmoConfig`] and [`CustomGizmoConfig`] associated with a [`CustomGizmoConfig`] `T`
pub fn get_mut<T: CustomGizmoConfig>(&mut self) -> (&mut GizmoConfig, &mut T) {
let (config, ext) = self.get_mut_dyn(T::type_path());
// hash map invariant guarantees that `&dyn CustomGizmoConfig` is of correct type T
let ext = ext.as_any_mut().downcast_mut().unwrap();
(config, ext)
}

/// Returns an iterator over all [`GizmoConfig`]s.
pub fn iter(&self) -> impl Iterator<Item = (&str, &GizmoConfig, &dyn Reflect)> + '_ {
self.store
.iter()
.map(|(&id, (config, ext))| (id, config, ext.deref()))
}

/// Returns an iterator over all [`GizmoConfig`]s, by mutable reference.
pub fn iter_mut(
&mut self,
) -> impl Iterator<Item = (&str, &mut GizmoConfig, &mut dyn Reflect)> + '_ {
self.store
.iter_mut()
.map(|(&id, (config, ext))| (id, config, ext.deref_mut()))
}

/// Inserts [`GizmoConfig`] and [`CustomGizmoConfig`] replacing old values
pub fn insert<T: CustomGizmoConfig>(&mut self, config: GizmoConfig, ext_config: T) {
// INVARIANT: hash map must only map TypeId::of::<T>() to Box<T>
self.store
.insert(T::type_path(), (config, Box::new(ext_config)));
}

pub(crate) fn regsiter<T: CustomGizmoConfig>(&mut self) {
jeliag marked this conversation as resolved.
Show resolved Hide resolved
self.insert::<T>(GizmoConfig::default(), T::default());
jeliag marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// A struct that stores configuration for gizmos.
#[derive(Component, Clone)]
pub struct GizmoConfig {
/// Set to `false` to stop drawing gizmos.
///
/// Defaults to `true`.
pub enabled: bool,
/// Line width specified in pixels.
///
/// If `line_perspective` is `true` then this is the size in pixels at the camera's near plane.
///
/// Defaults to `2.0`.
pub line_width: f32,
/// Apply perspective to gizmo lines.
///
/// This setting only affects 3D, non-orthographic cameras.
///
/// Defaults to `false`.
pub line_perspective: bool,
/// How closer to the camera than real geometry the line should be.
///
/// Value between -1 and 1 (inclusive).
/// * 0 means that there is no change to the line position when rendering
/// * 1 means it is furthest away from camera as possible
/// * -1 means that it will always render in front of other things.
///
/// This is typically useful if you are drawing wireframes on top of polygons
/// and your wireframe is z-fighting (flickering on/off) with your main model.
/// You would set this value to a negative number close to 0.0.
pub depth_bias: f32,
/// Describes which rendering layers gizmos will be rendered to.
///
/// Gizmos will only be rendered to cameras with intersecting layers.
pub render_layers: RenderLayers,
}

impl Default for GizmoConfig {
fn default() -> Self {
Self {
enabled: true,
line_width: 2.,
line_perspective: false,
depth_bias: 0.,
render_layers: Default::default(),
}
}
}

/// Configuration for drawing the [Aabb](bevy_render::primitives::Aabb) component on entities.
#[derive(Default, Reflect)]
pub struct AabbGizmoConfig {
/// Draws all bounding boxes in the scene when set to `true`.
///
/// To draw a specific entity's bounding box, you can add the [ShowAabbGizmo](crate::ShowAabbGizmo) component.
///
/// Defaults to `false`.
pub draw_all: bool,
/// The default color for bounding box gizmos.
///
/// A random color is chosen per box if `None`.
///
/// Defaults to `None`.
pub default_color: Option<Color>,
}

impl CustomGizmoConfig for AabbGizmoConfig {}
Loading