add interaction profile changed event, support velocities and expose Space(Location/Velocity)Flags as components

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2024-07-22 00:01:59 +02:00
parent fd2e04656d
commit f281266447
4 changed files with 215 additions and 77 deletions

View File

@@ -3,12 +3,12 @@ use std::{mem::MaybeUninit, ptr, sync::Mutex};
use bevy::{prelude::*, utils::hashbrown::HashSet};
use bevy_mod_xr::{
session::{session_available, session_running, XrFirst, XrHandleEvents},
spaces::{XrDestroySpace, XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace, XrSpatialOffset},
spaces::{XrDestroySpace, XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace, XrVelocity},
types::XrPose,
};
use openxr::{
sys, HandJointLocation, HandJointLocations, HandJointVelocities, HandJointVelocity,
ReferenceSpaceType, SpaceLocationFlags, HAND_JOINT_COUNT,
ReferenceSpaceType, SpaceLocationFlags, SpaceVelocityFlags, HAND_JOINT_COUNT,
};
use crate::{
@@ -27,6 +27,7 @@ impl Plugin for OxrSpacePatchingPlugin {
app.add_systems(Startup, patch_destroy_space.run_if(session_available));
}
}
pub struct OxrSpatialPlugin;
impl Plugin for OxrSpatialPlugin {
fn build(&self, app: &mut App) {
@@ -42,10 +43,29 @@ impl Plugin for OxrSpatialPlugin {
update_space_transforms
.in_set(OxrSpaceSyncSet)
.run_if(session_running),
);
)
.observe(add_location_flags)
.observe(add_velocity_flags);
}
}
fn add_velocity_flags(event: Trigger<OnAdd, XrVelocity>, mut cmds: Commands) {
if event.entity() == Entity::PLACEHOLDER {
error!("called add_location_flags observer without entity");
return;
}
cmds.entity(event.entity())
.insert(OxrSpaceLocationFlags(openxr::SpaceLocationFlags::default()));
}
fn add_location_flags(event: Trigger<OnAdd, XrSpace>, mut cmds: Commands) {
if event.entity() == Entity::PLACEHOLDER {
error!("called add_location_flags observer without entity");
return;
}
cmds.entity(event.entity())
.insert(OxrSpaceLocationFlags(openxr::SpaceLocationFlags::default()));
}
fn destroy_space_event(instance: Res<OxrInstance>, mut events: EventReader<XrDestroySpace>) {
for space in events.read() {
match instance.destroy_space(space.0) {
@@ -92,6 +112,34 @@ unsafe extern "system" fn patched_destroy_space(space: openxr::sys::Space) -> op
}
}
#[derive(Clone, Copy, Component)]
pub struct OxrSpaceLocationFlags(pub openxr::SpaceLocationFlags);
impl OxrSpaceLocationFlags {
pub fn pos_valid(&self) -> bool {
self.0.contains(SpaceLocationFlags::POSITION_VALID)
}
pub fn pos_tracked(&self) -> bool {
self.0.contains(SpaceLocationFlags::POSITION_TRACKED)
}
pub fn rot_valid(&self) -> bool {
self.0.contains(SpaceLocationFlags::ORIENTATION_VALID)
}
pub fn rot_tracked(&self) -> bool {
self.0.contains(SpaceLocationFlags::ORIENTATION_TRACKED)
}
}
#[derive(Clone, Copy, Component)]
pub struct OxrSpaceVelocityFlags(pub openxr::SpaceVelocityFlags);
impl OxrSpaceVelocityFlags {
pub fn linear_valid(&self) -> bool {
self.0.contains(SpaceVelocityFlags::LINEAR_VALID)
}
pub fn angular_valid(&self) -> bool {
self.0.contains(SpaceVelocityFlags::ANGULAR_VALID)
}
}
#[allow(clippy::type_complexity)]
fn update_space_transforms(
session: Res<OxrSession>,
default_ref_space: Res<XrPrimaryReferenceSpace>,
@@ -100,39 +148,61 @@ fn update_space_transforms(
mut query: Query<(
&mut Transform,
&XrSpace,
Option<&XrSpatialOffset>,
Option<&mut XrVelocity>,
Option<&XrReferenceSpace>,
&mut OxrSpaceLocationFlags,
Option<&mut OxrSpaceVelocityFlags>,
)>,
) {
for (mut transform, space, offset, ref_space) in &mut query {
let offset = offset.copied().unwrap_or_default();
for (
mut transform,
space,
velocity,
ref_space,
mut space_location_flags,
space_velocity_flags,
) in &mut query
{
let ref_space = ref_space.unwrap_or(&default_ref_space);
if let Ok(space_location) = session.locate_space(
space,
ref_space,
if pipelined.is_some() {
openxr::Time::from_nanos(
frame_state.predicted_display_time.as_nanos()
+ frame_state.predicted_display_period.as_nanos(),
)
} else {
frame_state.predicted_display_time
},
) {
if space_location
.location_flags
.contains(SpaceLocationFlags::POSITION_VALID)
{
transform.translation = offset
.to_transform()
.transform_point(space_location.pose.position.to_vec3())
let time = if pipelined.is_some() {
openxr::Time::from_nanos(
frame_state.predicted_display_time.as_nanos()
+ frame_state.predicted_display_period.as_nanos(),
)
} else {
frame_state.predicted_display_time
};
let space_location = if let Some(mut velocity) = velocity {
match session.locate_space_with_velocity(space, ref_space, time) {
Ok((location, space_velocity)) => {
let flags = OxrSpaceVelocityFlags(space_velocity.velocity_flags);
if flags.linear_valid() {
velocity.linear = space_velocity.linear_velocity.to_vec3();
}
if flags.linear_valid() {
velocity.linear = space_velocity.linear_velocity.to_vec3();
}
let Some(mut vel_flags) = space_velocity_flags else {
error!("XrVelocity without OxrSpaceVelocityFlags");
return;
};
*vel_flags = flags;
Ok(location)
}
Err(err) => Err(err),
}
if space_location
.location_flags
.contains(SpaceLocationFlags::ORIENTATION_VALID)
{
transform.rotation = offset.rotation * space_location.pose.orientation.to_quat();
} else {
session.locate_space(space, ref_space, time)
};
if let Ok(space_location) = space_location {
let flags = OxrSpaceLocationFlags(space_location.location_flags);
if flags.pos_valid() {
transform.translation = space_location.pose.position.to_vec3();
}
if flags.rot_valid() {
transform.rotation = space_location.pose.orientation.to_quat();
}
*space_location_flags = flags;
}
}
}