Skip to content

Commit a2422c8

Browse files
committed
gizmo wip
1 parent bd2a6f3 commit a2422c8

File tree

8 files changed

+382
-160
lines changed

8 files changed

+382
-160
lines changed

crates/bevy_debug_draw/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,6 @@ bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" }
2121
bevy_core = { path = "../bevy_core", version = "0.9.0-dev" }
2222
bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev" }
2323
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.9.0-dev" }
24+
# Other
25+
once_cell = "1.16"
26+
crossbeam-channel = "0.5"

crates/bevy_debug_draw/src/gizmos.rs

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
use std::{f32::consts::TAU, iter};
2+
3+
use bevy_math::{Mat2, Quat, Vec2, Vec3};
4+
use bevy_render::prelude::Color;
5+
use crossbeam_channel::{unbounded, Receiver, Sender};
6+
7+
use crate::SendItem;
8+
9+
pub struct Gizmos {
10+
sender: Sender<SendItem>,
11+
pub(crate) receiver: Receiver<SendItem>,
12+
circle_segments: usize,
13+
}
14+
15+
impl Gizmos {
16+
pub(crate) fn new() -> Self {
17+
let (sender, receiver) = unbounded();
18+
Gizmos {
19+
sender,
20+
receiver,
21+
circle_segments: 32,
22+
}
23+
}
24+
}
25+
26+
impl Gizmos {
27+
/// Draw a line from `start` to `end`.
28+
#[inline]
29+
pub fn line(&self, start: Vec3, end: Vec3, color: Color) {
30+
self.send_line([start, end], [color, color]);
31+
}
32+
33+
/// Draw a line from `start` to `end`.
34+
#[inline]
35+
pub fn line_gradient(&self, start: Vec3, end: Vec3, start_color: Color, end_color: Color) {
36+
self.send_line([start, end], [start_color, end_color]);
37+
}
38+
39+
/// Draw a line from `start` to `start + vector`.
40+
#[inline]
41+
pub fn ray(&self, start: Vec3, vector: Vec3, color: Color) {
42+
self.line(start, start + vector, color);
43+
}
44+
45+
/// Draw a line from `start` to `start + vector`.
46+
#[inline]
47+
pub fn ray_gradient(&self, start: Vec3, vector: Vec3, start_color: Color, end_color: Color) {
48+
self.line_gradient(start, start + vector, start_color, end_color);
49+
}
50+
51+
#[inline]
52+
pub fn linestrip(&self, positions: impl IntoIterator<Item = Vec3>, color: Color) {
53+
self.linestrip_gradient(positions.into_iter().zip(iter::repeat(color)));
54+
}
55+
56+
#[inline]
57+
pub fn linestrip_gradient(&self, strip: impl IntoIterator<Item = (Vec3, Color)>) {
58+
let iter = strip
59+
.into_iter()
60+
.map(|(p, c)| (p.to_array(), c.as_linear_rgba_f32()));
61+
let _ = self.sender.send(SendItem::Strip(iter.unzip()));
62+
}
63+
64+
/// Draw a circle at `position` with the flat side facing `normal`.
65+
#[inline]
66+
pub fn circle(&self, position: Vec3, normal: Vec3, radius: f32, color: Color) {
67+
let rotation = Quat::from_rotation_arc(Vec3::Z, normal);
68+
69+
let positions = self
70+
.circle_inner(radius)
71+
.map(|vec2| (position + rotation * vec2.extend(0.)));
72+
73+
self.linestrip(positions, color);
74+
}
75+
76+
/// Draw a sphere.
77+
#[inline]
78+
pub fn sphere(&self, position: Vec3, radius: f32, color: Color) {
79+
self.circle(position, Vec3::X, radius, color);
80+
self.circle(position, Vec3::Y, radius, color);
81+
self.circle(position, Vec3::Z, radius, color);
82+
}
83+
84+
/// Draw a rectangle.
85+
#[inline]
86+
pub fn rect(&self, position: Vec3, rotation: Quat, size: Vec2, color: Color) {
87+
let positions = self
88+
.rect_inner(size)
89+
.map(|vec2| position + rotation * vec2.extend(0.));
90+
self.linestrip(positions, color);
91+
}
92+
93+
/// Draw a box.
94+
#[inline]
95+
pub fn cuboid(&self, position: Vec3, rotation: Quat, size: Vec3, color: Color) {
96+
let half_size = size / 2.;
97+
// Front
98+
let tlf = position + rotation * Vec3::new(-half_size.x, half_size.y, half_size.z);
99+
let trf = position + rotation * Vec3::new(half_size.x, half_size.y, half_size.z);
100+
let blf = position + rotation * Vec3::new(-half_size.x, -half_size.y, half_size.z);
101+
let brf = position + rotation * Vec3::new(half_size.x, -half_size.y, half_size.z);
102+
// Back
103+
let tlb = position + rotation * Vec3::new(-half_size.x, half_size.y, -half_size.z);
104+
let trb = position + rotation * Vec3::new(half_size.x, half_size.y, -half_size.z);
105+
let blb = position + rotation * Vec3::new(-half_size.x, -half_size.y, -half_size.z);
106+
let brb = position + rotation * Vec3::new(half_size.x, -half_size.y, -half_size.z);
107+
108+
let positions = [
109+
tlf, trf, trf, brf, brf, blf, blf, tlf, // Front
110+
tlb, trb, trb, brb, brb, blb, blb, tlb, // Back
111+
tlf, tlb, trf, trb, brf, brb, blf, blb, // Front to back
112+
];
113+
self.linelist(positions, color);
114+
}
115+
116+
/// Draw a line from `start` to `end`.
117+
#[inline]
118+
pub fn line_2d(&self, start: Vec2, end: Vec2, color: Color) {
119+
self.line(start.extend(0.), end.extend(0.), color);
120+
}
121+
122+
/// Draw a line from `start` to `end`.
123+
#[inline]
124+
pub fn line_gradient_2d(&self, start: Vec2, end: Vec2, start_color: Color, end_color: Color) {
125+
self.line_gradient(start.extend(0.), end.extend(0.), start_color, end_color);
126+
}
127+
128+
#[inline]
129+
pub fn linestrip_2d(&self, positions: impl IntoIterator<Item = Vec2>, color: Color) {
130+
self.linestrip(positions.into_iter().map(|vec2| vec2.extend(0.)), color);
131+
}
132+
133+
#[inline]
134+
pub fn linestrip_gradient_2d(&self, positions: impl IntoIterator<Item = (Vec2, Color)>) {
135+
self.linestrip_gradient(
136+
positions
137+
.into_iter()
138+
.map(|(vec2, color)| (vec2.extend(0.), color)),
139+
);
140+
}
141+
142+
/// Draw a line from `start` to `start + vector`.
143+
#[inline]
144+
pub fn ray_2d(&self, start: Vec2, vector: Vec2, color: Color) {
145+
self.line_2d(start, start + vector, color);
146+
}
147+
148+
/// Draw a line from `start` to `start + vector`.
149+
#[inline]
150+
pub fn ray_gradient_2d(&self, start: Vec2, vector: Vec2, start_color: Color, end_color: Color) {
151+
self.line_gradient_2d(start, start + vector, start_color, end_color);
152+
}
153+
154+
// Draw a circle.
155+
#[inline]
156+
pub fn circle_2d(&self, position: Vec2, radius: f32, color: Color) {
157+
let positions = self.circle_inner(radius).map(|vec2| (vec2 + position));
158+
self.linestrip_2d(positions, color);
159+
}
160+
161+
/// Draw a rectangle.
162+
#[inline]
163+
pub fn rect_2d(&self, position: Vec2, rotation: f32, size: Vec2, color: Color) {
164+
let rotation = Mat2::from_angle(rotation);
165+
let positions = self.rect_inner(size).map(|vec2| position + rotation * vec2);
166+
self.linestrip_2d(positions, color);
167+
}
168+
169+
fn circle_inner(&self, radius: f32) -> impl Iterator<Item = Vec2> {
170+
let circle_segments = self.circle_segments;
171+
(0..(circle_segments + 1)).into_iter().map(move |i| {
172+
let angle = i as f32 * TAU / circle_segments as f32;
173+
Vec2::from(angle.sin_cos()) * radius
174+
})
175+
}
176+
177+
fn rect_inner(&self, size: Vec2) -> impl Iterator<Item = Vec2> {
178+
let half_size = size / 2.;
179+
let tl = Vec2::new(-half_size.x, half_size.y);
180+
let tr = Vec2::new(half_size.x, half_size.y);
181+
let bl = Vec2::new(-half_size.x, -half_size.y);
182+
let br = Vec2::new(half_size.x, -half_size.y);
183+
184+
[tl, tr, br, bl, tl].into_iter()
185+
}
186+
187+
#[inline]
188+
fn send_line(&self, [p0, p1]: [Vec3; 2], [c0, c1]: [Color; 2]) {
189+
let _ = self.sender.send(SendItem::Single((
190+
[p0.to_array(), p1.to_array()],
191+
[c0.as_linear_rgba_f32(), c1.as_linear_rgba_f32()],
192+
)));
193+
}
194+
195+
#[inline]
196+
fn linelist(&self, list: impl IntoIterator<Item = Vec3>, color: Color) {
197+
let iter = list
198+
.into_iter()
199+
.map(|p| p.to_array())
200+
.zip(iter::repeat(color.as_linear_rgba_f32()));
201+
let _ = self.sender.send(SendItem::List(iter.unzip()));
202+
}
203+
}

0 commit comments

Comments
 (0)