Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gizmos/src/config.rs
9435 views
1
//! A module for the [`GizmoConfig<T>`] [`Resource`].
2
3
use bevy_camera::visibility::RenderLayers;
4
pub use bevy_gizmos_macros::GizmoConfigGroup;
5
6
use {crate::GizmoAsset, bevy_asset::Handle, bevy_ecs::component::Component};
7
8
use bevy_ecs::{reflect::ReflectResource, resource::Resource};
9
use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath};
10
use bevy_utils::TypeIdMap;
11
use core::{
12
any::TypeId,
13
hash::Hash,
14
ops::{Deref, DerefMut},
15
panic,
16
};
17
18
/// An enum configuring how line joints will be drawn.
19
#[derive(Debug, Default, Copy, Clone, Reflect, PartialEq, Eq, Hash)]
20
#[reflect(Default, PartialEq, Hash, Clone)]
21
pub enum GizmoLineJoint {
22
/// Does not draw any line joints.
23
#[default]
24
None,
25
/// Extends both lines at the joining point until they meet in a sharp point.
26
Miter,
27
/// Draws a round corner with the specified resolution between the two lines.
28
///
29
/// The resolution determines the amount of triangles drawn per joint,
30
/// e.g. `GizmoLineJoint::Round(4)` will draw 4 triangles at each line joint.
31
Round(u32),
32
/// Draws a bevel, a straight line in this case, to connect the ends of both lines.
33
Bevel,
34
}
35
36
/// An enum used to configure the style of gizmo lines, similar to CSS line-style
37
#[derive(Copy, Clone, Debug, Default, PartialEq, Reflect)]
38
#[reflect(Default, PartialEq, Hash, Clone)]
39
#[non_exhaustive]
40
pub enum GizmoLineStyle {
41
/// A solid line without any decorators
42
#[default]
43
Solid,
44
/// A dotted line
45
Dotted,
46
/// A dashed line with configurable gap and line sizes
47
Dashed {
48
/// The length of the gap in `line_width`s
49
gap_scale: f32,
50
/// The length of the visible line in `line_width`s
51
line_scale: f32,
52
},
53
}
54
55
impl Eq for GizmoLineStyle {}
56
57
impl Hash for GizmoLineStyle {
58
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
59
match self {
60
Self::Solid => {
61
0u64.hash(state);
62
}
63
Self::Dotted => 1u64.hash(state),
64
Self::Dashed {
65
gap_scale,
66
line_scale,
67
} => {
68
2u64.hash(state);
69
gap_scale.to_bits().hash(state);
70
line_scale.to_bits().hash(state);
71
}
72
}
73
}
74
}
75
76
/// A trait used to create gizmo configs groups.
77
///
78
/// Here you can store additional configuration for you gizmo group not covered by [`GizmoConfig`]
79
///
80
/// Make sure to derive [`Default`] + [`Reflect`] and register in the app using `app.init_gizmo_group::<T>()`
81
pub trait GizmoConfigGroup: Reflect + TypePath + Default {}
82
83
/// The default gizmo config group.
84
#[derive(Default, Reflect, GizmoConfigGroup)]
85
#[reflect(Default)]
86
pub struct DefaultGizmoConfigGroup;
87
88
/// Used when the gizmo config group needs to be type-erased.
89
/// Also used for retained gizmos, which can't have a gizmo config group.
90
#[derive(Default, Reflect, GizmoConfigGroup, Debug, Clone)]
91
#[reflect(Default, Clone)]
92
pub struct ErasedGizmoConfigGroup;
93
94
/// A [`Resource`] storing [`GizmoConfig`] and [`GizmoConfigGroup`] structs
95
///
96
/// Use `app.init_gizmo_group::<T>()` to register a custom config group.
97
#[derive(Reflect, Resource, Default)]
98
#[reflect(Resource, Default)]
99
pub struct GizmoConfigStore {
100
// INVARIANT: must map TypeId::of::<T>() to correct type T
101
#[reflect(ignore)]
102
store: TypeIdMap<(GizmoConfig, Box<dyn Reflect>)>,
103
}
104
105
impl GizmoConfigStore {
106
/// Returns [`GizmoConfig`] and [`GizmoConfigGroup`] associated with [`TypeId`] of a [`GizmoConfigGroup`]
107
pub fn get_config_dyn(&self, config_type_id: &TypeId) -> Option<(&GizmoConfig, &dyn Reflect)> {
108
let (config, ext) = self.store.get(config_type_id)?;
109
Some((config, ext.deref()))
110
}
111
112
/// Returns [`GizmoConfig`] and [`GizmoConfigGroup`] associated with [`GizmoConfigGroup`] `T`
113
///
114
/// # Panics
115
/// If the config does not exist for [`GizmoConfigGroup`] `T`
116
///
117
/// For a non-panicking version, see [`get_config`].
118
///
119
/// [`get_config`]: Self::get_config
120
pub fn config<T: GizmoConfigGroup>(&self) -> (&GizmoConfig, &T) {
121
let Some(configs) = self.get_config() else {
122
panic!("Requested config {} does not exist in `GizmoConfigStore`! Did you forget to add it using `app.init_gizmo_group<T>()`?", T::type_path());
123
};
124
configs
125
}
126
127
/// Returns Some([`GizmoConfig`] and [`GizmoConfigGroup`] associated with [`GizmoConfigGroup`] `T` if they exist,
128
/// else None.
129
///
130
/// If the configs will always be present, use [`config`].
131
///
132
/// [`config`]: Self::config
133
pub fn get_config<T: GizmoConfigGroup>(&self) -> Option<(&GizmoConfig, &T)> {
134
let (config, ext) = self.get_config_dyn(&TypeId::of::<T>())?;
135
// hash map invariant guarantees that &dyn Reflect is of correct type T
136
let ext = ext.as_any().downcast_ref().unwrap();
137
Some((config, ext))
138
}
139
140
/// Returns mutable [`GizmoConfig`] and [`GizmoConfigGroup`] associated with [`TypeId`] of a [`GizmoConfigGroup`]
141
pub fn get_config_mut_dyn(
142
&mut self,
143
config_type_id: &TypeId,
144
) -> Option<(&mut GizmoConfig, &mut dyn Reflect)> {
145
let (config, ext) = self.store.get_mut(config_type_id)?;
146
Some((config, ext.deref_mut()))
147
}
148
149
/// Returns mutable [`GizmoConfig`] and [`GizmoConfigGroup`] associated with [`GizmoConfigGroup`] `T`
150
///
151
/// # Panics
152
/// If the config does not exist for [`GizmoConfigGroup`] `T`
153
///
154
/// For a non-panicking version, see [`get_config_mut`].
155
///
156
/// [`get_config_mut`]: Self::get_config_mut
157
pub fn config_mut<T: GizmoConfigGroup>(&mut self) -> (&mut GizmoConfig, &mut T) {
158
let Some(configs) = self.get_config_mut() else {
159
panic!("Requested config {} does not exist in `GizmoConfigStore`! Did you forget to add it using `app.init_gizmo_group<T>()`?", T::type_path());
160
};
161
configs
162
}
163
164
/// Returns mutable Some([`GizmoConfig`] and [`GizmoConfigGroup`]) associated with [`GizmoConfigGroup`] `T` if they exist,
165
/// else None
166
///
167
/// If the configs will always be present, use [`config_mut`].
168
///
169
/// [`config_mut`]: Self::config_mut
170
pub fn get_config_mut<T: GizmoConfigGroup>(&mut self) -> Option<(&mut GizmoConfig, &mut T)> {
171
let (config, ext) = self.get_config_mut_dyn(&TypeId::of::<T>())?;
172
// hash map invariant guarantees that &dyn Reflect is of correct type T
173
let ext = ext.as_any_mut().downcast_mut().unwrap();
174
Some((config, ext))
175
}
176
177
/// Returns an iterator over all [`GizmoConfig`]s.
178
pub fn iter(&self) -> impl Iterator<Item = (&TypeId, &GizmoConfig, &dyn Reflect)> + '_ {
179
self.store
180
.iter()
181
.map(|(id, (config, ext))| (id, config, ext.deref()))
182
}
183
184
/// Returns an iterator over all [`GizmoConfig`]s, by mutable reference.
185
pub fn iter_mut(
186
&mut self,
187
) -> impl Iterator<Item = (&TypeId, &mut GizmoConfig, &mut dyn Reflect)> + '_ {
188
self.store
189
.iter_mut()
190
.map(|(id, (config, ext))| (id, config, ext.deref_mut()))
191
}
192
193
/// Inserts [`GizmoConfig`] and [`GizmoConfigGroup`] replacing old values
194
pub fn insert<T: GizmoConfigGroup>(&mut self, config: GizmoConfig, ext_config: T) {
195
// INVARIANT: hash map must correctly map TypeId::of::<T>() to &dyn Reflect of type T
196
self.store
197
.insert(TypeId::of::<T>(), (config, Box::new(ext_config)));
198
}
199
200
pub(crate) fn register<T: GizmoConfigGroup>(&mut self) {
201
self.insert(GizmoConfig::default(), T::default());
202
}
203
}
204
205
/// A struct that stores configuration for gizmos.
206
#[derive(Clone, Reflect, Debug)]
207
#[reflect(Clone, Default)]
208
pub struct GizmoConfig {
209
/// Set to `false` to stop drawing gizmos.
210
///
211
/// Defaults to `true`.
212
pub enabled: bool,
213
/// Line settings.
214
pub line: GizmoLineConfig,
215
/// How closer to the camera than real geometry the gizmos should be.
216
///
217
/// In 2D this setting has no effect and is effectively always -1.
218
///
219
/// Value between -1 and 1 (inclusive).
220
/// * 0 means that there is no change to the line position when rendering
221
/// * 1 means it is furthest away from camera as possible
222
/// * -1 means that it will always render in front of other things.
223
///
224
/// This is typically useful if you are drawing wireframes on top of polygons
225
/// and your wireframe is z-fighting (flickering on/off) with your main model.
226
/// You would set this value to a negative number close to 0.
227
pub depth_bias: f32,
228
/// Describes which rendering layers gizmos will be rendered to.
229
///
230
/// Gizmos will only be rendered to cameras with intersecting layers.
231
pub render_layers: RenderLayers,
232
}
233
234
impl Default for GizmoConfig {
235
fn default() -> Self {
236
Self {
237
enabled: true,
238
line: Default::default(),
239
depth_bias: 0.,
240
render_layers: Default::default(),
241
}
242
}
243
}
244
245
/// A struct that stores configuration for gizmos.
246
#[derive(Clone, Reflect, Debug)]
247
#[reflect(Clone, Default)]
248
pub struct GizmoLineConfig {
249
/// Line width specified in pixels.
250
///
251
/// If `perspective` is `true` then this is the size in pixels at the camera's near plane.
252
///
253
/// Defaults to `2.0`.
254
pub width: f32,
255
/// Apply perspective to gizmo lines.
256
///
257
/// This setting only affects 3D, non-orthographic cameras.
258
///
259
/// Defaults to `false`.
260
pub perspective: bool,
261
/// Determine the style of gizmo lines.
262
pub style: GizmoLineStyle,
263
/// Describe how lines should join.
264
pub joints: GizmoLineJoint,
265
}
266
267
impl Default for GizmoLineConfig {
268
fn default() -> Self {
269
Self {
270
width: 2.,
271
perspective: false,
272
style: GizmoLineStyle::Solid,
273
joints: GizmoLineJoint::None,
274
}
275
}
276
}
277
278
/// Configuration for gizmo meshes.
279
#[derive(Component)]
280
pub struct GizmoMeshConfig {
281
/// Apply perspective to gizmo lines.
282
///
283
/// This setting only affects 3D, non-orthographic cameras.
284
///
285
/// Defaults to `false`.
286
pub line_perspective: bool,
287
/// Determine the style of gizmo lines.
288
pub line_style: GizmoLineStyle,
289
/// Describe how lines should join.
290
pub line_joints: GizmoLineJoint,
291
/// Describes which rendering layers gizmos will be rendered to.
292
///
293
/// Gizmos will only be rendered to cameras with intersecting layers.
294
pub render_layers: RenderLayers,
295
/// Handle of the gizmo asset.
296
pub handle: Handle<GizmoAsset>,
297
}
298
299