mod inline;
pub use inline::{Fanout, Inline};
use crate::physics::Simulation;
use crate::ecs::ScheduleMode;
pub trait PhysicsFanout: core::fmt::Debug + Send {
fn worker_count(&self, mode: ScheduleMode) -> usize;
fn step(&self, sim: &mut Simulation, dt: f32, mode: ScheduleMode);
}
#[derive(Debug, Clone, Copy, Default)]
pub struct SerialFanout;
impl PhysicsFanout for SerialFanout {
fn worker_count(&self, _mode: ScheduleMode) -> usize {
1
}
fn step(&self, sim: &mut Simulation, dt: f32, _mode: ScheduleMode) {
sim.step_with(dt, &Inline);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::physics::{ColliderShape, DynamicParams, LayerMask};
fn falling() -> (Simulation, crate::physics::BodyHandle) {
let mut sim = Simulation::with_capacity(4);
let ball = sim
.add_dynamic(
&ColliderShape::Ball { radius: 0.5 },
[0.0, 10.0, 0.0],
[0.0; 3],
DynamicParams {
mass: 1.0,
friction: 0.5,
restitution: 0.0,
gravity_scale: 1.0,
linear_damping: 0.0,
},
LayerMask::ALL,
)
.expect("room for one body");
(sim, ball)
}
#[test]
fn the_serial_fanout_lends_one_worker_and_steps() {
assert_eq!(SerialFanout.worker_count(ScheduleMode::Serial), 1);
assert_eq!(SerialFanout.worker_count(ScheduleMode::Parallel), 1);
let (mut sim, ball) = falling();
for _ in 0..10 {
SerialFanout.step(&mut sim, 1.0 / 60.0, ScheduleMode::Serial);
}
assert!(
sim.body_pose_quat(ball).expect("a live body").0[1] < 10.0,
"the fan-out advanced the simulation"
);
}
#[test]
fn the_schedule_mode_does_not_change_a_serial_step() {
let run = |mode| {
let (mut sim, ball) = falling();
for _ in 0..30 {
SerialFanout.step(&mut sim, 1.0 / 60.0, mode);
}
sim.body_pose_quat(ball).expect("a live body").0
};
assert_eq!(run(ScheduleMode::Serial), run(ScheduleMode::Parallel));
}
}