Skip to content

Commit e6a0f75

Browse files
authored
More gizmos builders (#13261)
# Objective - Add GizmoBuilders for some primitives as discussed in #13233 ## Solution - `gizmos.primitive_2d(CIRCLE)` and `gizmos.primitive_2d(ELLIPSE)` now return `Ellipse2dBuilder` aswell. - `gizmos.primitive_3d(SPHERE)` and `gizmos.sphere()` now return the same `SphereBuilder`. - the `.circle_segments` method on the `SphereBuilder` that used to be returned by `.sphere()` is now called `.segments` - the sphere primitive gizmo now matches the `gizmos.sphere` gizmo - `gizmos.primitive_2d(ANNULUS)` now returns a `Annulus2dBuilder` allowing the configuration of the `segments` - gizmos cylinders and capsules now have only 1 line per axis, similar to `gizmos.sphere` ## Migration Guide - Some `gizmos.primitive_nd` methods now return some or different builders. You may need to adjust types and match statements - Replace any calls to `circle_segments()` with `.segments()` --------- Co-authored-by: Raphael Büttgenbach <[email protected]>
1 parent cca4fc7 commit e6a0f75

File tree

6 files changed

+259
-285
lines changed

6 files changed

+259
-285
lines changed

crates/bevy_gizmos/src/circles.rs

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,45 @@ where
178178
resolution: DEFAULT_CIRCLE_RESOLUTION,
179179
}
180180
}
181+
182+
/// Draw a wireframe sphere in 3D made out of 3 circles around the axes.
183+
///
184+
/// This should be called for each frame the sphere needs to be rendered.
185+
///
186+
/// # Example
187+
/// ```
188+
/// # use bevy_gizmos::prelude::*;
189+
/// # use bevy_render::prelude::*;
190+
/// # use bevy_math::prelude::*;
191+
/// # use bevy_color::Color;
192+
/// fn system(mut gizmos: Gizmos) {
193+
/// gizmos.sphere(Vec3::ZERO, Quat::IDENTITY, 1., Color::BLACK);
194+
///
195+
/// // Each circle has 32 line-segments by default.
196+
/// // You may want to increase this for larger spheres.
197+
/// gizmos
198+
/// .sphere(Vec3::ZERO, Quat::IDENTITY, 5., Color::BLACK)
199+
/// .resolution(64);
200+
/// }
201+
/// # bevy_ecs::system::assert_is_system(system);
202+
/// ```
203+
#[inline]
204+
pub fn sphere(
205+
&mut self,
206+
position: Vec3,
207+
rotation: Quat,
208+
radius: f32,
209+
color: impl Into<Color>,
210+
) -> SphereBuilder<'_, 'w, 's, Config, Clear> {
211+
SphereBuilder {
212+
gizmos: self,
213+
radius,
214+
position,
215+
rotation,
216+
color: color.into(),
217+
resolution: DEFAULT_CIRCLE_RESOLUTION,
218+
}
219+
}
181220
}
182221

183222
/// A builder returned by [`Gizmos::ellipse`].
@@ -266,3 +305,66 @@ where
266305
self.gizmos.linestrip_2d(positions, self.color);
267306
}
268307
}
308+
309+
/// Builder for configuring the drawing options of [`Sphere`].
310+
pub struct SphereBuilder<'a, 'w, 's, Config, Clear>
311+
where
312+
Config: GizmoConfigGroup,
313+
Clear: 'static + Send + Sync,
314+
{
315+
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
316+
317+
// Radius of the sphere
318+
radius: f32,
319+
320+
// Rotation of the sphere around the origin in 3D space
321+
rotation: Quat,
322+
// Center position of the sphere in 3D space
323+
position: Vec3,
324+
// Color of the sphere
325+
color: Color,
326+
327+
// Number of line-segments used to approximate the sphere geometry
328+
resolution: usize,
329+
}
330+
331+
impl<Config, Clear> SphereBuilder<'_, '_, '_, Config, Clear>
332+
where
333+
Config: GizmoConfigGroup,
334+
Clear: 'static + Send + Sync,
335+
{
336+
/// Set the number of line-segments used to approximate the sphere geometry.
337+
pub fn resolution(mut self, resolution: usize) -> Self {
338+
self.resolution = resolution;
339+
self
340+
}
341+
}
342+
343+
impl<Config, Clear> Drop for SphereBuilder<'_, '_, '_, Config, Clear>
344+
where
345+
Config: GizmoConfigGroup,
346+
Clear: 'static + Send + Sync,
347+
{
348+
fn drop(&mut self) {
349+
if !self.gizmos.enabled {
350+
return;
351+
}
352+
353+
let SphereBuilder {
354+
radius,
355+
position: center,
356+
rotation,
357+
color,
358+
resolution,
359+
..
360+
} = self;
361+
362+
// draws one great circle around each of the local axes
363+
Vec3::AXES.into_iter().for_each(|axis| {
364+
let normal = *rotation * axis;
365+
self.gizmos
366+
.circle(*center, Dir3::new_unchecked(normal), *radius, *color)
367+
.resolution(*resolution);
368+
});
369+
}
370+
}

