aboutsummaryrefslogtreecommitdiff
path: root/src_testbed/box2d_backend.rs
diff options
context:
space:
mode:
authorSébastien Crozet <developer@crozet.re>2020-08-25 22:10:25 +0200
committerSébastien Crozet <developer@crozet.re>2020-08-25 22:10:25 +0200
commit754a48b7ff6d8c58b1ee08651e60112900b60455 (patch)
tree7d777a6c003f1f5d8f8d24f533f35a95a88957fe /src_testbed/box2d_backend.rs
downloadrapier-0.1.0.tar.gz
rapier-0.1.0.tar.bz2
rapier-0.1.0.zip
First public release of Rapier.v0.1.0
Diffstat (limited to 'src_testbed/box2d_backend.rs')
-rw-r--r--src_testbed/box2d_backend.rs237
1 files changed, 237 insertions, 0 deletions
diff --git a/src_testbed/box2d_backend.rs b/src_testbed/box2d_backend.rs
new file mode 100644
index 0000000..07cef1e
--- /dev/null
+++ b/src_testbed/box2d_backend.rs
@@ -0,0 +1,237 @@
+use std::collections::HashMap;
+
+use na::{Isometry2, Vector2};
+use rapier::counters::Counters;
+use rapier::dynamics::{
+ IntegrationParameters, JointParams, JointSet, RigidBodyHandle, RigidBodySet,
+};
+use rapier::geometry::{Collider, ColliderSet, Shape};
+use std::f32;
+
+use wrapped2d::b2;
+use wrapped2d::dynamics::joints::{PrismaticJointDef, RevoluteJointDef, WeldJointDef};
+use wrapped2d::user_data::NoUserData;
+
+fn na_vec_to_b2_vec(v: Vector2<f32>) -> b2::Vec2 {
+ b2::Vec2 { x: v.x, y: v.y }
+}
+
+fn b2_vec_to_na_vec(v: b2::Vec2) -> Vector2<f32> {
+ Vector2::new(v.x, v.y)
+}
+
+fn b2_transform_to_na_isometry(v: b2::Transform) -> Isometry2<f32> {
+ Isometry2::new(b2_vec_to_na_vec(v.pos), v.rot.angle())
+}
+
+pub struct Box2dWorld {
+ world: b2::World<NoUserData>,
+ rapier2box2d: HashMap<RigidBodyHandle, b2::BodyHandle>,
+}
+
+impl Box2dWorld {
+ pub fn from_rapier(
+ gravity: Vector2<f32>,
+ bodies: &RigidBodySet,
+ colliders: &ColliderSet,
+ joints: &JointSet,
+ ) -> Self {
+ let mut world = b2::World::new(&na_vec_to_b2_vec(gravity));
+ world.set_continuous_physics(false);
+
+ let mut res = Box2dWorld {
+ world,
+ rapier2box2d: HashMap::new(),
+ };
+
+ res.insert_bodies(bodies);
+ res.insert_colliders(colliders);
+ res.insert_joints(joints);
+ res
+ }
+
+ fn insert_bodies(&mut self, bodies: &RigidBodySet) {
+ for (handle, body) in bodies.iter() {
+ let body_type = if !body.is_dynamic() {
+ b2::BodyType::Static
+ } else {
+ b2::BodyType::Dynamic
+ };
+
+ let linear_damping = 0.0;
+ let angular_damping = 0.0;
+
+ // if let Some(rb) = body.downcast_ref::<RigidBody<f32>>() {
+ // linear_damping = rb.linear_damping();
+ // angular_damping = rb.angular_damping();
+ // } else {
+ // linear_damping = 0.0;
+ // angular_damping = 0.0;
+ // }
+
+ let def = b2::BodyDef {
+ body_type,
+ position: na_vec_to_b2_vec(body.position.translation.vector),
+ angle: body.position.rotation.angle(),
+ linear_velocity: na_vec_to_b2_vec(body.linvel),
+ angular_velocity: body.angvel,
+ linear_damping,
+ angular_damping,
+ ..b2::BodyDef::new()
+ };
+ let b2_handle = self.world.create_body(&def);
+ self.rapier2box2d.insert(handle, b2_handle);
+
+ // Collider.
+ let mut b2_body = self.world.body_mut(b2_handle);
+ b2_body.set_bullet(false /* collider.is_ccd_enabled() */);
+ }
+ }
+
+ fn insert_colliders(&mut self, colliders: &ColliderSet) {
+ for (_, collider) in colliders.iter() {
+ let b2_body_handle = self.rapier2box2d[&collider.parent()];
+ let mut b2_body = self.world.body_mut(b2_body_handle);
+ Self::create_fixture(&collider, &mut *b2_body);
+ }
+ }
+
+ fn insert_joints(&mut self, joints: &JointSet) {
+ for joint in joints.iter() {
+ let body_a = self.rapier2box2d[&joint.body1];
+ let body_b = self.rapier2box2d[&joint.body2];
+
+ match &joint.params {
+ JointParams::BallJoint(params) => {
+ let def = RevoluteJointDef {
+ body_a,
+ body_b,
+ collide_connected: true,
+ local_anchor_a: na_vec_to_b2_vec(params.local_anchor1.coords),
+ local_anchor_b: na_vec_to_b2_vec(params.local_anchor2.coords),
+ reference_angle: 0.0,
+ enable_limit: false,
+ lower_angle: 0.0,
+ upper_angle: 0.0,
+ enable_motor: false,
+ motor_speed: 0.0,
+ max_motor_torque: 0.0,
+ };
+
+ self.world.create_joint(&def);
+ }
+ JointParams::FixedJoint(params) => {
+ let def = WeldJointDef {
+ body_a,
+ body_b,
+ collide_connected: true,
+ local_anchor_a: na_vec_to_b2_vec(params.local_anchor1.translation.vector),
+ local_anchor_b: na_vec_to_b2_vec(params.local_anchor2.translation.vector),
+ reference_angle: 0.0,
+ frequency: 0.0,
+ damping_ratio: 0.0,
+ };
+
+ self.world.create_joint(&def);
+ }
+ JointParams::PrismaticJoint(params) => {
+ let def = PrismaticJointDef {
+ body_a,
+ body_b,
+ collide_connected: true,
+ local_anchor_a: na_vec_to_b2_vec(params.local_anchor1.coords),
+ local_anchor_b: na_vec_to_b2_vec(params.local_anchor2.coords),
+ local_axis_a: na_vec_to_b2_vec(params.local_axis1().into_inner()),
+ reference_angle: 0.0,
+ enable_limit: params.limits_enabled,
+ lower_translation: params.limits[0],
+ upper_translation: params.limits[1],
+ enable_motor: false,
+ max_motor_force: 0.0,
+ motor_speed: 0.0,
+ };
+
+ self.world.create_joint(&def);
+ }
+ }
+ }
+ }
+
+ fn create_fixture(collider: &Collider, body: &mut b2::MetaBody<NoUserData>) {
+ let center = na_vec_to_b2_vec(collider.delta().translation.vector);
+ let mut fixture_def = b2::FixtureDef::new();
+
+ fixture_def.restitution = 0.0;
+ fixture_def.friction = collider.friction;
+ fixture_def.density = collider.density();
+ fixture_def.is_sensor = collider.is_sensor();
+ fixture_def.filter = b2::Filter::new();
+
+ match collider.shape() {
+ Shape::Ball(b) => {
+ let mut b2_shape = b2::CircleShape::new();
+ b2_shape.set_radius(b.radius);
+ b2_shape.set_position(center);
+ body.create_fixture(&b2_shape, &mut fixture_def);
+ }
+ Shape::Cuboid(c) => {
+ let b2_shape = b2::PolygonShape::new_box(c.half_extents.x, c.half_extents.y);
+ body.create_fixture(&b2_shape, &mut fixture_def);
+ }
+ Shape::Polygon(poly) => {
+ let points: Vec<_> = poly
+ .vertices()
+ .iter()
+ .map(|p| collider.delta() * p)
+ .map(|p| na_vec_to_b2_vec(p.coords))
+ .collect();
+ let b2_shape = b2::PolygonShape::new_with(&points);
+ body.create_fixture(&b2_shape, &mut fixture_def);
+ }
+ Shape::HeightField(heightfield) => {
+ let mut segments = heightfield.segments();
+ let seg1 = segments.next().unwrap();
+ let mut vertices = vec![
+ na_vec_to_b2_vec(seg1.a.coords),
+ na_vec_to_b2_vec(seg1.b.coords),
+ ];
+
+ // TODO: this will not handle holes properly.
+ segments.for_each(|seg| {
+ vertices.push(na_vec_to_b2_vec(seg.b.coords));
+ });
+
+ let b2_shape = b2::ChainShape::new_chain(&vertices);
+ body.create_fixture(&b2_shape, &mut fixture_def);
+ }
+ _ => eprintln!("Creating a shape unknown to the Box2d backend."),
+ }
+ }
+
+ pub fn step(&mut self, counters: &mut Counters, params: &IntegrationParameters) {
+ // self.world.set_continuous_physics(world.integration_parameters.max_ccd_substeps != 0);
+
+ counters.step_started();
+ self.world.step(
+ params.dt(),
+ params.max_velocity_iterations as i32,
+ params.max_position_iterations as i32,
+ );
+ counters.step_completed();
+ }
+
+ pub fn sync(&self, bodies: &mut RigidBodySet, colliders: &mut ColliderSet) {
+ for (handle, mut body) in bodies.iter_mut() {
+ if let Some(pb2_handle) = self.rapier2box2d.get(&handle) {
+ let b2_body = self.world.body(*pb2_handle);
+ let pos = b2_transform_to_na_isometry(b2_body.transform().clone());
+ body.set_position(pos);
+
+ for coll_handle in body.colliders() {
+ let collider = &mut colliders[*coll_handle];
+ collider.set_position_debug(pos * collider.delta());
+ }
+ }
+ }
+ }
+}