use crate::plugin::RapierContext;
use bevy::prelude::*;
use bevy::transform::TransformSystem;
use rapier::math::{Point, Real};
use rapier::pipeline::{DebugRenderBackend, DebugRenderObject, DebugRenderPipeline};
pub use rapier::pipeline::{DebugRenderMode, DebugRenderStyle};
use std::fmt::Debug;
#[derive(Copy, Clone, Component, PartialEq, Debug)]
pub struct ColliderDebugColor(pub Color);
pub struct RapierDebugRenderPlugin {
pub enabled: bool,
pub style: DebugRenderStyle,
pub mode: DebugRenderMode,
}
#[allow(clippy::derivable_impls)] impl Default for RapierDebugRenderPlugin {
#[cfg(feature = "dim2")]
fn default() -> Self {
Self {
enabled: true,
style: DebugRenderStyle {
rigid_body_axes_length: 20.0,
..Default::default()
},
mode: DebugRenderMode::default(),
}
}
#[cfg(feature = "dim3")]
fn default() -> Self {
Self {
enabled: true,
style: DebugRenderStyle::default(),
mode: DebugRenderMode::default(),
}
}
}
impl RapierDebugRenderPlugin {
pub fn disabled(mut self) -> Self {
self.enabled = false;
self
}
}
#[derive(Resource, Reflect)]
#[reflect(Resource)]
pub struct DebugRenderContext {
pub enabled: bool,
#[reflect(ignore)]
pub pipeline: DebugRenderPipeline,
}
impl Default for DebugRenderContext {
fn default() -> Self {
Self {
enabled: true,
pipeline: DebugRenderPipeline::default(),
}
}
}
impl Plugin for RapierDebugRenderPlugin {
fn build(&self, app: &mut App) {
app.register_type::<DebugRenderContext>();
app.insert_resource(DebugRenderContext {
enabled: self.enabled,
pipeline: DebugRenderPipeline::new(self.style, self.mode),
})
.add_systems(
PostUpdate,
debug_render_scene.after(TransformSystem::TransformPropagate),
);
}
}
struct BevyLinesRenderBackend<'world, 'state, 'a, 'b> {
custom_colors: Query<'world, 'state, &'a ColliderDebugColor>,
context: &'b RapierContext,
gizmos: Gizmos<'world, 'state>,
}
impl<'world, 'state, 'a, 'b> BevyLinesRenderBackend<'world, 'state, 'a, 'b> {
fn object_color(&self, object: DebugRenderObject, default: [f32; 4]) -> [f32; 4] {
let color = match object {
DebugRenderObject::Collider(h, ..) => self.context.colliders.get(h).and_then(|co| {
self.custom_colors
.get(Entity::from_bits(co.user_data as u64))
.map(|co| co.0)
.ok()
}),
_ => None,
};
color.map(|co| co.as_hsla_f32()).unwrap_or(default)
}
}
impl<'world, 'state, 'a, 'b> DebugRenderBackend for BevyLinesRenderBackend<'world, 'state, 'a, 'b> {
#[cfg(feature = "dim2")]
fn draw_line(
&mut self,
object: DebugRenderObject,
a: Point<Real>,
b: Point<Real>,
color: [f32; 4],
) {
let color = self.object_color(object, color);
self.gizmos.line(
[a.x, a.y, 0.0].into(),
[b.x, b.y, 0.0].into(),
Color::hsla(color[0], color[1], color[2], color[3]),
)
}
#[cfg(feature = "dim3")]
fn draw_line(
&mut self,
object: DebugRenderObject,
a: Point<Real>,
b: Point<Real>,
color: [f32; 4],
) {
let color = self.object_color(object, color);
self.gizmos.line(
[a.x, a.y, a.z].into(),
[b.x, b.y, b.z].into(),
Color::hsla(color[0], color[1], color[2], color[3]),
)
}
}
fn debug_render_scene(
rapier_context: Res<RapierContext>,
mut render_context: ResMut<DebugRenderContext>,
gizmos: Gizmos,
custom_colors: Query<&ColliderDebugColor>,
) {
if !render_context.enabled {
return;
}
let mut backend = BevyLinesRenderBackend {
custom_colors,
context: &rapier_context,
gizmos,
};
let unscaled_style = render_context.pipeline.style;
render_context.pipeline.render(
&mut backend,
&rapier_context.bodies,
&rapier_context.colliders,
&rapier_context.impulse_joints,
&rapier_context.multibody_joints,
&rapier_context.narrow_phase,
);
render_context.pipeline.style = unscaled_style;
}