crates/bevy_gizmos/src/gizmos.rs

Lines changed: 1 addition & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22
33
use std::{iter, marker::PhantomData, mem};
44

5-
use crate::circles::DEFAULT_CIRCLE_RESOLUTION;
65
use bevy_color::{Color, LinearRgba};
76
use bevy_ecs::{
87
component::Tick,
98
system::{Deferred, ReadOnlySystemParam, Res, Resource, SystemBuffer, SystemMeta, SystemParam},
109
world::{unsafe_world_cell::UnsafeWorldCell, World},
1110
};
12-
use bevy_math::{Dir3, Quat, Rotation2d, Vec2, Vec3};
11+
use bevy_math::{Quat, Rotation2d, Vec2, Vec3};
1312
use bevy_transform::TransformPoint;
1413
use bevy_utils::default;
1514

@@ -459,45 +458,6 @@ where
459458
strip_colors.push(LinearRgba::NAN);
460459
}
461460

462-
/// Draw a wireframe sphere in 3D made out of 3 circles around the axes.
463-
///
464-
/// This should be called for each frame the sphere needs to be rendered.
465-
///
466-
/// # Example
467-
/// ```
468-
/// # use bevy_gizmos::prelude::*;
469-
/// # use bevy_render::prelude::*;
470-
/// # use bevy_math::prelude::*;
471-
/// # use bevy_color::Color;
472-
/// fn system(mut gizmos: Gizmos) {
473-
/// gizmos.sphere(Vec3::ZERO, Quat::IDENTITY, 1., Color::BLACK);
474-
///
475-
/// // Each circle has 32 line-segments by default.
476-
/// // You may want to increase this for larger spheres.
477-
/// gizmos
478-
/// .sphere(Vec3::ZERO, Quat::IDENTITY, 5., Color::BLACK)
479-
/// .resolution(64);
480-
/// }
481-
/// # bevy_ecs::system::assert_is_system(system);
482-
/// ```
483-
#[inline]
484-
pub fn sphere(
485-
&mut self,
486-
position: Vec3,
487-
rotation: Quat,
488-
radius: f32,
489-
color: impl Into<Color>,
490-
) -> SphereBuilder<'_, 'w, 's, Config, Clear> {
491-
SphereBuilder {
492-
gizmos: self,
493-
position,
494-
rotation: rotation.normalize(),
495-
radius,
496-
color: color.into(),
497-
resolution: DEFAULT_CIRCLE_RESOLUTION,
498-
}
499-
}
500-
501461
/// Draw a wireframe rectangle in 3D.
502462
///
503463
/// This should be called for each frame the rectangle needs to be rendered.
@@ -790,49 +750,6 @@ where
790750
}
791751
}
792752

793-
/// A builder returned by [`Gizmos::sphere`].
794-
pub struct SphereBuilder<'a, 'w, 's, Config, Clear = ()>
795-
where
796-
Config: GizmoConfigGroup,
797-
Clear: 'static + Send + Sync,
798-
{
799-
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
800-
position: Vec3,
801-
rotation: Quat,
802-
radius: f32,
803-
color: Color,
804-
resolution: usize,
805-
}
806-
807-
impl<Config, Clear> SphereBuilder<'_, '_, '_, Config, Clear>
808-
where
809-
Config: GizmoConfigGroup,
810-
Clear: 'static + Send + Sync,
811-
{
812-
/// Set the number of line-segments per circle for this sphere.
813-
pub fn resolution(mut self, resolution: usize) -> Self {
814-
self.resolution = resolution;
815-
self
816-
}
817-
}
818-
819-
impl<Config, Clear> Drop for SphereBuilder<'_, '_, '_, Config, Clear>
820-
where
821-
Config: GizmoConfigGroup,
822-
Clear: 'static + Send + Sync,
823-
{
824-
fn drop(&mut self) {
825-
if !self.gizmos.enabled {
826-
return;
827-
}
828-
for axis in Dir3::AXES {
829-
self.gizmos
830-
.circle(self.position, self.rotation * axis, self.radius, self.color)
831-
.resolution(self.resolution);
832-
}
833-
}
834-
}
835-
836753
fn rect_inner(size: Vec2) -> [Vec2; 4] {
837754
let half_size = size / 2.;
838755
let tl = Vec2::new(-half_size.x, half_size.y);

crates/bevy_gizmos/src/primitives/dim2.rs

Lines changed: 84 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ where
102102
Config: GizmoConfigGroup,
103103
Clear: 'static + Send + Sync,
104104
{
105-
type Output<'a> = () where Self: 'a;
105+
type Output<'a> = crate::circles::Ellipse2dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a;
106106

107107
fn primitive_2d(
108108
&mut self,
@@ -111,11 +111,7 @@ where
111111
_angle: f32,
112112
color: impl Into<Color>,
113113
) -> Self::Output<'_> {
114-
if !self.enabled {
115-
return;
116-
}
117-
118-
self.circle_2d(position, primitive.radius, color);
114+
self.circle_2d(position, primitive.radius, color)
119115
}
120116
}
121117

