Skip to content

Commit b1ab036

Browse files
authored
Contextually clearing gizmos (#10973)
# Objective Allow `Gizmos` to work in `FixedUpdate` without any changes needed. This changes `Gizmos` from being a purely immediate mode api, but allows the user to use it as if it were an immediate mode API regardless of schedule context. Also allows for extending by other custom schedules by adding their own `GizmoStorage<Clear>` and the requisite systems: - `propagate_gizmos::<Clear>` before `update_gizmo_meshes` - `stash_default_gizmos` when starting a clear context - `pop_default_gizmos` when ending a clear context - `collect_default_gizmos` when grabbing the requested gizmos - `clear_gizmos` for clearing the context's gizmos ## Solution Adds a generic to `Gizmos` that defaults to `Update` (the current way gizmos works). When entering a new clear context the default `Gizmos` gets swapped out for that context's duration so the context can collect the gizmos requested. Prior work: #9153 ## To do - [x] `FixedUpdate` should probably get its own First, Pre, Update, Post, Last system sets for this. Otherwise users will need to make sure to order their systems before `clear_gizmos`. This could alternatively be fixed by moving the setup of this to `bevy_time::fixed`? PR to fix this issue: #10977 - [x] use mem::take internally for the swaps? - [x] Better name for the `Context` generic on gizmos? `Clear`? --- ## Changelog - Gizmos drawn in `FixedMain` now last until the next `FixedMain` iteration runs.
1 parent fcd87b2 commit b1ab036

File tree

10 files changed

+787
-209
lines changed

10 files changed

+787
-209
lines changed

crates/bevy_gizmos/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ bevy_reflect = { path = "../bevy_reflect", version = "0.14.0-dev" }
2727
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.14.0-dev" }
2828
bevy_transform = { path = "../bevy_transform", version = "0.14.0-dev" }
2929
bevy_gizmos_macros = { path = "macros", version = "0.14.0-dev" }
30+
bevy_time = { path = "../bevy_time", version = "0.14.0-dev" }
3031

3132
bytemuck = "1.0"
3233

crates/bevy_gizmos/src/arcs.rs

Lines changed: 47 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ use std::f32::consts::TAU;
1111

1212
// === 2D ===
1313

14-
impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
14+
impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear>
15+
where
16+
Config: GizmoConfigGroup,
17+
Clear: 'static + Send + Sync,
18+
{
1519
/// Draw an arc, which is a part of the circumference of a circle, in 2D.
1620
///
1721
/// This should be called for each frame the arc needs to be rendered.
@@ -50,7 +54,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
5054
arc_angle: f32,
5155
radius: f32,
5256
color: impl Into<Color>,
53-
) -> Arc2dBuilder<'_, 'w, 's, T> {
57+
) -> Arc2dBuilder<'_, 'w, 's, Config, Clear> {
5458
Arc2dBuilder {
5559
gizmos: self,
5660
position,
@@ -64,8 +68,12 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
6468
}
6569

6670
/// A builder returned by [`Gizmos::arc_2d`].
67-
pub struct Arc2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
68-
gizmos: &'a mut Gizmos<'w, 's, T>,
71+
pub struct Arc2dBuilder<'a, 'w, 's, Config, Clear>
72+
where
73+
Config: GizmoConfigGroup,
74+
Clear: 'static + Send + Sync,
75+
{
76+
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
6977
position: Vec2,
7078
direction_angle: f32,
7179
arc_angle: f32,
@@ -74,15 +82,23 @@ pub struct Arc2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
7482
segments: Option<usize>,
7583
}
7684

77-
impl<T: GizmoConfigGroup> Arc2dBuilder<'_, '_, '_, T> {
85+
impl<Config, Clear> Arc2dBuilder<'_, '_, '_, Config, Clear>
86+
where
87+
Config: GizmoConfigGroup,
88+
Clear: 'static + Send + Sync,
89+
{
7890
/// Set the number of line-segments for this arc.
7991
pub fn segments(mut self, segments: usize) -> Self {
8092
self.segments.replace(segments);
8193
self
8294
}
8395
}
8496

