1
- use std:: { marker :: PhantomData , mem } ;
1
+ use std:: f32 :: consts :: TAU ;
2
2
3
3
use bevy_app:: { CoreStage , Plugin } ;
4
4
use bevy_asset:: { load_internal_asset, Assets , Handle , HandleUntyped } ;
5
5
use bevy_ecs:: {
6
6
prelude:: { Component , Entity } ,
7
7
query:: With ,
8
- system:: { Commands , Query , Res , ResMut , Resource , SystemParam } ,
8
+ system:: { Commands , Query , Res , ResMut , Resource } ,
9
9
} ;
10
- use bevy_math:: { Vec2 , Vec3 } ;
10
+ use bevy_math:: { vec3 , Quat , Vec2 , Vec3 } ;
11
11
use bevy_reflect:: TypeUuid ;
12
12
use bevy_render:: {
13
13
prelude:: { Color , Mesh , SpatialBundle } ,
@@ -16,20 +16,20 @@ use bevy_render::{
16
16
Extract , RenderApp , RenderStage ,
17
17
} ;
18
18
19
- #[ cfg( feature = "3d " ) ]
19
+ #[ cfg( feature = "bevy_pbr " ) ]
20
20
use bevy_pbr:: { NotShadowCaster , NotShadowReceiver } ;
21
- #[ cfg( feature = "2d " ) ]
21
+ #[ cfg( feature = "bevy_sprite " ) ]
22
22
use bevy_sprite:: Mesh2dHandle ;
23
23
24
- #[ cfg( feature = "2d " ) ]
24
+ #[ cfg( feature = "bevy_sprite " ) ]
25
25
pub mod pipeline_2d;
26
- #[ cfg( feature = "3d " ) ]
26
+ #[ cfg( feature = "bevy_pbr " ) ]
27
27
pub mod pipeline_3d;
28
28
29
29
/// The `bevy_debug_draw` prelude.
30
30
pub mod prelude {
31
31
#[ doc( hidden) ]
32
- pub use crate :: { DebugDraw , DebugDraw2d , DebugDrawConfig , DebugDrawPlugin } ;
32
+ pub use crate :: { DebugDraw , DebugDrawConfig , DebugDrawPlugin } ;
33
33
}
34
34
35
35
pub const SHADER_HANDLE : HandleUntyped =
@@ -39,13 +39,15 @@ pub struct DebugDrawPlugin;
39
39
40
40
impl Plugin for DebugDrawPlugin {
41
41
fn build ( & self , app : & mut bevy_app:: App ) {
42
- app. init_resource :: < DebugDrawResource > ( )
42
+ load_internal_asset ! ( app, SHADER_HANDLE , "debuglines.wgsl" , Shader :: from_wgsl) ;
43
+
44
+ app. init_resource :: < DebugDraw > ( )
43
45
. init_resource :: < DebugDrawConfig > ( )
44
46
. add_system_to_stage ( CoreStage :: PostUpdate , update)
45
47
. sub_app_mut ( RenderApp )
46
48
. add_system_to_stage ( RenderStage :: Extract , extract) ;
47
49
48
- #[ cfg( feature = "2d " ) ]
50
+ #[ cfg( feature = "bevy_sprite " ) ]
49
51
{
50
52
use bevy_core_pipeline:: core_2d:: Transparent2d ;
51
53
use pipeline_2d:: * ;
@@ -57,7 +59,7 @@ impl Plugin for DebugDrawPlugin {
57
59
. add_system_to_stage ( RenderStage :: Queue , queue) ;
58
60
}
59
61
60
- #[ cfg( feature = "3d " ) ]
62
+ #[ cfg( feature = "bevy_pbr " ) ]
61
63
{
62
64
use bevy_core_pipeline:: core_3d:: Opaque3d ;
63
65
use pipeline_3d:: * ;
@@ -68,13 +70,15 @@ impl Plugin for DebugDrawPlugin {
68
70
. init_resource :: < SpecializedMeshPipelines < DebugLinePipeline > > ( )
69
71
. add_system_to_stage ( RenderStage :: Queue , queue) ;
70
72
}
71
-
72
- load_internal_asset ! ( app, SHADER_HANDLE , "debuglines.wgsl" , Shader :: from_wgsl) ;
73
73
}
74
74
}
75
75
76
76
#[ derive( Resource , Clone , Copy ) ]
77
77
pub struct DebugDrawConfig {
78
+ /// Whether debug drawing should be shown.
79
+ ///
80
+ /// Defaults to `true`.
81
+ pub enabled : bool ,
78
82
/// Whether debug drawing should ignore depth and draw on top of everything else.
79
83
///
80
84
/// Defaults to `true`.
@@ -84,118 +88,188 @@ pub struct DebugDrawConfig {
84
88
impl Default for DebugDrawConfig {
85
89
fn default ( ) -> Self {
86
90
Self {
91
+ enabled : true ,
87
92
always_on_top : true ,
88
93
}
89
94
}
90
95
}
91
96
92
- #[ derive( Resource , Default ) ]
93
- pub struct DebugDrawResource {
97
+ #[ derive( Resource ) ]
98
+ pub struct DebugDraw {
94
99
positions : Vec < [ f32 ; 3 ] > ,
95
100
colors : Vec < [ f32 ; 4 ] > ,
96
101
mesh_handle : Option < Handle < Mesh > > ,
102
+ /// The amount of line segments to use when drawing a circle.
103
+ ///
104
+ /// Defaults to `24`.
105
+ pub circle_segments : u32 ,
106
+ }
107
+
108
+ impl Default for DebugDraw {
109
+ fn default ( ) -> Self {
110
+ DebugDraw {
111
+ positions : Vec :: new ( ) ,
112
+ colors : Vec :: new ( ) ,
113
+ mesh_handle : None ,
114
+ circle_segments : 24 ,
115
+ }
116
+ }
97
117
}
98
118
99
- impl DebugDrawResource {
119
+ impl DebugDraw {
100
120
/// Draw a line from `start` to `end`.
101
- fn line ( & mut self , start : Vec3 , end : Vec3 , color : Color ) {
102
- self . positions
103
- . extend_from_slice ( & [ start. to_array ( ) , end. to_array ( ) ] ) ;
121
+ pub fn line ( & mut self , start : Vec3 , end : Vec3 , color : Color ) {
122
+ self . positions . extend ( [ start. to_array ( ) , end. to_array ( ) ] ) ;
104
123
let color = color. as_linear_rgba_f32 ( ) ;
105
- self . colors . extend_from_slice ( & [ color, color] ) ;
124
+ self . colors . extend ( [ color, color] ) ;
106
125
}
107
126
108
127
/// Draw a line from `start` to `start + vector`.
109
- fn ray ( & mut self , start : Vec3 , vector : Vec3 , color : Color ) {
128
+ pub fn ray ( & mut self , start : Vec3 , vector : Vec3 , color : Color ) {
110
129
self . line ( start, start + vector, color) ;
111
130
}
112
131
113
- fn clear ( & mut self ) {
114
- self . positions . clear ( ) ;
115
- self . colors . clear ( ) ;
116
- }
132
+ /// Draw a circle at `position` with the flat side facing `normal`.
133
+ pub fn circle ( & mut self , position : Vec3 , normal : Vec3 , radius : f32 , color : Color ) {
134
+ let rotation = Quat :: from_rotation_arc ( Vec3 :: Z , normal) ;
135
+ self . positions
136
+ . extend ( ( 0 ..self . circle_segments ) . into_iter ( ) . flat_map ( |i| {
137
+ let angle = i as f32 * TAU / self . circle_segments as f32 ;
117
138
118
- fn update_mesh ( & mut self , mesh : & mut Mesh ) {
119
- mesh. insert_attribute ( Mesh :: ATTRIBUTE_POSITION , mem:: take ( & mut self . positions ) ) ;
120
- mesh. insert_attribute ( Mesh :: ATTRIBUTE_COLOR , mem:: take ( & mut self . colors ) ) ;
121
- }
122
- }
139
+ let ( y, x) = angle. sin_cos ( ) ;
140
+ let start = rotation * Vec3 :: new ( x, y, 0. ) * radius + position;
123
141
124
- #[ derive( SystemParam ) ]
125
- pub struct DebugDraw < ' w , ' s > {
126
- debug_draw : ResMut < ' w , DebugDrawResource > ,
127
- #[ system_param( ignore) ]
128
- marker : PhantomData < & ' s ( ) > ,
129
- }
142
+ let ( y, x) = ( angle + TAU / self . circle_segments as f32 ) . sin_cos ( ) ;
143
+ let end = rotation * Vec3 :: new ( x, y, 0. ) * radius + position;
130
144
131
- impl < ' w , ' s > DebugDraw < ' w , ' s > {
132
- /// Draw a line from `start` to `end`.
133
- pub fn line ( & mut self , start : Vec3 , end : Vec3 , color : Color ) {
134
- self . debug_draw . line ( start, end, color) ;
145
+ [ start. to_array ( ) , end. to_array ( ) ]
146
+ } ) ) ;
147
+
148
+ self . colors . extend (
149
+ std:: iter:: repeat ( color. as_linear_rgba_f32 ( ) ) . take ( self . circle_segments as usize * 2 ) ,
150
+ ) ;
135
151
}
136
152
137
- /// Draw a line from `start` to `start + vector`.
138
- pub fn ray ( & mut self , start : Vec3 , vector : Vec3 , color : Color ) {
139
- self . debug_draw . ray ( start, vector, color) ;
153
+ /// Draw a sphere.
154
+ pub fn sphere ( & mut self , position : Vec3 , radius : f32 , color : Color ) {
155
+ self . circle ( position, Vec3 :: X , radius, color) ;
156
+ self . circle ( position, Vec3 :: Y , radius, color) ;
157
+ self . circle ( position, Vec3 :: Z , radius, color) ;
140
158
}
141
159
142
- pub fn clear ( & mut self ) {
143
- self . debug_draw . clear ( ) ;
160
+ /// Draw a rectangle.
161
+ pub fn rect ( & mut self , position : Vec3 , rotation : Quat , size : Vec2 , color : Color ) {
162
+ let half_size = size / 2. ;
163
+ let tl = ( position + rotation * vec3 ( -half_size. x , half_size. y , 0. ) ) . to_array ( ) ;
164
+ let tr = ( position + rotation * vec3 ( half_size. x , half_size. y , 0. ) ) . to_array ( ) ;
165
+ let bl = ( position + rotation * vec3 ( -half_size. x , -half_size. y , 0. ) ) . to_array ( ) ;
166
+ let br = ( position + rotation * vec3 ( half_size. x , -half_size. y , 0. ) ) . to_array ( ) ;
167
+ self . positions . extend ( [ tl, tr, tr, br, br, bl, bl, tl] ) ;
168
+ self . colors
169
+ . extend ( std:: iter:: repeat ( color. as_linear_rgba_f32 ( ) ) . take ( 8 ) )
144
170
}
145
- }
146
171
147
- #[ derive( SystemParam ) ]
148
- pub struct DebugDraw2d < ' w , ' s > {
149
- debug_draw : ResMut < ' w , DebugDrawResource > ,
150
- #[ system_param( ignore) ]
151
- marker : PhantomData < & ' s ( ) > ,
152
- }
172
+ /// Draw a box.
173
+ pub fn cuboid ( & mut self , position : Vec3 , rotation : Quat , size : Vec3 , color : Color ) {
174
+ let half_size = size / 2. ;
175
+ // Front
176
+ let tlf = ( position + rotation * vec3 ( -half_size. x , half_size. y , half_size. z ) ) . to_array ( ) ;
177
+ let trf = ( position + rotation * vec3 ( half_size. x , half_size. y , half_size. z ) ) . to_array ( ) ;
178
+ let blf = ( position + rotation * vec3 ( -half_size. x , -half_size. y , half_size. z ) ) . to_array ( ) ;
179
+ let brf = ( position + rotation * vec3 ( half_size. x , -half_size. y , half_size. z ) ) . to_array ( ) ;
180
+ // Back
181
+ let tlb = ( position + rotation * vec3 ( -half_size. x , half_size. y , -half_size. z ) ) . to_array ( ) ;
182
+ let trb = ( position + rotation * vec3 ( half_size. x , half_size. y , -half_size. z ) ) . to_array ( ) ;
183
+ let blb = ( position + rotation * vec3 ( -half_size. x , -half_size. y , -half_size. z ) ) . to_array ( ) ;
184
+ let brb = ( position + rotation * vec3 ( half_size. x , -half_size. y , -half_size. z ) ) . to_array ( ) ;
185
+ self . positions . extend ( [
186
+ tlf, trf, trf, brf, brf, blf, blf, tlf, // Front
187
+ tlb, trb, trb, brb, brb, blb, blb, tlb, // Back
188
+ tlf, tlb, trf, trb, brf, brb, blf, blb, // Front to back
189
+ ] ) ;
190
+ self . colors
191
+ . extend ( std:: iter:: repeat ( color. as_linear_rgba_f32 ( ) ) . take ( 24 ) )
192
+ }
193
+
194
+ /// Draw an axis-aligned box.
195
+ pub fn aab ( & mut self , position : Vec3 , size : Vec3 , color : Color ) {
196
+ self . cuboid ( position, Quat :: IDENTITY , size, color) ;
197
+ }
153
198
154
- impl < ' w , ' s > DebugDraw2d < ' w , ' s > {
155
199
/// Draw a line from `start` to `end`.
156
- pub fn line ( & mut self , start : Vec2 , end : Vec2 , color : Color ) {
157
- self . debug_draw
158
- . line ( start. extend ( 0. ) , end. extend ( 0. ) , color) ;
200
+ pub fn line_2d ( & mut self , start : Vec2 , end : Vec2 , color : Color ) {
201
+ self . line ( start. extend ( 0. ) , end. extend ( 0. ) , color) ;
159
202
}
160
203
161
204
/// Draw a line from `start` to `start + vector`.
162
- pub fn ray ( & mut self , start : Vec2 , vector : Vec2 , color : Color ) {
163
- self . debug_draw
164
- . ray ( start. extend ( 0. ) , vector. extend ( 0. ) , color) ;
205
+ pub fn ray_2d ( & mut self , start : Vec2 , vector : Vec2 , color : Color ) {
206
+ self . ray ( start. extend ( 0. ) , vector. extend ( 0. ) , color) ;
207
+ }
208
+
209
+ pub fn circle_2d ( & mut self , position : Vec2 , radius : f32 , color : Color ) {
210
+ self . circle ( position. extend ( 0. ) , Vec3 :: Z , radius, color) ;
211
+ }
212
+
213
+ /// Draw a rectangle at `position`.
214
+ pub fn rect_2d ( & mut self , position : Vec2 , rotation : f32 , size : Vec2 , color : Color ) {
215
+ self . rect (
216
+ position. extend ( 0. ) ,
217
+ Quat :: from_rotation_z ( rotation) ,
218
+ size,
219
+ color,
220
+ ) ;
165
221
}
166
222
167
223
pub fn clear ( & mut self ) {
168
- self . debug_draw . clear ( ) ;
224
+ self . positions . clear ( ) ;
225
+ self . colors . clear ( ) ;
226
+ }
227
+
228
+ pub fn update_mesh ( & mut self , mesh : & mut Mesh ) {
229
+ mesh. insert_attribute (
230
+ Mesh :: ATTRIBUTE_POSITION ,
231
+ std:: mem:: take ( & mut self . positions ) ,
232
+ ) ;
233
+ mesh. insert_attribute ( Mesh :: ATTRIBUTE_COLOR , std:: mem:: take ( & mut self . colors ) ) ;
169
234
}
170
235
}
171
236
172
237
#[ derive( Component ) ]
173
238
pub struct DebugDrawMesh ;
174
239
175
240
pub ( crate ) fn update (
176
- mut draw : ResMut < DebugDrawResource > ,
241
+ config : Res < DebugDrawConfig > ,
242
+ mut debug_draw : ResMut < DebugDraw > ,
177
243
mut meshes : ResMut < Assets < Mesh > > ,
178
244
mut commands : Commands ,
179
245
) {
180
- if let Some ( mut mesh) = draw
246
+ if let Some ( mut mesh) = debug_draw
181
247
. mesh_handle
182
248
. as_ref ( )
183
249
. and_then ( |handle| meshes. get_mut ( handle) )
184
250
{
185
- draw. update_mesh ( & mut mesh) ;
186
- } else {
251
+ if config. enabled {
252
+ debug_draw. update_mesh ( & mut mesh) ;
253
+ } else {
254
+ debug_draw. clear ( ) ;
255
+ mesh. remove_attribute ( Mesh :: ATTRIBUTE_POSITION ) ;
256
+ mesh. remove_attribute ( Mesh :: ATTRIBUTE_COLOR ) ;
257
+ }
258
+ } else if config. enabled {
187
259
let mut mesh = Mesh :: new ( PrimitiveTopology :: LineList ) ;
188
- draw . update_mesh ( & mut mesh) ;
260
+ debug_draw . update_mesh ( & mut mesh) ;
189
261
let mesh_handle = meshes. add ( mesh) ;
190
262
commands. spawn ( (
191
263
SpatialBundle :: VISIBLE_IDENTITY ,
192
264
DebugDrawMesh ,
193
- #[ cfg ( feature = "3d " ) ]
265
+ #[ cfg ( feature = "bevy_pbr " ) ]
194
266
( mesh_handle. clone_weak ( ) , NotShadowCaster , NotShadowReceiver ) ,
195
- #[ cfg ( feature = "2d " ) ]
267
+ #[ cfg ( feature = "bevy_sprite " ) ]
196
268
Mesh2dHandle ( mesh_handle. clone_weak ( ) ) ,
197
269
) ) ;
198
- draw. mesh_handle = Some ( mesh_handle) ;
270
+ debug_draw. mesh_handle = Some ( mesh_handle) ;
271
+ } else {
272
+ debug_draw. clear ( ) ;
199
273
}
200
274
}
201
275
0 commit comments