mod common;
use common::{add_floor, step, DT};
use oxijolt::*;
fn real() -> usize {
size_of::<Real>()
}
const EMPTY_WORLD: usize = 1 + 4 + 12 + 4 + 4 + 4 + 4;
fn static_body() -> usize {
4 + 1 + 3 * real() + 16
}
fn moving_body() -> usize {
let sleep_test_offset = if real() == 8 { 24 } else { 0 };
static_body() + 4 * 12 + sleep_test_offset + 3 * 16 + 4 + 1
}
const CONTACT_PAIR_WITH_ONE_MANIFOLD: usize = 8 + 12 + 12 + 4 + 16 + 2 + 12 + 8 + 4;
const CONTACT_POINT: usize = 12 + 12 + 4;
const HINGE: usize = 4 + 1 + 4 + 8 + 12 + 4 + 4 + 4 + 4;
fn character_stream() -> usize {
4 + 4 + 4 + 3 * real() + 12 + 12 + 3 * real() + 16 + 12 + 4 + 1 + 4
}
fn character_contact() -> usize {
12 + 3 * real() + 3 * 12 + 4 + 4 + 5
}
fn data_size(world: &PhysicsWorld) -> usize {
world.save_state().data_size()
}
fn empty_world() -> PhysicsWorld {
PhysicsWorld::new(WorldSettings::default()).unwrap()
}
fn cube() -> Shape {
Shape::new_box(Vec3::new(0.5, 0.5, 0.5)).unwrap()
}
#[test]
fn an_empty_world_holds_the_counts() {
assert_eq!(data_size(&empty_world()), EMPTY_WORLD);
}
#[test]
fn a_static_body_adds_its_id_flag_and_pose() {
let mut world = empty_world();
add_floor(&mut world);
assert_eq!(data_size(&world), EMPTY_WORLD + static_body());
}
#[test]
fn every_body_that_can_move_adds_the_same_bytes() {
let at = |x| RVec3::new(x, 10.0, 0.0);
for settings in [
BodySettings::new_dynamic().position(at(0.0)),
BodySettings::new_kinematic().position(at(3.0)),
] {
let mut world = empty_world();
let id = world.create_body(&cube(), &settings).unwrap();
assert!(world.body(id).unwrap().is_active());
assert_eq!(data_size(&world), EMPTY_WORLD + moving_body());
world.body_mut(id).unwrap().deactivate().unwrap();
assert!(!world.body(id).unwrap().is_active());
assert_eq!(data_size(&world), EMPTY_WORLD + moving_body());
}
}
#[test]
fn a_resting_cube_adds_one_contact_pair_with_four_points() {
let mut world = empty_world();
add_floor(&mut world);
world
.create_body(
&cube(),
&BodySettings::new_dynamic().position(RVec3::new(0.0, 0.5, 0.0)),
)
.unwrap();
let bodies = EMPTY_WORLD + static_body() + moving_body();
assert_eq!(data_size(&world), bodies);
step(&mut world, 1);
assert_eq!(
data_size(&world),
bodies + CONTACT_PAIR_WITH_ONE_MANIFOLD + 4 * CONTACT_POINT
);
}
#[test]
fn a_hinge_adds_its_index_and_solver_state() {
let mut world = empty_world();
let settings = BodySettings::new_dynamic().gravity_factor(0.0);
let a = world
.create_body(
&cube(),
&settings.clone().position(RVec3::new(0.0, 0.0, 0.0)),
)
.unwrap();
let b = world
.create_body(&cube(), &settings.position(RVec3::new(3.0, 0.0, 0.0)))
.unwrap();
let bodies = EMPTY_WORLD + 2 * moving_body();
assert_eq!(data_size(&world), bodies);
world
.create_constraint(
a,
b,
&HingeConstraintSettings::new(
RVec3::new(1.5, 0.0, 0.0),
Vec3::new(0.0, 0.0, 1.0),
Vec3::new(1.0, 0.0, 0.0),
),
)
.unwrap();
assert_eq!(data_size(&world), bodies + HINGE);
}
fn character_stream_len(world: &PhysicsWorld, id: CharacterId) -> usize {
world.character(id).unwrap().save_state().to_bytes().len() - 12
}
#[test]
fn a_character_adds_its_inner_body_and_keeps_its_contacts_in_its_own_state() {
let mut world = empty_world();
let capsule = Shape::new_capsule(0.7, 0.4).unwrap();
let settings = CharacterSettings::new(&capsule)
.shape_offset(Vec3::new(0.0, 1.1, 0.0))
.inner_body(Some(InnerBody {
shape: &capsule,
object_layer: ObjectLayer::MOVING,
}));
let id = world
.create_character(&settings, RVec3::new(0.0, 5.0, 0.0), Quat::IDENTITY)
.unwrap();
assert_eq!(data_size(&world), EMPTY_WORLD + moving_body());
assert_eq!(character_stream_len(&world, id), character_stream());
add_floor(&mut world);
let mut character = world.character_mut(id).unwrap();
character.set_position(RVec3::ZERO).unwrap();
for _ in 0..3 {
world
.update_character(
id,
DT,
Vec3::new(0.0, -9.81, 0.0),
&ExtendedUpdateSettings::default(),
&QueryFilter::new(),
)
.unwrap();
}
assert_eq!(
character_stream_len(&world, id),
character_stream() + character_contact()
);
}