Skip to content

Move Circle Gizmos to Their Own File #10631

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Nov 20, 2023
142 changes: 142 additions & 0 deletions crates/bevy_gizmos/src/circles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//! Additional [`Gizmo`] Functions -- Arrows

use crate::prelude::Gizmos;
use bevy_math::{Quat, Vec2, Vec3};
use bevy_render::color::Color;
use std::f32::consts::TAU;

pub const DEFAULT_CIRCLE_SEGMENTS: usize = 32;

pub fn circle_inner(radius: f32, segments: usize) -> impl Iterator<Item = Vec2> {
(0..segments + 1).map(move |i| {
let angle = i as f32 * TAU / segments as f32;
Vec2::from(angle.sin_cos()) * radius
})
}

impl<'s> Gizmos<'s> {
/// Draw a circle in 3D at `position` with the flat side facing `normal`.
///
/// This should be called for each frame the circle needs to be rendered.
///
/// # Example
/// ```
/// # use bevy_gizmos::prelude::*;
/// # use bevy_render::prelude::*;
/// # use bevy_math::prelude::*;
/// fn system(mut gizmos: Gizmos) {
/// gizmos.circle(Vec3::ZERO, Vec3::Z, 1., Color::GREEN);
///
/// // Circles have 32 line-segments by default.
/// // You may want to increase this for larger circles.
/// gizmos
/// .circle(Vec3::ZERO, Vec3::Z, 5., Color::RED)
/// .segments(64);
/// }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
#[inline]
pub fn circle(
&mut self,
position: Vec3,
normal: Vec3,
radius: f32,
color: Color,
) -> CircleBuilder<'_, 's> {
CircleBuilder {
gizmos: self,
position,
normal,
radius,
color,
segments: DEFAULT_CIRCLE_SEGMENTS,
}
}

/// Draw a circle in 2D.
///
/// This should be called for each frame the circle needs to be rendered.
///
/// # Example
/// ```
/// # use bevy_gizmos::prelude::*;
/// # use bevy_render::prelude::*;
/// # use bevy_math::prelude::*;
/// fn system(mut gizmos: Gizmos) {
/// gizmos.circle_2d(Vec2::ZERO, 1., Color::GREEN);
///
/// // Circles have 32 line-segments by default.
/// // You may want to increase this for larger circles.
/// gizmos
/// .circle_2d(Vec2::ZERO, 5., Color::RED)
/// .segments(64);
/// }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
#[inline]
pub fn circle_2d(
&mut self,
position: Vec2,
radius: f32,
color: Color,
) -> Circle2dBuilder<'_, 's> {
Circle2dBuilder {
gizmos: self,
position,
radius,
color,
segments: DEFAULT_CIRCLE_SEGMENTS,
}
}
}

/// A builder returned by [`Gizmos::circle`].
pub struct CircleBuilder<'a, 's> {
gizmos: &'a mut Gizmos<'s>,
position: Vec3,
normal: Vec3,
radius: f32,
color: Color,
segments: usize,
}

impl CircleBuilder<'_, '_> {
/// Set the number of line-segments for this circle.
pub fn segments(mut self, segments: usize) -> Self {
self.segments = segments;
self
}
}

impl Drop for CircleBuilder<'_, '_> {
fn drop(&mut self) {
let rotation = Quat::from_rotation_arc(Vec3::Z, self.normal);
let positions = circle_inner(self.radius, self.segments)
.map(|vec2| (self.position + rotation * vec2.extend(0.)));
self.gizmos.linestrip(positions, self.color);
}
}

/// A builder returned by [`Gizmos::circle_2d`].
pub struct Circle2dBuilder<'a, 's> {
gizmos: &'a mut Gizmos<'s>,
position: Vec2,
radius: f32,
color: Color,
segments: usize,
}

impl Circle2dBuilder<'_, '_> {
/// Set the number of line-segments for this circle.
pub fn segments(mut self, segments: usize) -> Self {
self.segments = segments;
self
}
}

impl Drop for Circle2dBuilder<'_, '_> {
fn drop(&mut self) {
let positions = circle_inner(self.radius, self.segments).map(|vec2| (vec2 + self.position));
self.gizmos.linestrip_2d(positions, self.color);
}
}
135 changes: 1 addition & 134 deletions crates/bevy_gizmos/src/gizmos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use std::{f32::consts::TAU, iter};

