Skip to content
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

Move Circle Gizmos to Their Own File #10631

Merged
merged 10 commits into from
Nov 20, 2023
7 changes: 5 additions & 2 deletions crates/bevy_gizmos/src/arrows.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
//! Additional Gizmo Functions -- Arrows
//! Additional [`Gizmos`] Functions -- Arrows
//!
//! Includes the implementation of [`Gizmos::arrow`] and [`Gizmos::arrow_2d`],
//! and assorted support items.

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

/// A builder returned by [`Gizmos::arrow`] and [`Gizmos::arrow_2d`]
pub struct ArrowBuilder<'a, 's> {
gizmos: &'a mut Gizmos<'s>,
start: Vec3,
Expand All @@ -12,7 +16,6 @@ pub struct ArrowBuilder<'a, 's> {
tip_length: f32,
}

/// A builder returned by [`Gizmos::arrow`] and [`Gizmos::arrow_2d`]
impl ArrowBuilder<'_, '_> {
/// Change the length of the tips to be `length`.
/// The default tip length is [length of the arrow]/10.
Expand Down
145 changes: 145 additions & 0 deletions crates/bevy_gizmos/src/circles.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//! Additional [`Gizmos`] Functions -- Circles
//!
//! Includes the implementation of [`Gizmos::circle`] and [`Gizmos::circle_2d`],
//! and assorted support items.

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

pub(crate) const DEFAULT_CIRCLE_SEGMENTS: usize = 32;

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};

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
3 changes: 2 additions & 1 deletion crates/bevy_gizmos/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
//!
//! See the documentation on [`Gizmos`] for more examples.

mod arrows;
pub mod arrows;
pub mod circles;
pub mod gizmos;

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