85-
impl<T: GizmoConfigGroup> Drop for Arc2dBuilder<'_, '_, '_, T> {
97+
impl<Config, Clear> Drop for Arc2dBuilder<'_, '_, '_, Config, Clear>
98+
where
99+
Config: GizmoConfigGroup,
100+
Clear: 'static + Send + Sync,
101+
{
86102
fn drop(&mut self) {
87103
if !self.gizmos.enabled {
88104
return;
@@ -114,7 +130,11 @@ fn arc_2d_inner(
114130

115131
// === 3D ===
116132

117-
impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
133+
impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear>
134+
where
135+
Config: GizmoConfigGroup,
136+
Clear: 'static + Send + Sync,
137+
{
118138
/// Draw an arc, which is a part of the circumference of a circle, in 3D. For default values
119139
/// this is drawing a standard arc. A standard arc is defined as
120140
///
@@ -169,7 +189,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
169189
position: Vec3,
170190
rotation: Quat,
171191
color: impl Into<Color>,
172-
) -> Arc3dBuilder<'_, 'w, 's, T> {
192+
) -> Arc3dBuilder<'_, 'w, 's, Config, Clear> {
173193
Arc3dBuilder {
174194
gizmos: self,
175195
start_vertex: Vec3::X,
@@ -226,7 +246,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
226246
from: Vec3,
227247
to: Vec3,
228248
color: impl Into<Color>,
229-
) -> Arc3dBuilder<'_, 'w, 's, T> {
249+
) -> Arc3dBuilder<'_, 'w, 's, Config, Clear> {
230250
self.arc_from_to(center, from, to, color, |x| x)
231251
}
232252

@@ -273,7 +293,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
273293
from: Vec3,
274294
to: Vec3,
275295
color: impl Into<Color>,
276-
) -> Arc3dBuilder<'_, 'w, 's, T> {
296+
) -> Arc3dBuilder<'_, 'w, 's, Config, Clear> {
277297
self.arc_from_to(center, from, to, color, |angle| {
278298
if angle > 0.0 {
279299
TAU - angle
@@ -293,7 +313,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
293313
to: Vec3,
294314
color: impl Into<Color>,
295315
angle_fn: impl Fn(f32) -> f32,
296-
) -> Arc3dBuilder<'_, 'w, 's, T> {
316+
) -> Arc3dBuilder<'_, 'w, 's, Config, Clear> {
297317
// `from` and `to` can be the same here since in either case nothing gets rendered and the
298318
// orientation ambiguity of `up` doesn't matter
299319
let from_axis = (from - center).normalize_or_zero();
@@ -320,8 +340,12 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
320340
}
321341

322342
/// A builder returned by [`Gizmos::arc_2d`].
323-
pub struct Arc3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
324-
gizmos: &'a mut Gizmos<'w, 's, T>,
343+
pub struct Arc3dBuilder<'a, 'w, 's, Config, Clear>
344+
where
345+
Config: GizmoConfigGroup,
346+
Clear: 'static + Send + Sync,
347+
{
348+
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
325349
// this is the vertex the arc starts on in the XZ plane. For the normal arc_3d method this is
326350
// always starting at Vec3::X. For the short/long arc methods we actually need a way to start
327351
// at the from position and this is where this internal field comes into play. Some implicit
@@ -340,15 +364,23 @@ pub struct Arc3dBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
340364
segments: Option<usize>,
341365
}
342366

343-
impl<T: GizmoConfigGroup> Arc3dBuilder<'_, '_, '_, T> {
367+
impl<Config, Clear> Arc3dBuilder<'_, '_, '_, Config, Clear>
368+
where
369+
Config: GizmoConfigGroup,
370+
Clear: 'static + Send + Sync,
371+
{
344372
/// Set the number of line-segments for this arc.
345373
pub fn segments(mut self, segments: usize) -> Self {
346374
self.segments.replace(segments);
347375
self
348376
}
349377
}
350378