@@ -205,46 +201,114 @@ where
205201
Config: GizmoConfigGroup,
206202
Clear: 'static + Send + Sync,
207203
{
208-
type Output<'a> = () where Self: 'a;
204+
type Output<'a> = crate::circles::Ellipse2dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a;
209205

210-
fn primitive_2d(
206+
fn primitive_2d<'a>(
211207
&mut self,
212208
primitive: &Ellipse,
213209
position: Vec2,
214210
angle: f32,
215211
color: impl Into<Color>,
216212
) -> Self::Output<'_> {
217-
if !self.enabled {
218-
return;
219-
}
220-
221-
self.ellipse_2d(position, angle, primitive.half_size, color);
213+
self.ellipse_2d(position, angle, primitive.half_size, color)
222214
}
223215
}
224216

225217
// annulus 2d
226218

219+
/// Builder for configuring the drawing options of [`Annulus`].
220+
pub struct Annulus2dBuilder<'a, 'w, 's, Config, Clear>
221+
where
222+
Config: GizmoConfigGroup,
223+
Clear: 'static + Send + Sync,
224+
{
225+
gizmos: &'a mut Gizmos<'w, 's, Config, Clear>,
226+
position: Vec2,
227+
inner_radius: f32,
228+
outer_radius: f32,
229+
color: Color,
230+
inner_resolution: usize,
231+
outer_resolution: usize,
232+
}
233+
234+
impl<Config, Clear> Annulus2dBuilder<'_, '_, '_, Config, Clear>
235+
where
236+
Config: GizmoConfigGroup,
237+
Clear: 'static + Send + Sync,
238+
{
239+
/// Set the number of line-segments for each circle of the annulus.
240+
pub fn resolution(mut self, resolution: usize) -> Self {
241+
self.outer_resolution = resolution;
242+
self.inner_resolution = resolution;
243+
self
244+
}
245+
246+
/// Set the number of line-segments for the outer circle of the annulus.
247+
pub fn outer_resolution(mut self, resolution: usize) -> Self {
248+
self.outer_resolution = resolution;
249+
self
250+
}
251+
252+
/// Set the number of line-segments for the inner circle of the annulus.
253+
pub fn inner_resolution(mut self, resolution: usize) -> Self {
254+
self.inner_resolution = resolution;
255+
self
256+
}
257+
}
258+
227259
impl<'w, 's, Config, Clear> GizmoPrimitive2d<Annulus> for Gizmos<'w, 's, Config, Clear>
228260
where
229261
Config: GizmoConfigGroup,
230262
Clear: 'static + Send + Sync,
231263
{
232-
type Output<'a> = () where Self: 'a;
264+
type Output<'a> = Annulus2dBuilder<'a, 'w, 's, Config, Clear> where Self: 'a;
233265

234266
fn primitive_2d(
235267
&mut self,
236268
primitive: &Annulus,
237269
position: Vec2,
238-
angle: f32,
270+
_angle: f32,
239271
color: impl Into<Color>,
240272
) -> Self::Output<'_> {
241-
if !self.enabled {
273+
Annulus2dBuilder {
274+
gizmos: self,
275+
position,
276+
inner_radius: primitive.inner_circle.radius,
277+
outer_radius: primitive.outer_circle.radius,
278+
color: color.into(),
279+
inner_resolution: crate::circles::DEFAULT_CIRCLE_RESOLUTION,
280+
outer_resolution: crate::circles::DEFAULT_CIRCLE_RESOLUTION,
281+
}
282+
}
283+
}
284+
285+
impl<Config, Clear> Drop for Annulus2dBuilder<'_, '_, '_, Config, Clear>
286+
where
287+
Config: GizmoConfigGroup,
288+
Clear: 'static + Send + Sync,
289+
{
290+
fn drop(&mut self) {
291+
if !self.gizmos.enabled {
242292
return;
243293
}
244294

245-
let color = color.into();
246-
self.primitive_2d(&primitive.inner_circle, position, angle, color);
247-
self.primitive_2d(&primitive.outer_circle, position, angle, color);
295+
let Annulus2dBuilder {
296+
gizmos,
297+
position,
298+
inner_radius,
299+
outer_radius,
300+
inner_resolution,
301+
outer_resolution,
302+
color,
303+
..
304+
} = self;
305+
306+
gizmos
307+
.circle_2d(*position, *outer_radius, *color)
308+
.resolution(*outer_resolution);
309+
gizmos
310+
.circle_2d(*position, *inner_radius, *color)
311+
.resolution(*inner_resolution);
248312
}
249313
}
250314

@@ -266,8 +330,7 @@ where
266330
) -> Self::Output<'_> {
267331
if !self.enabled {
268332
return;
269-
}
270-
333+
};
271334
let [a, b, c, d] =
272335
[(1.0, 0.0), (0.0, 1.0), (-1.0, 0.0), (0.0, -1.0)].map(|(sign_x, sign_y)| {
273336
Vec2::new(

0 commit comments

Comments
 (0)