pub use crate::circles::DEFAULT_CIRCLE_SEGMENTS;
use bevy_ecs::{
system::{Deferred, Resource, SystemBuffer, SystemMeta, SystemParam},
world::World,
Expand All @@ -13,8 +14,6 @@ use bevy_transform::TransformPoint;
type PositionItem = [f32; 3];
type ColorItem = [f32; 4];

const DEFAULT_CIRCLE_SEGMENTS: usize = 32;

#[derive(Resource, Default)]
pub(crate) struct GizmoStorage {
pub list_positions: Vec<PositionItem>,
Expand Down Expand Up @@ -201,44 +200,6 @@ impl<'s> Gizmos<'s> {
strip_colors.push([f32::NAN; 4]);
}

/// Draw a circle in 3D at `position` with the flat side facing `normal`.
///
/// This should be called for each frame the circle needs to be rendered.
///
/// # Example
/// ```
/// # use bevy_gizmos::prelude::*;
/// # use bevy_render::prelude::*;
/// # use bevy_math::prelude::*;
/// fn system(mut gizmos: Gizmos) {
/// gizmos.circle(Vec3::ZERO, Vec3::Z, 1., Color::GREEN);
///
/// // Circles have 32 line-segments by default.
/// // You may want to increase this for larger circles.
/// gizmos
/// .circle(Vec3::ZERO, Vec3::Z, 5., Color::RED)
/// .segments(64);
/// }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
#[inline]
pub fn circle(
&mut self,
position: Vec3,
normal: Vec3,
radius: f32,
color: Color,
) -> CircleBuilder<'_, 's> {
CircleBuilder {
gizmos: self,
position,
normal,
radius,
color,
segments: DEFAULT_CIRCLE_SEGMENTS,
}
}

/// Draw a wireframe sphere in 3D made out of 3 circles around the axes.
///
/// This should be called for each frame the sphere needs to be rendered.
Expand Down Expand Up @@ -466,42 +427,6 @@ impl<'s> Gizmos<'s> {
self.line_gradient_2d(start, start + vector, start_color, end_color);
}

/// Draw a circle in 2D.
///
/// This should be called for each frame the circle needs to be rendered.
///
/// # Example
/// ```
/// # use bevy_gizmos::prelude::*;
/// # use bevy_render::prelude::*;
/// # use bevy_math::prelude::*;
/// fn system(mut gizmos: Gizmos) {
/// gizmos.circle_2d(Vec2::ZERO, 1., Color::GREEN);
///
/// // Circles have 32 line-segments by default.
/// // You may want to increase this for larger circles.
/// gizmos
/// .circle_2d(Vec2::ZERO, 5., Color::RED)
/// .segments(64);
/// }
/// # bevy_ecs::system::assert_is_system(system);
/// ```
#[inline]
pub fn circle_2d(
&mut self,
position: Vec2,
radius: f32,
color: Color,
) -> Circle2dBuilder<'_, 's> {
Circle2dBuilder {
gizmos: self,
position,
radius,
color,
segments: DEFAULT_CIRCLE_SEGMENTS,
}
}

/// Draw an arc, which is a part of the circumference of a circle, in 2D.
///
/// This should be called for each frame the arc needs to be rendered.
Expand Down Expand Up @@ -603,33 +528,6 @@ impl<'s> Gizmos<'s> {
}
}

/// A builder returned by [`Gizmos::circle`].
pub struct CircleBuilder<'a, 's> {
gizmos: &'a mut Gizmos<'s>,
position: Vec3,
normal: Vec3,
radius: f32,
color: Color,
segments: usize,
}

impl CircleBuilder<'_, '_> {
/// Set the number of line-segments for this circle.
pub fn segments(mut self, segments: usize) -> Self {
self.segments = segments;
self
}
}

impl Drop for CircleBuilder<'_, '_> {
fn drop(&mut self) {
let rotation = Quat::from_rotation_arc(Vec3::Z, self.normal);
let positions = circle_inner(self.radius, self.segments)
.map(|vec2| (self.position + rotation * vec2.extend(0.)));
self.gizmos.linestrip(positions, self.color);
}
}

/// A builder returned by [`Gizmos::sphere`].
pub struct SphereBuilder<'a, 's> {
gizmos: &'a mut Gizmos<'s>,
Expand Down Expand Up @@ -658,30 +556,6 @@ impl Drop for SphereBuilder<'_, '_> {
}
}

/// A builder returned by [`Gizmos::circle_2d`].
pub struct Circle2dBuilder<'a, 's> {
gizmos: &'a mut Gizmos<'s>,
position: Vec2,
radius: f32,
color: Color,
segments: usize,
}

impl Circle2dBuilder<'_, '_> {
/// Set the number of line-segments for this circle.
pub fn segments(mut self, segments: usize) -> Self {
self.segments = segments;
self
}
}

impl Drop for Circle2dBuilder<'_, '_> {
fn drop(&mut self) {
let positions = circle_inner(self.radius, self.segments).map(|vec2| (vec2 + self.position));
self.gizmos.linestrip_2d(positions, self.color);
}
}

/// A builder returned by [`Gizmos::arc_2d`].
pub struct Arc2dBuilder<'a, 's> {
gizmos: &'a mut Gizmos<'s>,
Expand Down Expand Up @@ -730,13 +604,6 @@ fn arc_inner(
})
}

fn circle_inner(radius: f32, segments: usize) -> impl Iterator<Item = Vec2> {
(0..segments + 1).map(move |i| {
let angle = i as f32 * TAU / segments as f32;
Vec2::from(angle.sin_cos()) * radius
})
}

fn rect_inner(size: Vec2) -> [Vec2; 4] {
let half_size = size / 2.;
let tl = Vec2::new(-half_size.x, half_size.y);
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_gizmos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
//! See the documentation on [`Gizmos`] for more examples.

mod arrows;
mod circles;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be pub? Along with arrows. Currently I don't see any way to access these types externally.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL it's possible to have a struct returned by a function which isn't exported anywhere

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, Rust's module privacy rules are bizarre, where you can create "sealed" traits and structs.

This got used to create unimplementable traits, so now they can't fix it.

pub mod gizmos;

#[cfg(feature = "bevy_sprite")]
Expand Down