Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gizmos/src/config.rs
6595 views
1
//! A module for the [`GizmoConfig<T>`] [`Resource`].
2
3
pub use bevy_gizmos_macros::GizmoConfigGroup;
4
5
#[cfg(all(
6
feature = "bevy_render",
7
any(feature = "bevy_pbr", feature = "bevy_sprite")
8
))]
9
use {crate::GizmoAsset, bevy_asset::Handle, bevy_ecs::component::Component};
10
11
use bevy_ecs::{reflect::ReflectResource, resource::Resource};
12
use bevy_reflect::{std_traits::ReflectDefault, Reflect, TypePath};
13
use bevy_utils::TypeIdMap;
14
use core::{
15
any::TypeId,
16
hash::Hash,
17
ops::{Deref, DerefMut},
18
panic,
19
};
20
21
/// An enum configuring how line joints will be drawn.
22
#[derive(Debug, Default, Copy, Clone, Reflect, PartialEq, Eq, Hash)]
23
#[reflect(Default, PartialEq, Hash, Clone)]
24
pub enum GizmoLineJoint {
25
/// Does not draw any line joints.
26
#[default]
27
None,
28
/// Extends both lines at the joining point until they meet in a sharp point.
29
Miter,
30
/// Draws a round corner with the specified resolution between the two lines.
31
///
32
/// The resolution determines the amount of triangles drawn per joint,
33
/// e.g. `GizmoLineJoint::Round(4)` will draw 4 triangles at each line joint.
34
Round(u32),
35
/// Draws a bevel, a straight line in this case, to connect the ends of both lines.
36
Bevel,
37
}
38
39
/// An enum used to configure the style of gizmo lines, similar to CSS line-style
40
#[derive(Copy, Clone, Debug, Default, PartialEq, Reflect)]
41
#[reflect(Default, PartialEq, Hash, Clone)]
42
#[non_exhaustive]
43
pub enum GizmoLineStyle {
44
/// A solid line without any decorators
45
#[default]
46
Solid,
47
/// A dotted line
48
Dotted,
49
/// A dashed line with configurable gap and line sizes
50
Dashed {
51
/// The length of the gap in `line_width`s
52
gap_scale: f32,
53
/// The length of the visible line in `line_width`s
54
line_scale: f32,
55
},
56
}
57
58
impl Eq for GizmoLineStyle {}
59
60
impl 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
79
/// A trait used to create gizmo configs groups.
80
///
81
/// Here you can store additional configuration for you gizmo group not covered by [`GizmoConfig`]
82
///
83
/// Make sure to derive [`Default`] + [`Reflect`] and register in the app using `app.init_gizmo_group::<T>()`
84
pub trait GizmoConfigGroup: Reflect + TypePath + Default {}
85
86
/// The default gizmo config group.
87
#[derive(Default, Reflect, GizmoConfigGroup)]
88
#[reflect(Default)]
89
pub struct DefaultGizmoConfigGroup;
90
91
/// Used when the gizmo config group needs to be type-erased.
92
/// Also used for retained gizmos, which can't have a gizmo config group.
93
#[derive(Default, Reflect, GizmoConfigGroup, Debug, Clone)]
94
#[reflect(Default, Clone)]
95
pub struct ErasedGizmoConfigGroup;
96
97
/// A [`Resource`] storing [`GizmoConfig`] and [`GizmoConfigGroup`] structs
98
///
99
/// Use `app.init_gizmo_group::<T>()` to register a custom config group.
100
#[derive(Reflect, Resource, Default)]
101
#[reflect(Resource, Default)]
102
pub struct GizmoConfigStore {
103
// INVARIANT: must map TypeId::of::<T>() to correct type T
104
#[reflect(ignore)]
105
store: TypeIdMap<(GizmoConfig, Box<dyn Reflect>)>,
106
}
107
108
impl GizmoConfigStore {
109
/// Returns [`GizmoConfig`] and [`GizmoConfigGroup`] associated with [`TypeId`] of a [`GizmoConfigGroup`]
110
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
/// Returns [`GizmoConfig`] and [`GizmoConfigGroup`] associated with [`GizmoConfigGroup`] `T`
116
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
// hash map invariant guarantees that &dyn Reflect is of correct type T
121
let ext = ext.as_any().downcast_ref().unwrap();
122
(config, ext)
123
}
124
125
/// Returns mutable [`GizmoConfig`] and [`GizmoConfigGroup`] associated with [`TypeId`] of a [`GizmoConfigGroup`]
126
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
/// Returns mutable [`GizmoConfig`] and [`GizmoConfigGroup`] associated with [`GizmoConfigGroup`] `T`
135
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
// hash map invariant guarantees that &dyn Reflect is of correct type T
140
let ext = ext.as_any_mut().downcast_mut().unwrap();
141
(config, ext)
142
}
143
144
/// Returns an iterator over all [`GizmoConfig`]s.
145
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
/// Returns an iterator over all [`GizmoConfig`]s, by mutable reference.
152
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
/// Inserts [`GizmoConfig`] and [`GizmoConfigGroup`] replacing old values
161
pub fn insert<T: GizmoConfigGroup>(&mut self, config: GizmoConfig, ext_config: T) {
162
// INVARIANT: hash map must correctly map TypeId::of::<T>() to &dyn Reflect of type T
163
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
/// A struct that stores configuration for gizmos.
173
#[derive(Clone, Reflect, Debug)]
174
#[reflect(Clone, Default)]
175
pub struct GizmoConfig {
176
/// Set to `false` to stop drawing gizmos.
177
///
178
/// Defaults to `true`.
179
pub enabled: bool,
180
/// Line settings.
181
pub line: GizmoLineConfig,
182
/// How closer to the camera than real geometry the gizmos should be.
183
///
184
/// In 2D this setting has no effect and is effectively always -1.
185
///
186
/// Value between -1 and 1 (inclusive).
187
/// * 0 means that there is no change to the line position when rendering
188
/// * 1 means it is furthest away from camera as possible
189
/// * -1 means that it will always render in front of other things.
190
///
191
/// This is typically useful if you are drawing wireframes on top of polygons
192
/// and your wireframe is z-fighting (flickering on/off) with your main model.
193
/// You would set this value to a negative number close to 0.
194
pub depth_bias: f32,
195
/// Describes which rendering layers gizmos will be rendered to.
196
///
197
/// Gizmos will only be rendered to cameras with intersecting layers.
198
#[cfg(feature = "bevy_render")]
199
pub render_layers: bevy_camera::visibility::RenderLayers,
200
}
201
202
impl 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
/// A struct that stores configuration for gizmos.
215
#[derive(Clone, Reflect, Debug)]
216
#[reflect(Clone, Default)]
217
pub struct GizmoLineConfig {
218
/// Line width specified in pixels.
219
///
220
/// If `perspective` is `true` then this is the size in pixels at the camera's near plane.
221
///
222
/// Defaults to `2.0`.
223
pub width: f32,
224
/// Apply perspective to gizmo lines.
225
///
226
/// This setting only affects 3D, non-orthographic cameras.
227
///
228
/// Defaults to `false`.
229
pub perspective: bool,
230
/// Determine the style of gizmo lines.
231
pub style: GizmoLineStyle,
232
/// Describe how lines should join.
233
pub joints: GizmoLineJoint,
234
}
235
236
impl 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)]
252
pub(crate) struct GizmoMeshConfig {
253
pub line_perspective: bool,
254
pub line_style: GizmoLineStyle,
255
pub line_joints: GizmoLineJoint,
256
pub render_layers: bevy_camera::visibility::RenderLayers,
257
pub handle: Handle<GizmoAsset>,
258
}
259
260