351-
impl<T: GizmoConfigGroup> Drop for Arc3dBuilder<'_, '_, '_, T> {
379+
impl<Config, Clear> Drop for Arc3dBuilder<'_, '_, '_, Config, Clear>
380+
where
381+
Config: GizmoConfigGroup,
382+
Clear: 'static + Send + Sync,
383+
{
352384
fn drop(&mut self) {
353385
if !self.gizmos.enabled {
354386
return;

crates/bevy_gizmos/src/arrows.rs

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,24 @@ use bevy_math::{Quat, Vec2, Vec3};
1212
use bevy_transform::TransformPoint;
1313

1414
/// A builder returned by [`Gizmos::arrow`] and [`Gizmos::arrow_2d`]
15-
pub struct ArrowBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
16-
gizmos: &'a mut Gizmos<'w, 's, T>,
15+
pub struct ArrowBuilder<'a, 'w, 's, Config, Clear>
16+
where
17+
Config: GizmoConfigGroup,
18+
Clear: 'static + Send + Sync,
19+
{
20+
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
1721
start: Vec3,
1822
end: Vec3,
1923
color: Color,
2024
double_ended: bool,
2125
tip_length: f32,
2226
}
2327

24-
impl<T: GizmoConfigGroup> ArrowBuilder<'_, '_, '_, T> {
28+
impl<Config, Clear> ArrowBuilder<'_, '_, '_, Config, Clear>
29+
where
30+
Config: GizmoConfigGroup,
31+
Clear: 'static + Send + Sync,
32+
{
2533
/// Change the length of the tips to be `length`.
2634
/// The default tip length is [length of the arrow]/10.
2735
///
@@ -51,7 +59,11 @@ impl<T: GizmoConfigGroup> ArrowBuilder<'_, '_, '_, T> {
5159
}
5260
}
5361

54-
impl<T: GizmoConfigGroup> Drop for ArrowBuilder<'_, '_, '_, T> {
62+
impl<Config, Clear> Drop for ArrowBuilder<'_, '_, '_, Config, Clear>
63+
where
64+
Config: GizmoConfigGroup,
65+
Clear: 'static + Send + Sync,
66+
{
5567
/// Draws the arrow, by drawing lines with the stored [`Gizmos`]
5668
fn drop(&mut self) {
5769
if !self.gizmos.enabled {
@@ -90,7 +102,11 @@ impl<T: GizmoConfigGroup> Drop for ArrowBuilder<'_, '_, '_, T> {
90102
}
91103
}
92104

93-
impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
105+
impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear>
106+
where
107+
Config: GizmoConfigGroup,
108+
Clear: 'static + Send + Sync,
109+
{
94110
/// Draw an arrow in 3D, from `start` to `end`. Has four tips for convenient viewing from any direction.
95111
///
96112
/// This should be called for each frame the arrow needs to be rendered.
@@ -111,7 +127,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
111127
start: Vec3,
112128
end: Vec3,
113129
color: impl Into<Color>,
114-
) -> ArrowBuilder<'_, 'w, 's, T> {
130+
) -> ArrowBuilder<'_, 'w, 's, Config, Clear> {
115131
let length = (end - start).length();
116132
ArrowBuilder {
117133
gizmos: self,
@@ -143,12 +159,16 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
143159
start: Vec2,
144160
end: Vec2,
145161
color: impl Into<Color>,
146-
) -> ArrowBuilder<'_, 'w, 's, T> {
162+
) -> ArrowBuilder<'_, 'w, 's, Config, Clear> {
147163
self.arrow(start.extend(0.), end.extend(0.), color)
148164
}
149165
}
150166

151-
impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
167+
impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear>
168+
where
169+
Config: GizmoConfigGroup,
170+
Clear: 'static + Send + Sync,
171+
{
152172
/// Draw a set of axes local to the given transform (`transform`), with length scaled by a factor
153173
/// of `base_length`.
154174
///

crates/bevy_gizmos/src/circles.rs

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@ fn ellipse_inner(half_size: Vec2, segments: usize) -> impl Iterator<Item = Vec2>
1919
})
2020
}
2121

