Skip to content

Commit 7d8e1e5

Browse files
committed
sordid
1 parent c4e791d commit 7d8e1e5

File tree

10 files changed

+622
-2
lines changed

10 files changed

+622
-2
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ default = [
3737
"vorbis",
3838
"x11",
3939
"filesystem_watcher",
40+
"bevy_debug_draw",
4041
]
4142

4243
# Force dynamic linking, which improves iterative compile times
@@ -68,6 +69,7 @@ bevy_sprite = ["bevy_internal/bevy_sprite"]
6869
bevy_text = ["bevy_internal/bevy_text"]
6970
bevy_ui = ["bevy_internal/bevy_ui"]
7071
bevy_winit = ["bevy_internal/bevy_winit"]
72+
bevy_debug_draw = ["bevy_internal/bevy_debug_draw"]
7173

7274
# Tracing features
7375
trace_chrome = ["trace", "bevy_internal/trace_chrome"]

crates/bevy_debug_draw/Cargo.toml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
[package]
2+
name = "bevy_debug_draw"
3+
version = "0.9.0-dev"
4+
edition = "2021"
5+
description = "Provides debug drawing for Bevy Engine"
6+
homepage = "https://bevyengine.org"
7+
repository = "https://github.com/bevyengine/bevy"
8+
license = "MIT OR Apache-2.0"
9+
keywords = ["bevy"]
10+
11+
[features]
12+
default = ["2d", "3d"]
13+
14+
3d = ["bevy_pbr"]
15+
2d = ["bevy_sprite"]
16+
17+
[dependencies]
18+
bevy_pbr = { path = "../bevy_pbr", version = "0.9.0-dev", optional = true }
19+
bevy_sprite = { path = "../bevy_sprite", version = "0.9.0-dev", optional = true }
20+
bevy_app = { path = "../bevy_app", version = "0.9.0-dev" }
21+
bevy_ecs = { path = "../bevy_ecs", version = "0.9.0-dev" }
22+
bevy_transform = { path = "../bevy_transform", version = "0.9.0-dev" }
23+
bevy_math = { path = "../bevy_math", version = "0.9.0-dev" }
24+
bevy_asset = { path = "../bevy_asset", version = "0.9.0-dev" }
25+
bevy_render = { path = "../bevy_render", version = "0.9.0-dev" }
26+
bevy_log = { path = "../bevy_log", version = "0.9.0-dev" }
27+
bevy_time = { path = "../bevy_time", version = "0.9.0-dev" }
28+
bevy_utils = { path = "../bevy_utils", version = "0.9.0-dev" }
29+
bevy_core = { path = "../bevy_core", version = "0.9.0-dev" }
30+
bevy_reflect = { path = "../bevy_reflect", version = "0.9.0-dev" }
31+
bevy_core_pipeline = { path = "../bevy_core_pipeline", version = "0.9.0-dev" }
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#ifdef DEBUG_LINES_3D
2+
#import bevy_pbr::mesh_view_bindings
3+
#else
4+
#import bevy_sprite::mesh2d_view_bindings
5+
#endif
6+
7+
struct VertexInput {
8+
@location(0) pos: vec3<f32>,
9+
@location(1) color: vec4<f32>,
10+
}
11+
12+
struct VertexOutput {
13+
@builtin(position) pos: vec4<f32>,
14+
@location(0) color: vec4<f32>,
15+
}
16+
17+
struct FragmentOutput {
18+
@builtin(frag_depth) depth: f32,
19+
@location(0) color: vec4<f32>,
20+
}
21+
22+
@vertex
23+
fn vertex(in: VertexInput) -> VertexOutput {
24+
var out: VertexOutput;
25+
26+
out.pos = view.view_proj * vec4<f32>(in.pos, 1.0);
27+
out.color = in.color;
28+
29+
return out;
30+
}
31+
32+
@fragment
33+
fn fragment(in: VertexOutput) -> FragmentOutput {
34+
var out: FragmentOutput;
35+
36+
#ifdef DEPTH_TEST_ENABLED
37+
out.depth = in.pos.z;
38+
#else
39+
out.depth = 1.0;
40+
#endif
41+
42+
out.color = in.color;
43+
return out;
44+
}

