feat: update to parry 0.21

This commit is contained in:
Sébastien Crozet
2025-05-16 18:23:45 +02:00
committed by Sébastien Crozet
parent b798e1942d
commit ef47848fba
10 changed files with 117 additions and 129 deletions

View File

@@ -14,11 +14,6 @@ pub fn init_world(testbed: &mut Testbed) {
let settings = testbed.example_settings_mut(); let settings = testbed.example_settings_mut();
let geometry_mode = settings.get_or_set_string(
"Voxels mode",
0,
vec!["PseudoCube".to_string(), "PseudoBall".to_string()],
);
let falling_objects = settings.get_or_set_string( let falling_objects = settings.get_or_set_string(
"Falling objects", "Falling objects",
5, // Defaults to Mixed. 5, // Defaults to Mixed.
@@ -40,12 +35,6 @@ pub fn init_world(testbed: &mut Testbed) {
// settings.get_or_set_bool("Load .obj", false); // settings.get_or_set_bool("Load .obj", false);
let load_obj = false; let load_obj = false;
let primitive_geometry = if geometry_mode == 0 {
VoxelPrimitiveGeometry::PseudoCube
} else {
VoxelPrimitiveGeometry::PseudoBall
};
/* /*
* World * World
*/ */
@@ -112,13 +101,8 @@ pub fn init_world(testbed: &mut Testbed) {
.map(|idx| [idx[0] as u32, idx[1] as u32, idx[2] as u32]) .map(|idx| [idx[0] as u32, idx[1] as u32, idx[2] as u32])
.collect(); .collect();
let decomposed_shape = SharedShape::voxelized_mesh( let decomposed_shape =
primitive_geometry, SharedShape::voxelized_mesh(&vertices, &indices, 0.1, FillMode::default());
&vertices,
&indices,
0.1,
FillMode::default(),
);
shapes.push(decomposed_shape); shapes.push(decomposed_shape);
@@ -160,8 +144,7 @@ pub fn init_world(testbed: &mut Testbed) {
} }
} }
} }
let collider = let collider = ColliderBuilder::voxels_from_points(voxel_size, &samples).build();
ColliderBuilder::voxels_from_points(primitive_geometry, voxel_size, &samples).build();
let floor_aabb = collider.compute_aabb(); let floor_aabb = collider.compute_aabb();
colliders.insert(collider); colliders.insert(collider);

View File

