mod framework;
use std::ptr::{null, null_mut};
use framework::*;
use oxijolt_sys::*;
const GREY: u32 = 0xFF80_8080;
const ROOT_SUB_SHAPE: JPH_SubShapeID = 0xFFFF_FFFF;
fn material(user_data: u64) -> *mut JPH_PhysicsMaterial {
init();
let material = unsafe { JPH_PhysicsMaterial_Create2(c"material".as_ptr(), GREY, user_data) };
assert!(!material.is_null());
material
}
fn user_data(material: *const JPH_PhysicsMaterial) -> Option<u64> {
let mut value = 7;
let found = unsafe { JPH_PhysicsMaterial_GetUserData(material, &mut value) };
if found {
Some(value)
} else {
assert_eq!(value, 7, "the out value is left untouched");
None
}
}
fn box_with_material(material: *const JPH_PhysicsMaterial) -> *mut JPH_Shape {
let half_extent = vec3(0.5, 0.5, 0.5);
unsafe {
init();
let settings = JPH_BoxShapeSettings_Create(&half_extent, 0.05);
JPH_ConvexShapeSettings_SetMaterial(settings.cast(), material);
let shape = JPH_BoxShapeSettings_CreateShape(settings);
JPH_ShapeSettings_Destroy(settings.cast());
assert!(!shape.is_null());
shape.cast()
}
}
#[test]
fn user_data_round_trips() {
for value in [0, 42, u64::MAX] {
let material = material(value);
assert_eq!(user_data(material), Some(value));
unsafe { JPH_PhysicsMaterial_Destroy(material) };
}
}
#[test]
fn other_materials_have_no_user_data() {
init();
let plain = unsafe { JPH_PhysicsMaterial_Create(c"plain".as_ptr(), GREY) };
assert_eq!(user_data(plain), None);
assert_eq!(user_data(null()), None);
let shape = box_with_material(null());
let default = unsafe { JPH_Shape_GetMaterial(shape, ROOT_SUB_SHAPE) };
assert!(!default.is_null(), "Jolt returns PhysicsMaterial::sDefault");
assert_eq!(user_data(default), None);
unsafe {
JPH_PhysicsMaterial_Destroy(plain);
JPH_Shape_Destroy(shape);
}
}
#[test]
fn convex_shape_settings_take_the_material() {
let material = material(5);
let shape = box_with_material(material);
let found = unsafe { JPH_Shape_GetMaterial(shape, ROOT_SUB_SHAPE) };
assert_eq!(found, material.cast_const());
unsafe { JPH_PhysicsMaterial_Destroy(material) };
let found = unsafe { JPH_Shape_GetMaterial(shape, ROOT_SUB_SHAPE) };
assert_eq!(user_data(found), Some(5));
unsafe { JPH_Shape_Destroy(shape) };
}
fn two_material_field(
materials: &[*const JPH_PhysicsMaterial],
) -> *mut JPH_HeightFieldShapeSettings {
init();
let samples = [0.0f32; 9];
let indices = [0u8, 1, 1, 0];
let (offset, scale) = (vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0));
unsafe {
JPH_HeightFieldShapeSettings_Create2(
samples.as_ptr(),
&offset,
&scale,
3,
indices.as_ptr(),
materials.as_ptr(),
materials.len() as u32,
)
}
}
#[test]
fn height_field_cells_resolve_their_materials() {
let (a, b) = (material(10), material(11));
let settings = two_material_field(&[a, b]);
assert!(!settings.is_null());
let shape = unsafe {
JPH_PhysicsMaterial_Destroy(a);
JPH_PhysicsMaterial_Destroy(b);
let shape = JPH_HeightFieldShapeSettings_CreateShape(settings);
JPH_ShapeSettings_Destroy(settings.cast());
shape
};
assert!(!shape.is_null());
for (x, y, expected) in [(0, 0, 10), (1, 0, 11), (0, 1, 11), (1, 1, 10)] {
let found = unsafe { JPH_HeightFieldShape_GetMaterial(shape, x, y) };
assert_eq!(user_data(found), Some(expected), "cell ({x}, {y})");
}
unsafe { JPH_Shape_Destroy(shape.cast()) };
}
#[test]
fn height_field_without_materials_is_refused() {
assert!(two_material_field(&[]).is_null());
let a = material(1);
let samples = [0.0f32; 9];
let (offset, scale) = (vec3(0.0, 0.0, 0.0), vec3(1.0, 1.0, 1.0));
let materials = [a.cast_const()];
unsafe {
let no_indices = JPH_HeightFieldShapeSettings_Create2(
samples.as_ptr(),
&offset,
&scale,
3,
null(),
materials.as_ptr(),
1,
);
assert!(no_indices.is_null());
let no_list = JPH_HeightFieldShapeSettings_Create2(
samples.as_ptr(),
&offset,
&scale,
3,
[0u8; 4].as_ptr(),
null_mut(),
1,
);
assert!(no_list.is_null());
JPH_PhysicsMaterial_Destroy(a);
}
}
fn ref_count(material: *const JPH_PhysicsMaterial) -> u32 {
unsafe { JPH_PhysicsMaterial_GetRefCount(material) }
}
#[test]
fn add_ref_and_count_follow_jolt() {
let material = material(5);
assert_eq!(ref_count(material), 1, "Create2 returns one reference");
let again = unsafe { JPH_PhysicsMaterial_AddRef(material) };
assert_eq!(again, material, "AddRef returns the material it was given");
assert_eq!(ref_count(material), 2);
let shape = box_with_material(material);
assert_eq!(ref_count(material), 3, "the box holds its own reference");
unsafe { JPH_Shape_Destroy(shape) };
assert_eq!(
ref_count(material),
2,
"destroying the box releases its reference"
);
unsafe { JPH_PhysicsMaterial_Destroy(again) };
assert_eq!(ref_count(material), 1);
unsafe { JPH_PhysicsMaterial_Destroy(material) };
assert!(unsafe { JPH_PhysicsMaterial_AddRef(null()) }.is_null());
assert_eq!(ref_count(null()), 0);
}