1pub use bevy_gizmos_macros::GizmoConfigGroup;
4
5#[cfg(all(
6 feature = "bevy_render",
7 any(feature = "bevy_pbr", feature = "bevy_sprite")
8))]
9use {crate::GizmoAsset, bevy_asset::Handle, bevy_ecs::component::Component};
10
11use bevy_ecs::{reflect::ReflectResource, resource::Resource};
12use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath};
13use bevy_utils::TypeIdMap;
14use core::{
15 any::TypeId,
16 hash::Hash,
17 ops::{Deref, DerefMut},
18 panic,
19};
20
21#[derive(Debug, Default, Copy, Clone, Reflect, PartialEq, Eq, Hash)]
23#[reflect(Default, PartialEq, Hash, Clone)]
24pub enum GizmoLineJoint {
25 #[default]
27 None,
28 Miter,
30 Round(u32),
35 Bevel,
37}
38
39#[derive(Copy, Clone, Debug, Default, PartialEq, Reflect)]
41#[reflect(Default, PartialEq, Hash, Clone)]
42#[non_exhaustive]
43pub enum GizmoLineStyle {
44 #[default]
46 Solid,
47 Dotted,
49 Dashed {
51 gap_scale: f32,
53 line_scale: f32,
55 },
56}
57
58impl Eq for GizmoLineStyle {}
59
60impl Hash for GizmoLineStyle {
61 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
62 match self {
63 Self::Solid => {
64 0u64.hash(state);
65 }
66 Self::Dotted => 1u64.hash(state),
67 Self::Dashed {
68 gap_scale,
69 line_scale,
70 } => {
71 2u64.hash(state);
72 gap_scale.to_bits().hash(state);
73 line_scale.to_bits().hash(state);
74 }
75 }
76 }
77}
78
79pub trait GizmoConfigGroup: Reflect + TypePath + Default {}
85
86#[derive(Default, Reflect, GizmoConfigGroup)]
88#[reflect(Default)]
89pub struct DefaultGizmoConfigGroup;
90
91#[derive(Default, Reflect, GizmoConfigGroup, Debug, Clone)]
94#[reflect(Default, Clone)]
95pub struct ErasedGizmoConfigGroup;
96
97#[derive(Reflect, Resource, Default)]
101#[reflect(Resource, Default)]
102pub struct GizmoConfigStore {
103 #[reflect(ignore)]
105 store: TypeIdMap<(GizmoConfig, Box<dyn Reflect>)>,
106}
107
108impl GizmoConfigStore {
109 pub fn get_config_dyn(&self, config_type_id: &TypeId) -> Option<(&GizmoConfig, &dyn Reflect)> {
111 let (config, ext) = self.store.get(config_type_id)?;
112 Some((config, ext.deref()))
113 }
114
115 pub fn config<T: GizmoConfigGroup>(&self) -> (&GizmoConfig, &T) {
117 let Some((config, ext)) = self.get_config_dyn(&TypeId::of::<T>()) else {
118 panic!("Requested config {} does not exist in `GizmoConfigStore`! Did you forget to add it using `app.init_gizmo_group<T>()`?", T::type_path());
119 };
120 let ext = ext.as_any().downcast_ref().unwrap();
122 (config, ext)
123 }
124
125 pub fn get_config_mut_dyn(
127 &mut self,
128 config_type_id: &TypeId,
129 ) -> Option<(&mut GizmoConfig, &mut dyn Reflect)> {
130 let (config, ext) = self.store.get_mut(config_type_id)?;
131 Some((config, ext.deref_mut()))
132 }
133
134 pub fn config_mut<T: GizmoConfigGroup>(&mut self) -> (&mut GizmoConfig, &mut T) {
136 let Some((config, ext)) = self.get_config_mut_dyn(&TypeId::of::<T>()) else {
137 panic!("Requested config {} does not exist in `GizmoConfigStore`! Did you forget to add it using `app.init_gizmo_group<T>()`?", T::type_path());
138 };
139 let ext = ext.as_any_mut().downcast_mut().unwrap();
141 (config, ext)
142 }
143
144 pub fn iter(&self) -> impl Iterator<Item = (&TypeId, &GizmoConfig, &dyn Reflect)> + '_ {
146 self.store
147 .iter()
148 .map(|(id, (config, ext))| (id, config, ext.deref()))
149 }
150
151 pub fn iter_mut(
153 &mut self,
154 ) -> impl Iterator<Item = (&TypeId, &mut GizmoConfig, &mut dyn Reflect)> + '_ {
155 self.store
156 .iter_mut()
157 .map(|(id, (config, ext))| (id, config, ext.deref_mut()))
158 }
159
160 pub fn insert<T: GizmoConfigGroup>(&mut self, config: GizmoConfig, ext_config: T) {
162 self.store
164 .insert(TypeId::of::<T>(), (config, Box::new(ext_config)));
165 }
166
167 pub(crate) fn register<T: GizmoConfigGroup>(&mut self) {
168 self.insert(GizmoConfig::default(), T::default());
169 }
170}
171
172#[derive(Clone, Reflect, Debug)]
174#[reflect(Clone, Default)]
175pub struct GizmoConfig {
176 pub enabled: bool,
180 pub line: GizmoLineConfig,
182 pub depth_bias: f32,
195 #[cfg(feature = "bevy_render")]
199 pub render_layers: bevy_render::view::RenderLayers,
200}
201
202impl Default for GizmoConfig {
203 fn default() -> Self {
204 Self {
205 enabled: true,
206 line: Default::default(),
207 depth_bias: 0.,
208 #[cfg(feature = "bevy_render")]
209 render_layers: Default::default(),
210 }
211 }
212}
213
214#[derive(Clone, Reflect, Debug)]
216#[reflect(Clone, Default)]
217pub struct GizmoLineConfig {
218 pub width: f32,
224 pub perspective: bool,
230 pub style: GizmoLineStyle,
232 pub joints: GizmoLineJoint,
234}
235
236impl Default for GizmoLineConfig {
237 fn default() -> Self {
238 Self {
239 width: 2.,
240 perspective: false,
241 style: GizmoLineStyle::Solid,
242 joints: GizmoLineJoint::None,
243 }
244 }
245}
246
247#[cfg(all(
248 feature = "bevy_render",
249 any(feature = "bevy_pbr", feature = "bevy_sprite")
250))]
251#[derive(Component)]
252pub(crate) struct GizmoMeshConfig {
253 pub line_perspective: bool,
254 pub line_style: GizmoLineStyle,
255 pub line_joints: GizmoLineJoint,
256 pub render_layers: bevy_render::view::RenderLayers,
257 pub handle: Handle<GizmoAsset>,
258}