use std::{ffi::CString, mem::MaybeUninit, ptr, sync::Arc};
use crate::*;
pub struct Space {
session: Arc<session::SessionInner>,
_action_guard: Option<Action<Posef>>,
handle: sys::Space,
}
impl Space {
#[inline]
pub unsafe fn reference_from_raw<G>(session: Session<G>, handle: sys::Space) -> Self {
Self {
session: session.inner,
_action_guard: None,
handle,
}
}
#[inline]
pub unsafe fn action_from_raw<G>(
action: Action<Posef>,
session: Session<G>,
handle: sys::Space,
) -> Self {
Self {
session: session.inner,
_action_guard: Some(action),
handle,
}
}
#[inline]
pub fn as_raw(&self) -> sys::Space {
self.handle
}
#[inline]
pub fn instance(&self) -> &Instance {
&self.session.instance
}
#[inline]
pub fn set_name(&mut self, name: &str) -> Result<()> {
if let Some(fp) = self.instance().exts().ext_debug_utils.as_ref() {
let name = CString::new(name).unwrap();
let info = sys::DebugUtilsObjectNameInfoEXT {
ty: sys::DebugUtilsObjectNameInfoEXT::TYPE,
next: ptr::null(),
object_type: ObjectType::SPACE,
object_handle: self.as_raw().into_raw(),
object_name: name.as_ptr(),
};
unsafe {
cvt((fp.set_debug_utils_object_name)(
self.instance().as_raw(),
&info,
))?;
}
}
Ok(())
}
#[inline]
pub fn locate(&self, base: &Space, time: Time) -> Result<SpaceLocation> {
assert_eq!(&*self.session as *const session::SessionInner, &*base.session as *const session::SessionInner,
"`self` and `base` must have been created, allocated, or retrieved from the same `Session`");
unsafe {
let mut x = sys::SpaceLocation::out(ptr::null_mut());
cvt((self.fp().locate_space)(
self.as_raw(),
base.as_raw(),
time,
x.as_mut_ptr(),
))?;
Ok(SpaceLocation::new(&x))
}
}
#[inline]
pub fn relate(&self, base: &Space, time: Time) -> Result<(SpaceLocation, SpaceVelocity)> {
assert_eq!(&*self.session as *const session::SessionInner, &*base.session as *const session::SessionInner,
"`self` and `base` must have been created, allocated, or retrieved from the same `Session`");
unsafe {
let mut velocity = sys::SpaceVelocity::out(ptr::null_mut());
let mut location = sys::SpaceLocation::out(&mut velocity as *mut _ as _);
cvt((self.fp().locate_space)(
self.as_raw(),
base.as_raw(),
time,
location.as_mut_ptr(),
))?;
Ok((SpaceLocation::new(&location), SpaceVelocity::new(&velocity)))
}
}
#[inline]
pub fn locate_hand_joints(
&self,
tracker: &HandTracker,
time: Time,
) -> Result<Option<HandJointLocations>> {
assert_eq!(&*self.session as *const session::SessionInner, &*tracker.session as *const session::SessionInner,
"`self` and `tracker` must have been created, allocated, or retrieved from the same `Session`");
unsafe {
let locate_info = sys::HandJointsLocateInfoEXT {
ty: sys::HandJointsLocateInfoEXT::TYPE,
next: ptr::null(),
base_space: self.as_raw(),
time,
};
let mut locations = MaybeUninit::<[HandJointLocation; HAND_JOINT_COUNT]>::uninit();
let mut location_info = sys::HandJointLocationsEXT {
ty: sys::HandJointLocationsEXT::TYPE,
next: ptr::null_mut(),
is_active: false.into(),
joint_count: HAND_JOINT_COUNT as u32,
joint_locations: locations.as_mut_ptr() as _,
};
cvt((tracker.fp().locate_hand_joints)(
tracker.as_raw(),
&locate_info,
&mut location_info,
))?;
Ok(if location_info.is_active.into() {
Some(locations.assume_init())
} else {
None
})
}
}
#[inline]
pub fn relate_hand_joints(
&self,
tracker: &HandTracker,
time: Time,
) -> Result<Option<(HandJointLocations, HandJointVelocities)>> {
assert_eq!(&*self.session as *const session::SessionInner, &*tracker.session as *const session::SessionInner,
"`self` and `tracker` must have been created, allocated, or retrieved from the same `Session`");
unsafe {
let locate_info = sys::HandJointsLocateInfoEXT {
ty: sys::HandJointsLocateInfoEXT::TYPE,
next: ptr::null(),
base_space: self.as_raw(),
time,
};
let mut velocities = MaybeUninit::<[HandJointVelocity; HAND_JOINT_COUNT]>::uninit();
let mut velocity_info = sys::HandJointVelocitiesEXT {
ty: sys::HandJointVelocitiesEXT::TYPE,
next: ptr::null_mut(),
joint_count: HAND_JOINT_COUNT as u32,
joint_velocities: velocities.as_mut_ptr() as _,
};
let mut locations = MaybeUninit::<[HandJointLocation; HAND_JOINT_COUNT]>::uninit();
let mut location_info = sys::HandJointLocationsEXT {
ty: sys::HandJointLocationsEXT::TYPE,
next: &mut velocity_info as *mut _ as _,
is_active: false.into(),
joint_count: HAND_JOINT_COUNT as u32,
joint_locations: locations.as_mut_ptr() as _,
};
cvt((tracker.fp().locate_hand_joints)(
tracker.as_raw(),
&locate_info,
&mut location_info,
))?;
Ok(if location_info.is_active.into() {
Some((locations.assume_init(), velocities.assume_init()))
} else {
None
})
}
}
#[inline]
fn fp(&self) -> &raw::Instance {
self.session.instance.fp()
}
}
impl Drop for Space {
fn drop(&mut self) {
unsafe {
(self.fp().destroy_space)(self.handle);
}
}
}
#[derive(Copy, Clone, Default, PartialEq)]
pub struct SpaceLocation {
pub location_flags: SpaceLocationFlags,
pub pose: Posef,
}
impl SpaceLocation {
unsafe fn new(raw: &MaybeUninit<sys::SpaceLocation>) -> Self {
let ptr = raw.as_ptr();
let flags = *ptr::addr_of!((*ptr).location_flags);
Self {
location_flags: flags,
pose: Posef {
orientation: flags
.contains(sys::SpaceLocationFlags::ORIENTATION_VALID)
.then(|| *ptr::addr_of!((*ptr).pose.orientation))
.unwrap_or_default(),
position: flags
.contains(sys::SpaceLocationFlags::POSITION_VALID)
.then(|| *ptr::addr_of!((*ptr).pose.position))
.unwrap_or_default(),
},
}
}
}
#[derive(Copy, Clone, Default, PartialEq)]
pub struct SpaceVelocity {
pub velocity_flags: SpaceVelocityFlags,
pub linear_velocity: Vector3f,
pub angular_velocity: Vector3f,
}
impl SpaceVelocity {
unsafe fn new(raw: &MaybeUninit<sys::SpaceVelocity>) -> Self {
let ptr = raw.as_ptr();
let flags = *ptr::addr_of!((*ptr).velocity_flags);
Self {
velocity_flags: flags,
linear_velocity: flags
.contains(sys::SpaceVelocityFlags::LINEAR_VALID)
.then(|| *ptr::addr_of!((*ptr).linear_velocity))
.unwrap_or_default(),
angular_velocity: flags
.contains(sys::SpaceVelocityFlags::ANGULAR_VALID)
.then(|| *ptr::addr_of!((*ptr).angular_velocity))
.unwrap_or_default(),
}
}
}