crates/bevy_debug_draw/src/lib.rs

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
use std::{marker::PhantomData, mem};
2+
3+
use bevy_app::{CoreStage, Plugin};
4+
use bevy_asset::{load_internal_asset, Assets, Handle, HandleUntyped};
5+
use bevy_ecs::{
6+
prelude::{Component, Entity},
7+
query::With,
8+
system::{Commands, Query, Res, ResMut, Resource, SystemParam},
9+
};
10+
use bevy_math::{Vec2, Vec3};
11+
use bevy_reflect::TypeUuid;
12+
use bevy_render::{
13+
prelude::{Color, Mesh, SpatialBundle},
14+
render_phase::AddRenderCommand,
15+
render_resource::{PrimitiveTopology, Shader, SpecializedMeshPipelines},
16+
Extract, RenderApp, RenderStage,
17+
};
18+
19+
#[cfg(feature = "3d")]
20+
use bevy_pbr::{NotShadowCaster, NotShadowReceiver};
21+
#[cfg(feature = "2d")]
22+
use bevy_sprite::Mesh2dHandle;
23+
24+
#[cfg(feature = "2d")]
25+
pub mod pipeline_2d;
26+
#[cfg(feature = "3d")]
27+
pub mod pipeline_3d;
28+
29+
/// The `bevy_debug_draw` prelude.
30+
pub mod prelude {
31+
#[doc(hidden)]
32+
pub use crate::{DebugDraw, DebugDraw2d, DebugDrawConfig, DebugDrawPlugin};
33+
}
34+
35+
pub const SHADER_HANDLE: HandleUntyped =
36+
HandleUntyped::weak_from_u64(Shader::TYPE_UUID, 7414812689238026784);
37+
38+
pub struct DebugDrawPlugin;
39+
40+
impl Plugin for DebugDrawPlugin {
41+
fn build(&self, app: &mut bevy_app::App) {
42+
app.init_resource::<DebugDrawResource>()
43+
.init_resource::<DebugDrawConfig>()
44+
.add_system_to_stage(CoreStage::PostUpdate, update)
45+
.sub_app_mut(RenderApp)
46+
.add_system_to_stage(RenderStage::Extract, extract);
47+
48+
#[cfg(feature = "2d")]
49+
{
50+
use bevy_core_pipeline::core_2d::Transparent2d;
51+
use pipeline_2d::*;
52+
53+
app.sub_app_mut(RenderApp)
54+
.add_render_command::<Transparent2d, DrawDebugLines>()
55+
.init_resource::<DebugLinePipeline>()
56+
.init_resource::<SpecializedMeshPipelines<DebugLinePipeline>>()
57+
.add_system_to_stage(RenderStage::Queue, queue);
58+
}
59+
60+
#[cfg(feature = "3d")]
61+
{
62+
use bevy_core_pipeline::core_3d::Opaque3d;
63+
use pipeline_3d::*;
64+
65+
app.sub_app_mut(RenderApp)
66+
.add_render_command::<Opaque3d, DrawDebugLines>()
67+
.init_resource::<DebugLinePipeline>()
68+
.init_resource::<SpecializedMeshPipelines<DebugLinePipeline>>()
69+
.add_system_to_stage(RenderStage::Queue, queue);
70+
}
71+
72+
load_internal_asset!(app, SHADER_HANDLE, "debuglines.wgsl", Shader::from_wgsl);
73+
}
74+
}
75+
76+
#[derive(Resource, Clone, Copy)]
77+
pub struct DebugDrawConfig {
78+
/// Whether debug drawing should ignore depth and draw on top of everything else.
79+
///
80+
/// Defaults to `true`.
81+
pub always_on_top: bool,
82+
}
83+
84+
impl Default for DebugDrawConfig {
85+
fn default() -> Self {
86+
Self {
87+
always_on_top: true,
88+
}
89+
}
90+
}
91+
92+
#[derive(Resource, Default)]
93+
pub struct DebugDrawResource {
94+
positions: Vec<[f32; 3]>,
95+
colors: Vec<[f32; 4]>,
96+
mesh_handle: Option<Handle<Mesh>>,
97+
}
98+
99+
impl DebugDrawResource {
100+
/// 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()]);
104+
let color = color.as_linear_rgba_f32();
105+
self.colors.extend_from_slice(&[color, color]);
106+
}
107+
108+
/// Draw a line from `start` to `start + vector`.
109+
fn ray(&mut self, start: Vec3, vector: Vec3, color: Color) {
110+
self.line(start, start + vector, color);
111+
}
112+
113+
fn clear(&mut self) {
114+
self.positions.clear();
115+
self.colors.clear();
116+
}
117+
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+
}
123+
124+
#[derive(SystemParam)]
125+
pub struct DebugDraw<'w, 's> {
126+
debug_draw: ResMut<'w, DebugDrawResource>,
127+
#[system_param(ignore)]
128+
marker: PhantomData<&'s ()>,
129+
}
130+
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);
135+
}
136+
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);
140+
}
141+
142+
pub fn clear(&mut self) {
143+
self.debug_draw.clear();
144+
}
145+
}
146+
147+
#[derive(SystemParam)]
148+
pub struct DebugDraw2d<'w, 's> {
149+
debug_draw: ResMut<'w, DebugDrawResource>,
150+
#[system_param(ignore)]
151+
marker: PhantomData<&'s ()>,
152+
}
153+
154+
impl<'w, 's> DebugDraw2d<'w, 's> {
155+
/// 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);
159+
}
160+
161+
/// 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);
165+
}
166+
167+
pub fn clear(&mut self) {
168+
self.debug_draw.clear();
169+
}
170+
}
171+
172+
#[derive(Component)]
173+
pub struct DebugDrawMesh;
174+
175+
pub(crate) fn update(
176+
mut draw: ResMut<DebugDrawResource>,
177+
mut meshes: ResMut<Assets<Mesh>>,
178+
mut commands: Commands,
179+
) {
180+
if let Some(mut mesh) = draw
181+
.mesh_handle
182+
.as_ref()
183+
.and_then(|handle| meshes.get_mut(handle))
184+
{
185+
draw.update_mesh(&mut mesh);
186+
} else {
187+
let mut mesh = Mesh::new(PrimitiveTopology::LineList);
188+
draw.update_mesh(&mut mesh);
189+
let mesh_handle = meshes.add(mesh);
190+
commands.spawn((
191+
SpatialBundle::VISIBLE_IDENTITY,
192+
DebugDrawMesh,
193+
#[cfg(feature = "3d")]
194+
(mesh_handle.clone_weak(), NotShadowCaster, NotShadowReceiver),
195+
#[cfg(feature = "2d")]
196+
Mesh2dHandle(mesh_handle.clone_weak()),
197+
));
198+
draw.mesh_handle = Some(mesh_handle);
199+
}
200+
}
201+
202+
/// Move the DebugDrawMesh marker Component to the render context.
203+
pub(crate) fn extract(
204+
mut commands: Commands,
205+
query: Extract<Query<Entity, With<DebugDrawMesh>>>,
206+
config: Extract<Res<DebugDrawConfig>>,
207+
) {
208+
for entity in &query {
209+
commands.get_or_spawn(entity).insert(DebugDrawMesh);
210+
}
211+
212+
if config.is_changed() {
213+
commands.insert_resource(**config);
214+
}
215+
}

0 commit comments

Comments
 (0)