22-
impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
22+
impl<'w, 's, Config, Clear> Gizmos<'w, 's, Config, Clear>
23+
where
24+
Config: GizmoConfigGroup,
25+
Clear: 'static + Send + Sync,
26+
{
2327
/// Draw an ellipse in 3D at `position` with the flat side facing `normal`.
2428
///
2529
/// This should be called for each frame the ellipse needs to be rendered.
@@ -48,7 +52,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
4852
rotation: Quat,
4953
half_size: Vec2,
5054
color: impl Into<Color>,
51-
) -> EllipseBuilder<'_, 'w, 's, T> {
55+
) -> EllipseBuilder<'_, 'w, 's, Config, Clear> {
5256
EllipseBuilder {
5357
gizmos: self,
5458
position,
@@ -87,7 +91,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
8791
angle: f32,
8892
half_size: Vec2,
8993
color: impl Into<Color>,
90-
) -> Ellipse2dBuilder<'_, 'w, 's, T> {
94+
) -> Ellipse2dBuilder<'_, 'w, 's, Config, Clear> {
9195
Ellipse2dBuilder {
9296
gizmos: self,
9397
position,
@@ -126,7 +130,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
126130
normal: Dir3,
127131
radius: f32,
128132
color: impl Into<Color>,
129-
) -> EllipseBuilder<'_, 'w, 's, T> {
133+
) -> EllipseBuilder<'_, 'w, 's, Config, Clear> {
130134
EllipseBuilder {
131135
gizmos: self,
132136
position,
@@ -164,7 +168,7 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
164168
position: Vec2,
165169
radius: f32,
166170
color: impl Into<Color>,
167-
) -> Ellipse2dBuilder<'_, 'w, 's, T> {
171+
) -> Ellipse2dBuilder<'_, 'w, 's, Config, Clear> {
168172
Ellipse2dBuilder {
169173
gizmos: self,
170174
position,
@@ -177,24 +181,36 @@ impl<'w, 's, T: GizmoConfigGroup> Gizmos<'w, 's, T> {
177181
}
178182

179183
/// A builder returned by [`Gizmos::ellipse`].
180-
pub struct EllipseBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
181-
gizmos: &'a mut Gizmos<'w, 's, T>,
184+
pub struct EllipseBuilder<'a, 'w, 's, Config, Clear>
185+
where
186+
Config: GizmoConfigGroup,
187+
Clear: 'static + Send + Sync,
188+
{
189+
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
182190
position: Vec3,
183191
rotation: Quat,
184192
half_size: Vec2,
185193
color: Color,
186194
segments: usize,
187195
}
188196

189-
impl<T: GizmoConfigGroup> EllipseBuilder<'_, '_, '_, T> {
197+
impl<Config, Clear> EllipseBuilder<'_, '_, '_, Config, Clear>
198+
where
199+
Config: GizmoConfigGroup,
200+
Clear: 'static + Send + Sync,
201+
{
190202
/// Set the number of line-segments for this ellipse.
191203
pub fn segments(mut self, segments: usize) -> Self {
192204
self.segments = segments;
193205
self
194206
}
195207
}
196208

197-
impl<T: GizmoConfigGroup> Drop for EllipseBuilder<'_, '_, '_, T> {
209+
impl<Config, Clear> Drop for EllipseBuilder<'_, '_, '_, Config, Clear>
210+
where
211+
Config: GizmoConfigGroup,
212+
Clear: 'static + Send + Sync,
213+
{
198214
fn drop(&mut self) {
199215
if !self.gizmos.enabled {
200216
return;
@@ -208,24 +224,37 @@ impl<T: GizmoConfigGroup> Drop for EllipseBuilder<'_, '_, '_, T> {
208224
}
209225

210226
/// A builder returned by [`Gizmos::ellipse_2d`].
211-
pub struct Ellipse2dBuilder<'a, 'w, 's, T: GizmoConfigGroup> {
212-
gizmos: &'a mut Gizmos<'w, 's, T>,
227+
pub struct Ellipse2dBuilder<'a, 'w, 's, Config, Clear>
228+
where
229+
Config: GizmoConfigGroup,
230+
Clear: 'static + Send + Sync,
231+
{
232+
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
213233
position: Vec2,
214234
rotation: Mat2,
215235
half_size: Vec2,
216236
color: Color,
217237
segments: usize,
218238
}
219239

220-
impl<T: GizmoConfigGroup> Ellipse2dBuilder<'_, '_, '_, T> {
240+
impl<Config, Clear> Ellipse2dBuilder<'_, '_, '_, Config, Clear>
241+
where
242+
Config: GizmoConfigGroup,
243+
Clear: 'static + Send + Sync,
244+
{
221245
/// Set the number of line-segments for this ellipse.
222246
pub fn segments(mut self, segments: usize) -> Self {
223247
self.segments = segments;
224248
self
225249
}
226250
}
227251

228-
impl<T: GizmoConfigGroup> Drop for Ellipse2dBuilder<'_, '_, '_, T> {
252+
impl<Config, Clear> Drop for Ellipse2dBuilder<'_, '_, '_, Config, Clear>
253+
where
254+
Config: GizmoConfigGroup,
255+
Clear: 'static + Send + Sync,
256+
{
257+
/// Set the number of line-segments for this ellipse.
229258
fn drop(&mut self) {
230259
if !self.gizmos.enabled {
231260
return;

0 commit comments

Comments
 (0)