@@ -738,7 +738,6 @@ impl RigidBodyVelocity {
impl std::ops::Mul<Real> for RigidBodyVelocity { impl std::ops::Mul<Real> for RigidBodyVelocity {
type Output = Self; type Output = Self;
#[must_use]
fn mul(self, rhs: Real) -> Self { fn mul(self, rhs: Real) -> Self {
RigidBodyVelocity { RigidBodyVelocity {
linvel: self.linvel * rhs, linvel: self.linvel * rhs,
@@ -750,7 +749,6 @@ impl std::ops::Mul<Real> for RigidBodyVelocity {
impl std::ops::Add<RigidBodyVelocity> for RigidBodyVelocity { impl std::ops::Add<RigidBodyVelocity> for RigidBodyVelocity {
type Output = Self; type Output = Self;
#[must_use]
fn add(self, rhs: Self) -> Self { fn add(self, rhs: Self) -> Self {
RigidBodyVelocity { RigidBodyVelocity {
linvel: self.linvel + rhs.linvel, linvel: self.linvel + rhs.linvel,
@@ -769,7 +767,6 @@ impl std::ops::AddAssign<RigidBodyVelocity> for RigidBodyVelocity {
impl std::ops::Sub<RigidBodyVelocity> for RigidBodyVelocity { impl std::ops::Sub<RigidBodyVelocity> for RigidBodyVelocity {
type Output = Self; type Output = Self;
#[must_use]
fn sub(self, rhs: Self) -> Self { fn sub(self, rhs: Self) -> Self {
RigidBodyVelocity { RigidBodyVelocity {
linvel: self.linvel - rhs.linvel, linvel: self.linvel - rhs.linvel,

View File

@@ -1,4 +1,5 @@
use crate::geometry::{BroadPhasePairEvent, ColliderHandle, ColliderPair, ColliderSet}; use crate::dynamics::RigidBodySet;
use crate::geometry::{BroadPhase, BroadPhasePairEvent, ColliderHandle, ColliderPair, ColliderSet};
use parry::math::Real; use parry::math::Real;
use parry::partitioning::Qbvh; use parry::partitioning::Qbvh;
use parry::partitioning::QbvhUpdateWorkspace; use parry::partitioning::QbvhUpdateWorkspace;
@@ -27,12 +28,15 @@ impl BroadPhaseQbvh {
workspace: QbvhUpdateWorkspace::default(), workspace: QbvhUpdateWorkspace::default(),
} }
} }
}
#[allow(dead_code)] // This broad-phase is just experimental right now. impl BroadPhase for BroadPhaseQbvh {
pub fn update( fn update(
&mut self, &mut self,
dt: Real,
prediction_distance: Real, prediction_distance: Real,
colliders: &ColliderSet, colliders: &mut ColliderSet,
bodies: &RigidBodySet,
modified_colliders: &[ColliderHandle], modified_colliders: &[ColliderHandle],
removed_colliders: &[ColliderHandle], removed_colliders: &[ColliderHandle],
events: &mut Vec<BroadPhasePairEvent>, events: &mut Vec<BroadPhasePairEvent>,
@@ -46,7 +50,9 @@ impl BroadPhaseQbvh {
// Visitor to find collision pairs. // Visitor to find collision pairs.
let mut visitor = BoundingVolumeIntersectionsSimultaneousVisitor::new( let mut visitor = BoundingVolumeIntersectionsSimultaneousVisitor::new(
|co1: &ColliderHandle, co2: &ColliderHandle| { |co1: &ColliderHandle, co2: &ColliderHandle| {
if *co1 != *co2 {
events.push(BroadPhasePairEvent::AddPair(ColliderPair::new(*co1, *co2))); events.push(BroadPhasePairEvent::AddPair(ColliderPair::new(*co1, *co2)));
}
true true
}, },
); );
@@ -77,6 +83,8 @@ impl BroadPhaseQbvh {
let _ = self.qbvh.refit(margin, &mut self.workspace, |handle| { let _ = self.qbvh.refit(margin, &mut self.workspace, |handle| {
colliders[*handle].compute_collision_aabb(prediction_distance / 2.0) colliders[*handle].compute_collision_aabb(prediction_distance / 2.0)
}); });
// self.qbvh
// .traverse_bvtt_with_stack(&self.qbvh, &mut visitor, &mut self.stack);
self.qbvh self.qbvh
.traverse_modified_bvtt_with_stack(&self.qbvh, &mut visitor, &mut self.stack); .traverse_modified_bvtt_with_stack(&self.qbvh, &mut visitor, &mut self.stack);
self.qbvh.rebalance(margin, &mut self.workspace); self.qbvh.rebalance(margin, &mut self.workspace);

View File

@@ -12,7 +12,7 @@ use crate::pipeline::{ActiveEvents, ActiveHooks};
use crate::prelude::ColliderEnabled; use crate::prelude::ColliderEnabled;
use na::Unit; use na::Unit;
use parry::bounding_volume::{Aabb, BoundingVolume}; use parry::bounding_volume::{Aabb, BoundingVolume};
use parry::shape::{Shape, TriMeshBuilderError, TriMeshFlags, VoxelPrimitiveGeometry}; use parry::shape::{Shape, TriMeshBuilderError, TriMeshFlags};
use parry::transformation::voxelization::FillMode; use parry::transformation::voxelization::FillMode;
#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
@@ -580,45 +580,28 @@ impl ColliderBuilder {
/// ///
/// For initializing a voxels shape from points in space, see [`Self::voxels_from_points`]. /// For initializing a voxels shape from points in space, see [`Self::voxels_from_points`].
/// For initializing a voxels shape from a mesh to voxelize, see [`Self::voxelized_mesh`]. /// For initializing a voxels shape from a mesh to voxelize, see [`Self::voxelized_mesh`].
pub fn voxels( pub fn voxels(voxel_size: Vector<Real>, voxels: &[Point<i32>]) -> Self {
primitive_geometry: VoxelPrimitiveGeometry, Self::new(SharedShape::voxels(voxel_size, voxels))
voxel_size: Vector<Real>,
voxels: &[Point<i32>],
) -> Self {
Self::new(SharedShape::voxels(primitive_geometry, voxel_size, voxels))
} }
/// Initializes a collider made of voxels. /// Initializes a collider made of voxels.
/// ///
/// Each voxel has the size `voxel_size` and contains at least one point from `centers`. /// Each voxel has the size `voxel_size` and contains at least one point from `centers`.
/// The `primitive_geometry` controls the behavior of collision detection at voxels boundaries. /// The `primitive_geometry` controls the behavior of collision detection at voxels boundaries.
pub fn voxels_from_points( pub fn voxels_from_points(voxel_size: Vector<Real>, points: &[Point<Real>]) -> Self {
primitive_geometry: VoxelPrimitiveGeometry, Self::new(SharedShape::voxels_from_points(voxel_size, points))
voxel_size: Vector<Real>,
points: &[Point<Real>],
) -> Self {
Self::new(SharedShape::voxels_from_points(
primitive_geometry,
voxel_size,
points,
))
} }
/// Initializes a voxels obtained from the decomposition of the given trimesh (in 3D) /// Initializes a voxels obtained from the decomposition of the given trimesh (in 3D)
/// or polyline (in 2D) into voxelized convex parts. /// or polyline (in 2D) into voxelized convex parts.
pub fn voxelized_mesh( pub fn voxelized_mesh(
primitive_geometry: VoxelPrimitiveGeometry,
vertices: &[Point<Real>], vertices: &[Point<Real>],
indices: &[[u32; DIM]], indices: &[[u32; DIM]],
voxel_size: Real, voxel_size: Real,
fill_mode: FillMode, fill_mode: FillMode,
) -> Self { ) -> Self {
Self::new(SharedShape::voxelized_mesh( Self::new(SharedShape::voxelized_mesh(
primitive_geometry, vertices, indices, voxel_size, fill_mode,
vertices,
indices,
voxel_size,
fill_mode,
)) ))
} }

View File

@@ -17,7 +17,7 @@ pub use self::narrow_phase::NarrowPhase;
pub use parry::bounding_volume::BoundingVolume; pub use parry::bounding_volume::BoundingVolume;
pub use parry::query::{PointQuery, PointQueryWithLocation, RayCast, TrackedContact}; pub use parry::query::{PointQuery, PointQueryWithLocation, RayCast, TrackedContact};
pub use parry::shape::{SharedShape, VoxelPrimitiveGeometry, VoxelState, VoxelType, Voxels}; pub use parry::shape::{SharedShape, VoxelState, VoxelType, Voxels};
use crate::math::{Real, Vector}; use crate::math::{Real, Vector};

View File

@@ -1,6 +1,6 @@
use bevy::prelude::*; use bevy::prelude::*;
use na::{point, Point3}; use na::{point, Point3, Point4};
use crate::objects::node::EntityWithGraphics; use crate::objects::node::EntityWithGraphics;
use rapier::dynamics::{RigidBodyHandle, RigidBodySet}; use rapier::dynamics::{RigidBodyHandle, RigidBodySet};
@@ -27,8 +27,60 @@ pub type BevyMaterialComponent = MeshMaterial2d<BevyMaterial>;
#[cfg(feature = "dim3")] #[cfg(feature = "dim3")]
pub type BevyMaterialComponent = MeshMaterial3d<BevyMaterial>; pub type BevyMaterialComponent = MeshMaterial3d<BevyMaterial>;
pub type InstancedMaterials = HashMap<Point3<usize>, Handle<BevyMaterial>>; #[derive(Clone, Default)]
pub const SELECTED_OBJECT_MATERIAL_KEY: Point3<usize> = point![42, 42, 42]; pub struct InstancedMaterials {
cache: HashMap<Point4<usize>, Handle<BevyMaterial>>,
}
impl InstancedMaterials {
pub fn insert(
&mut self,
materials: &mut Assets<BevyMaterial>,
color: Point3<f32>,
opacity: f32,
) -> Handle<BevyMaterial> {
let key = color
.coords
.push(opacity)
.map(|c| (c * 255.0) as usize)
.into();
let bevy_color = Color::from(Srgba::new(color.x, color.y, color.z, opacity));
#[cfg(feature = "dim2")]
let material = bevy_sprite::ColorMaterial {
color: bevy_color,
texture: None,
..default()
};
#[cfg(feature = "dim3")]
let material = StandardMaterial {
metallic: 0.5,
perceptual_roughness: 0.5,
double_sided: true, // TODO: this doesn't do anything?
..StandardMaterial::from(bevy_color)
};
self.cache
.entry(key)
.or_insert_with(|| materials.add(material))
.clone_weak()
}
pub fn get(&self, color: &Point3<f32>, opacity: f32) -> Option<Handle<BevyMaterial>> {
let key = color
.coords
.push(opacity)
.map(|c| (c * 255.0) as usize)
.into();
self.cache.get(&key).map(|h| h.clone_weak())
}
pub fn clear(&mut self) {
self.cache.clear();
}
}
pub const SELECTED_OBJECT_COLOR: Point3<f32> = point![1.0, 0.0, 0.0];
pub struct GraphicsManager { pub struct GraphicsManager {
rand: Pcg32, rand: Pcg32,
@@ -52,13 +104,16 @@ impl GraphicsManager {
ground_color: point![0.5, 0.5, 0.5], ground_color: point![0.5, 0.5, 0.5],
b2wireframe: HashMap::new(), b2wireframe: HashMap::new(),
prefab_meshes: HashMap::new(), prefab_meshes: HashMap::new(),
instanced_materials: HashMap::new(), instanced_materials: Default::default(),
gfx_shift: Vector::zeros(), gfx_shift: Vector::zeros(),
} }
} }
pub fn selection_material(&self) -> Handle<BevyMaterial> { pub fn selection_material(&self) -> Handle<BevyMaterial> {
self.instanced_materials[&SELECTED_OBJECT_MATERIAL_KEY].clone_weak() self.instanced_materials
.get(&SELECTED_OBJECT_COLOR, 1.0)
.unwrap()
.clone_weak()
} }
pub fn clear(&mut self, commands: &mut Commands) { pub fn clear(&mut self, commands: &mut Commands) {
@@ -110,6 +165,7 @@ impl GraphicsManager {
pub fn set_body_color( pub fn set_body_color(
&mut self, &mut self,
materials: &mut Assets<BevyMaterial>, materials: &mut Assets<BevyMaterial>,
material_handles: &mut Query<&mut BevyMaterialComponent>,
b: RigidBodyHandle, b: RigidBodyHandle,
color: [f32; 3], color: [f32; 3],
) { ) {
@@ -117,7 +173,11 @@ impl GraphicsManager {
if let Some(ns) = self.b2sn.get_mut(&b) { if let Some(ns) = self.b2sn.get_mut(&b) {
for n in ns.iter_mut() { for n in ns.iter_mut() {
n.set_color(materials, color.into()) n.set_color(materials, &mut self.instanced_materials, color.into());
if let Ok(mut mat) = material_handles.get_mut(n.entity) {
mat.0 = n.material.clone_weak();
}
} }
} }
} }
@@ -185,12 +245,7 @@ impl GraphicsManager {
color color
} }
fn alloc_color( fn alloc_color(&mut self, handle: RigidBodyHandle, is_fixed: bool) -> Point3<f32> {
&mut self,
materials: &mut Assets<BevyMaterial>,
handle: RigidBodyHandle,
is_fixed: bool,
) -> Point3<f32> {
let mut color = self.ground_color; let mut color = self.ground_color;
if !is_fixed { if !is_fixed {
@@ -200,7 +255,7 @@ impl GraphicsManager {
} }
} }
self.set_body_color(materials, handle, color.into()); self.b2color.insert(handle, color.into());
color color
} }
@@ -221,7 +276,7 @@ impl GraphicsManager {
.b2color .b2color
.get(&handle) .get(&handle)
.cloned() .cloned()
.unwrap_or_else(|| self.alloc_color(materials, handle, !body.is_dynamic())); .unwrap_or_else(|| self.alloc_color(handle, !body.is_dynamic()));
let _ = self.add_body_colliders_with_color( let _ = self.add_body_colliders_with_color(
commands, meshes, materials, components, handle, bodies, colliders, color, commands, meshes, materials, components, handle, bodies, colliders, color,

View File

@@ -179,7 +179,7 @@ impl Harness {
self.physics.hooks = Box::new(hooks); self.physics.hooks = Box::new(hooks);
self.physics.islands = IslandManager::new(); self.physics.islands = IslandManager::new();
self.physics.broad_phase = DefaultBroadPhase::new(); self.physics.broad_phase = DefaultBroadPhase::default();
self.physics.narrow_phase = NarrowPhase::new(); self.physics.narrow_phase = NarrowPhase::new();
self.state.timestep_id = 0; self.state.timestep_id = 0;
self.state.time = 0.0; self.state.time = 0.0;

View File

@@ -14,7 +14,7 @@ use rapier::geometry::{ColliderHandle, ColliderSet, Shape, ShapeType};
use rapier::geometry::{Cone, Cylinder}; use rapier::geometry::{Cone, Cylinder};
use rapier::math::{Isometry, Real, Vector}; use rapier::math::{Isometry, Real, Vector};
use crate::graphics::{BevyMaterial, InstancedMaterials, SELECTED_OBJECT_MATERIAL_KEY}; use crate::graphics::{BevyMaterial, InstancedMaterials, SELECTED_OBJECT_COLOR};
#[cfg(feature = "dim2")] #[cfg(feature = "dim2")]
use { use {
na::{vector, Point2, Vector2}, na::{vector, Point2, Vector2},
@@ -37,28 +37,7 @@ impl EntityWithGraphics {
materials: &mut Assets<BevyMaterial>, materials: &mut Assets<BevyMaterial>,
instanced_materials: &mut InstancedMaterials, instanced_materials: &mut InstancedMaterials,
) { ) {
if instanced_materials.contains_key(&SELECTED_OBJECT_MATERIAL_KEY) { instanced_materials.insert(materials, SELECTED_OBJECT_COLOR, 1.0);
return; // Already added.
}
#[cfg(feature = "dim2")]
let selection_material = bevy_sprite::ColorMaterial {
color: Color::from(Srgba::rgb(1.0, 0.0, 0.0)),
texture: None,
..default()
};
#[cfg(feature = "dim3")]
let selection_material = StandardMaterial {
metallic: 0.5,
perceptual_roughness: 0.5,
double_sided: true, // TODO: this doesn't do anything?
..StandardMaterial::from(Color::from(Srgba::rgb(1.0, 0.0, 0.0)))
};
instanced_materials.insert(
SELECTED_OBJECT_MATERIAL_KEY,
materials.add(selection_material),
);
} }
pub fn spawn( pub fn spawn(
@@ -84,8 +63,7 @@ impl EntityWithGraphics {
.cloned() .cloned()
.or_else(|| generate_collider_mesh(shape).map(|m| meshes.add(m))); .or_else(|| generate_collider_mesh(shape).map(|m| meshes.add(m)));
let opacity = 1.0; let opacity = if sensor { 0.25 } else { 1.0 };
let bevy_color = Color::from(Srgba::new(color.x, color.y, color.z, opacity));
let shape_pos = collider_pos * delta; let shape_pos = collider_pos * delta;
let mut transform = Transform::from_scale(scale); let mut transform = Transform::from_scale(scale);
transform.translation.x = shape_pos.translation.vector.x as f32; transform.translation.x = shape_pos.translation.vector.x as f32;
@@ -108,23 +86,7 @@ impl EntityWithGraphics {
transform.rotation = Quat::from_rotation_z(shape_pos.rotation.angle() as f32); transform.rotation = Quat::from_rotation_z(shape_pos.rotation.angle() as f32);
} }
#[cfg(feature = "dim2")] let material_handle = instanced_materials.insert(materials, color, opacity);
let material = bevy_sprite::ColorMaterial {
color: bevy_color,
texture: None,
..default()
};
#[cfg(feature = "dim3")]
let material = StandardMaterial {
metallic: 0.5,
perceptual_roughness: 0.5,
double_sided: true, // TODO: this doesn't do anything?
..StandardMaterial::from(bevy_color)
};
let material_handle = instanced_materials
.entry(color.coords.map(|c| (c * 255.0) as usize).into())
.or_insert_with(|| materials.add(material));
let material_weak_handle = material_handle.clone_weak();
if let Some(mesh) = mesh { if let Some(mesh) = mesh {
#[cfg(feature = "dim2")] #[cfg(feature = "dim2")]
@@ -154,7 +116,7 @@ impl EntityWithGraphics {
base_color: color, base_color: color,
collider, collider,
delta, delta,
material: material_weak_handle, material: material_handle,
opacity, opacity,
} }
} }
@@ -164,18 +126,13 @@ impl EntityWithGraphics {
commands.entity(self.entity).despawn(); commands.entity(self.entity).despawn();
} }
pub fn set_color(&mut self, materials: &mut Assets<BevyMaterial>, color: Point3<f32>) { pub fn set_color(
if let Some(material) = materials.get_mut(&self.material) { &mut self,
#[cfg(feature = "dim2")] materials: &mut Assets<BevyMaterial>,
{ instanced_materials: &mut InstancedMaterials,
material.color = Color::from(Srgba::new(color.x, color.y, color.z, self.opacity)); color: Point3<f32>,
} ) {
#[cfg(feature = "dim3")] self.material = instanced_materials.insert(materials, color, self.opacity);
{
material.base_color =
Color::from(Srgba::new(color.x, color.y, color.z, self.opacity));
}
}
self.color = color; self.color = color;
self.base_color = color; self.base_color = color;
} }

View File

@@ -113,7 +113,7 @@ impl PhysicsState {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
islands: IslandManager::new(), islands: IslandManager::new(),
broad_phase: DefaultBroadPhase::new(), broad_phase: DefaultBroadPhase::default(),
narrow_phase: NarrowPhase::new(), narrow_phase: NarrowPhase::new(),
bodies: RigidBodySet::new(), bodies: RigidBodySet::new(),
colliders: ColliderSet::new(), colliders: ColliderSet::new(),

View File

@@ -178,11 +178,12 @@ struct OtherBackends {
} }
struct Plugins(Vec<Box<dyn TestbedPlugin>>); struct Plugins(Vec<Box<dyn TestbedPlugin>>);
pub struct TestbedGraphics<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> { pub struct TestbedGraphics<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k> {
graphics: &'a mut GraphicsManager, graphics: &'a mut GraphicsManager,
commands: &'a mut Commands<'d, 'e>, commands: &'a mut Commands<'d, 'e>,
meshes: &'a mut Assets<Mesh>, meshes: &'a mut Assets<Mesh>,
materials: &'a mut Assets<BevyMaterial>, materials: &'a mut Assets<BevyMaterial>,
material_handles: &'a mut Query<'i, 'j, &'k mut BevyMaterialComponent>,
components: &'a mut Query<'b, 'f, &'c mut Transform>, components: &'a mut Query<'b, 'f, &'c mut Transform>,
#[allow(dead_code)] // Dead in 2D but not in 3D. #[allow(dead_code)] // Dead in 2D but not in 3D.
camera_transform: GlobalTransform, camera_transform: GlobalTransform,
@@ -192,8 +193,8 @@ pub struct TestbedGraphics<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> {
mouse: &'a SceneMouse, mouse: &'a SceneMouse,
} }
pub struct Testbed<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h> { pub struct Testbed<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k> {
graphics: Option<TestbedGraphics<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h>>, graphics: Option<TestbedGraphics<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'h, 'i, 'j, 'k>>,
harness: &'a mut Harness, harness: &'a mut Harness,
state: &'a mut TestbedState, state: &'a mut TestbedState,
#[cfg(feature = "other-backends")] #[cfg(feature = "other-backends")]
@@ -508,9 +509,10 @@ impl TestbedApp {
} }
} }
impl<'g, 'h> TestbedGraphics<'_, '_, '_, '_, '_, '_, 'g, 'h> { impl<'g, 'h> TestbedGraphics<'_, '_, '_, '_, '_, '_, 'g, 'h, '_, '_, '_> {
pub fn set_body_color(&mut self, body: RigidBodyHandle, color: [f32; 3]) { pub fn set_body_color(&mut self, body: RigidBodyHandle, color: [f32; 3]) {
self.graphics.set_body_color(self.materials, body, color); self.graphics
.set_body_color(self.materials, self.material_handles, body, color);
} }
pub fn ui_context_mut(&mut self) -> &mut EguiContexts<'g, 'h> { pub fn ui_context_mut(&mut self) -> &mut EguiContexts<'g, 'h> {
@@ -585,7 +587,7 @@ impl<'g, 'h> TestbedGraphics<'_, '_, '_, '_, '_, '_, 'g, 'h> {
} }
} }
impl Testbed<'_, '_, '_, '_, '_, '_, '_, '_> { impl Testbed<'_, '_, '_, '_, '_, '_, '_, '_, '_, '_, '_> {
pub fn set_number_of_steps_per_frame(&mut self, nsteps: usize) { pub fn set_number_of_steps_per_frame(&mut self, nsteps: usize) {
self.state.nsteps = nsteps self.state.nsteps = nsteps
} }
@@ -1131,6 +1133,7 @@ fn update_testbed(
commands: &mut commands, commands: &mut commands,
meshes: &mut *meshes, meshes: &mut *meshes,
materials: &mut *materials, materials: &mut *materials,
material_handles: &mut material_handles,
components: &mut gfx_components, components: &mut gfx_components,
camera_transform: *cameras.single().1, camera_transform: *cameras.single().1,
camera: &mut cameras.single_mut().2, camera: &mut cameras.single_mut().2,
@@ -1246,6 +1249,7 @@ fn update_testbed(
commands: &mut commands, commands: &mut commands,
meshes: &mut *meshes, meshes: &mut *meshes,
materials: &mut *materials, materials: &mut *materials,
material_handles: &mut material_handles,
components: &mut gfx_components, components: &mut gfx_components,
camera_transform: *cameras.single().1, camera_transform: *cameras.single().1,
camera: &mut cameras.single_mut().2, camera: &mut cameras.single_mut().2,
@@ -1421,6 +1425,7 @@ fn update_testbed(
commands: &mut commands, commands: &mut commands,
meshes: &mut *meshes, meshes: &mut *meshes,
materials: &mut *materials, materials: &mut *materials,
material_handles: &mut material_handles,
components: &mut gfx_components, components: &mut gfx_components,
camera_transform: *cameras.single().1, camera_transform: *cameras.single().1,
camera: &mut cameras.single_mut().2, camera: &mut cameras.single_mut().2,