Skip to content

Commit

Permalink
bop
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-blackbird committed Dec 5, 2022
1 parent 77588a0 commit 69c48e0
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 70 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,36 +4,39 @@ use bevy_math::{Mat2, Quat, Vec2, Vec3};
use bevy_render::prelude::Color;
use crossbeam_channel::{unbounded, Receiver, Sender};

use crate::SendItem;
use crate::{SendItem, GIZMO};

pub struct GizmoDraw {
sender: Sender<SendItem>,
pub(crate) receiver: Receiver<SendItem>,
circle_segments: usize,
}

impl GizmoDraw {
pub(crate) fn new() -> Self {
let (sender, receiver) = unbounded();
GizmoDraw {
sender,
receiver,
circle_segments: 32,
}
GizmoDraw { sender, receiver }
}
}

const CIRCLE_SEGMENTS: usize = 32;

impl GizmoDraw {
/// Draw a line from `start` to `end`.
#[inline]
pub fn line(&self, start: Vec3, end: Vec3, color: Color) {
self.send_line([start, end], [color, color]);
self.line_gradient(start, end, color, color);
}

/// Draw a line from `start` to `end`.
#[inline]
pub fn line_gradient(&self, start: Vec3, end: Vec3, start_color: Color, end_color: Color) {
self.send_line([start, end], [start_color, end_color]);
let _ = self.sender.send(SendItem::Single((
[start.to_array(), end.to_array()],
[
start_color.as_linear_rgba_f32(),
end_color.as_linear_rgba_f32(),
],
)));
}

/// Draw a line from `start` to `start + vector`.
Expand Down Expand Up @@ -61,39 +64,49 @@ impl GizmoDraw {
let _ = self.sender.send(SendItem::Strip(iter.unzip()));
}

/// Draw a circle at `position` with the flat side facing `normal`.
#[inline]
pub fn circle(&self, position: Vec3, normal: Vec3, radius: f32, color: Color) {
let rotation = Quat::from_rotation_arc(Vec3::Z, normal);

let positions = self
.circle_inner(radius)
.map(|vec2| (position + rotation * vec2.extend(0.)));
fn linelist(&self, list: impl IntoIterator<Item = Vec3>, color: Color) {
let iter = list
.into_iter()
.map(|p| p.to_array())
.zip(iter::repeat(color.as_linear_rgba_f32()));
let _ = self.sender.send(SendItem::List(iter.unzip()));
}

self.linestrip(positions, color);
/// Draw a circle at `position` with the flat side facing `normal`.
#[inline]
pub fn circle(&self, position: Vec3, normal: Vec3, radius: f32, color: Color) -> DrawCircle {
DrawCircle {
position,
normal,
radius,
color,
segments: CIRCLE_SEGMENTS,
}
}

/// Draw a sphere.
#[inline]
pub fn sphere(&self, position: Vec3, radius: f32, color: Color) {
self.circle(position, Vec3::X, radius, color);
self.circle(position, Vec3::Y, radius, color);
self.circle(position, Vec3::Z, radius, color);
pub fn sphere(&self, position: Vec3, radius: f32, color: Color) -> DrawSphere {
DrawSphere {
position,
radius,
color,
circle_segments: CIRCLE_SEGMENTS,
}
}

/// Draw a rectangle.
#[inline]
pub fn rect(&self, position: Vec3, rotation: Quat, size: Vec2, color: Color) {
let [tl, tr, br, bl] = self
.rect_inner(size)
.map(|vec2| position + rotation * vec2.extend(0.));
let [tl, tr, br, bl] = rect_inner(size).map(|vec2| position + rotation * vec2.extend(0.));
self.linestrip([tl, tr, br, bl, tl], color);
}

/// Draw a box.
#[inline]
pub fn cuboid(&self, position: Vec3, rotation: Quat, size: Vec3, color: Color) {
let rect = self.rect_inner(size.truncate());
let rect = rect_inner(size.truncate());
// Front
let [tlf, trf, brf, blf] = rect.map(|vec2| position + rotation * vec2.extend(size.z / 2.));
// Back
Expand Down Expand Up @@ -147,50 +160,104 @@ impl GizmoDraw {

// Draw a circle.
#[inline]
pub fn circle_2d(&self, position: Vec2, radius: f32, color: Color) {
let positions = self.circle_inner(radius).map(|vec2| (vec2 + position));
self.linestrip_2d(positions, color);
pub fn circle_2d(&self, position: Vec2, radius: f32, color: Color) -> DrawCircle2d {
DrawCircle2d {
position,
radius,
color,
segments: CIRCLE_SEGMENTS,
}
}

/// Draw a rectangle.
#[inline]
pub fn rect_2d(&self, position: Vec2, rotation: f32, size: Vec2, color: Color) {
let rotation = Mat2::from_angle(rotation);
let [tl, tr, br, bl] = self.rect_inner(size).map(|vec2| position + rotation * vec2);
let [tl, tr, br, bl] = rect_inner(size).map(|vec2| position + rotation * vec2);
self.linestrip_2d([tl, tr, br, bl, tl], color);
}
}

pub struct DrawCircle {
position: Vec3,
normal: Vec3,
radius: f32,
color: Color,
segments: usize,
}

impl DrawCircle {
pub fn segments(mut self, segments: usize) -> Self {
self.segments = segments;
self
}
}

impl Drop for DrawCircle {
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.)));
GIZMO.linestrip(positions, self.color);
}
}
pub struct DrawCircle2d {
position: Vec2,
radius: f32,
color: Color,
segments: usize,
}

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

fn rect_inner(&self, size: Vec2) -> [Vec2; 4] {
let half_size = size / 2.;
let tl = Vec2::new(-half_size.x, half_size.y);
let tr = Vec2::new(half_size.x, half_size.y);
let bl = Vec2::new(-half_size.x, -half_size.y);
let br = Vec2::new(half_size.x, -half_size.y);
[tl, tr, br, bl]
impl Drop for DrawCircle2d {
fn drop(&mut self) {
let positions = circle_inner(self.radius, self.segments).map(|vec2| (vec2 + self.position));
GIZMO.linestrip_2d(positions, self.color);
}
}

#[inline]
fn send_line(&self, [p0, p1]: [Vec3; 2], [c0, c1]: [Color; 2]) {
let _ = self.sender.send(SendItem::Single((
[p0.to_array(), p1.to_array()],
[c0.as_linear_rgba_f32(), c1.as_linear_rgba_f32()],
)));
pub struct DrawSphere {
position: Vec3,
radius: f32,
color: Color,
circle_segments: usize,
}

impl DrawSphere {
pub fn circle_segments(mut self, segments: usize) -> Self {
self.circle_segments = segments;
self
}
}

#[inline]
fn linelist(&self, list: impl IntoIterator<Item = Vec3>, color: Color) {
let iter = list
.into_iter()
.map(|p| p.to_array())
.zip(iter::repeat(color.as_linear_rgba_f32()));
let _ = self.sender.send(SendItem::List(iter.unzip()));
impl Drop for DrawSphere {
fn drop(&mut self) {
for axis in Vec3::AXES {
GIZMO
.circle(self.position, axis, self.radius, self.color)
.segments(self.circle_segments);
}
}
}

fn circle_inner(radius: f32, segments: usize) -> impl Iterator<Item = Vec2> {
(0..segments + 1).into_iter().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);
let tr = Vec2::new(half_size.x, half_size.y);
let bl = Vec2::new(-half_size.x, -half_size.y);
let br = Vec2::new(half_size.x, -half_size.y);
[tl, tr, br, bl]
}
14 changes: 7 additions & 7 deletions crates/bevy_debug_draw/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use bevy_ecs::{
world::{FromWorld, World},
};
use bevy_math::Mat4;
use bevy_pbr::MeshUniform;
use bevy_reflect::TypeUuid;
use bevy_render::{
mesh::Mesh,
Expand All @@ -17,20 +16,21 @@ use bevy_render::{
Extract, RenderApp, RenderStage,
};

#[cfg(feature = "bevy_pbr")]
use bevy_pbr::MeshUniform;
#[cfg(feature = "bevy_sprite")]
use bevy_sprite::Mesh2dHandle;
use bevy_sprite::{Mesh2dHandle, Mesh2dUniform};

use bevy_sprite::Mesh2dUniform;
use once_cell::sync::Lazy;

pub mod gizmos;
pub mod gizmo_draw;

#[cfg(feature = "bevy_sprite")]
mod pipeline_2d;
#[cfg(feature = "bevy_pbr")]
mod pipeline_3d;

use crate::gizmos::GizmoDraw;
use crate::gizmo_draw::GizmoDraw;

/// The `bevy_debug_draw` prelude.
pub mod prelude {
Expand Down Expand Up @@ -185,21 +185,21 @@ fn extract(
GizmoDrawMesh,
#[cfg(feature = "bevy_pbr")]
(
handle.clone(),
MeshUniform {
flags: 0,
transform,
inverse_transpose_model,
},
handle.clone(),
),
#[cfg(feature = "bevy_sprite")]
(
Mesh2dHandle(handle.clone()),
Mesh2dUniform {
flags: 0,
transform,
inverse_transpose_model,
},
Mesh2dHandle(handle.clone()),
),
)
}));
Expand Down
5 changes: 2 additions & 3 deletions examples/2d/2d_debug_draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,9 @@ fn system(time: Res<Time>) {
Vec2::splat(300.),
Color::BLACK,
);

// The circles have 32 line-segments by default.
GIZMO.circle_2d(Vec2::ZERO, 120., Color::BLACK);
// You may want to increase this for larger circles.
// GIZMOS.circle_segments = 64;
// GIZMOS.circle_2d(Vec2::ZERO, 300., Color::NAVY);
// GIZMOS.circle_segments = 32;
GIZMO.circle_2d(Vec2::ZERO, 300., Color::NAVY).segments(64);
}
12 changes: 7 additions & 5 deletions examples/3d/3d_debug_draw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ fn system(time: Res<Time>) {
GIZMO.ray(Vec3::new(1., f, 0.), vector, Color::BLUE);
}

// The circles have 32 line-segments by default.
// Circles have 32 line-segments by default.
GIZMO.circle(Vec3::ZERO, Vec3::Y, 3., Color::BLACK);
// You may want to increase this for larger circles or spheres.
// GIZMOS.circle_segments = 64;
// GIZMOS.circle(Vec3::ZERO, Vec3::Y, 3.1, Color::NAVY);
// GIZMOS.sphere(Vec3::ZERO, 3.2, Color::BLACK);
// GIZMOS.circle_segments = 32;
GIZMO
.circle(Vec3::ZERO, Vec3::Y, 3.1, Color::NAVY)
.segments(64);
GIZMO
.sphere(Vec3::ZERO, 3.2, Color::BLACK)
.circle_segments(64);
}

fn rotate_camera(mut query: Query<&mut Transform, With<Camera>>, time: Res<Time>) {
Expand Down

0 comments on commit 69c48e0

Please sign in to comment.