add new XrSpace and impl that
Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
@@ -18,14 +18,8 @@ fn main() {
|
|||||||
create_action_entities.before(XRUtilsActionSystemSet::CreateEvents),
|
create_action_entities.before(XRUtilsActionSystemSet::CreateEvents),
|
||||||
)
|
)
|
||||||
.add_plugins(XRUtilsActionsPlugin)
|
.add_plugins(XRUtilsActionsPlugin)
|
||||||
.add_systems(
|
.add_systems(Update, read_action_with_marker_component)
|
||||||
Update,
|
.add_systems(Update, handle_flight_input)
|
||||||
read_action_with_marker_component.after(XRUtilsActionSystemSet::SyncActionStates),
|
|
||||||
)
|
|
||||||
.add_systems(
|
|
||||||
Update,
|
|
||||||
handle_flight_input.after(XRUtilsActionSystemSet::SyncActionStates),
|
|
||||||
)
|
|
||||||
// Realtime lighting is expensive, use ambient light instead
|
// Realtime lighting is expensive, use ambient light instead
|
||||||
.insert_resource(AmbientLight {
|
.insert_resource(AmbientLight {
|
||||||
color: Default::default(),
|
color: Default::default(),
|
||||||
@@ -89,16 +83,22 @@ fn create_action_entities(mut commands: Commands) {
|
|||||||
.id();
|
.id();
|
||||||
|
|
||||||
//create a binding
|
//create a binding
|
||||||
let binding = commands
|
let binding_index = commands
|
||||||
.spawn(XRUtilsBinding {
|
.spawn(XRUtilsBinding {
|
||||||
profile: "/interaction_profiles/valve/index_controller".into(),
|
profile: "/interaction_profiles/valve/index_controller".into(),
|
||||||
binding: "/user/hand/right/input/thumbstick".into(),
|
binding: "/user/hand/right/input/thumbstick".into(),
|
||||||
})
|
})
|
||||||
.id();
|
.id();
|
||||||
|
let binding_touch = commands
|
||||||
|
.spawn(XRUtilsBinding {
|
||||||
|
profile: "/interaction_profiles/oculus/touch_controller".into(),
|
||||||
|
binding: "/user/hand/right/input/thumbstick".into(),
|
||||||
|
})
|
||||||
|
.id();
|
||||||
//add action to set, this isnt the best
|
//add action to set, this isnt the best
|
||||||
//TODO look into a better system
|
//TODO look into a better system
|
||||||
commands.entity(action).add_child(binding);
|
commands.entity(action).add_child(binding_index);
|
||||||
|
commands.entity(action).add_child(binding_touch);
|
||||||
commands.entity(set).add_child(action);
|
commands.entity(set).add_child(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
160
crates/bevy_openxr/examples/raw_actions.rs
Normal file
160
crates/bevy_openxr/examples/raw_actions.rs
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_openxr::{
|
||||||
|
action_binding::{OxrSendActionBindings, OxrSuggestActionBinding},
|
||||||
|
action_set_attaching::OxrAttachActionSet,
|
||||||
|
action_set_syncing::{OxrActionSetSyncSet, OxrSyncActionSet},
|
||||||
|
add_xr_plugins,
|
||||||
|
init::OxrTrackingRoot,
|
||||||
|
resources::OxrInstance,
|
||||||
|
session::OxrSession,
|
||||||
|
spaces::OxrSpaceExt,
|
||||||
|
};
|
||||||
|
use bevy_xr::{
|
||||||
|
session::{session_available, XrSessionCreated},
|
||||||
|
spaces::{XrSpace, XrSpatialTransform},
|
||||||
|
types::XrPose,
|
||||||
|
};
|
||||||
|
use openxr::Posef;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut app = App::new();
|
||||||
|
app.add_plugins(add_xr_plugins(DefaultPlugins));
|
||||||
|
app.add_systems(XrSessionCreated, spawn_hands);
|
||||||
|
app.add_systems(XrSessionCreated, attach_set);
|
||||||
|
app.add_systems(PreUpdate, sync_actions.before(OxrActionSetSyncSet));
|
||||||
|
app.add_systems(OxrSendActionBindings, suggest_action_bindings);
|
||||||
|
app.add_systems(Startup, create_actions.run_if(session_available));
|
||||||
|
app.add_systems(Startup, setup);
|
||||||
|
|
||||||
|
app.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn attach_set(actions: Res<ControllerActions>, mut attach: EventWriter<OxrAttachActionSet>) {
|
||||||
|
attach.send(OxrAttachActionSet(actions.set.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource)]
|
||||||
|
struct ControllerActions {
|
||||||
|
set: openxr::ActionSet,
|
||||||
|
left: openxr::Action<Posef>,
|
||||||
|
right: openxr::Action<Posef>,
|
||||||
|
}
|
||||||
|
fn sync_actions(actions: Res<ControllerActions>, mut sync: EventWriter<OxrSyncActionSet>) {
|
||||||
|
sync.send(OxrSyncActionSet(actions.set.clone()));
|
||||||
|
}
|
||||||
|
/// set up a simple 3D scene
|
||||||
|
fn setup(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
|
// circular base
|
||||||
|
commands.spawn(PbrBundle {
|
||||||
|
mesh: meshes.add(Circle::new(4.0)),
|
||||||
|
material: materials.add(Color::WHITE),
|
||||||
|
transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
// cube
|
||||||
|
commands.spawn(PbrBundle {
|
||||||
|
mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)),
|
||||||
|
material: materials.add(Color::rgb_u8(124, 144, 255)),
|
||||||
|
transform: Transform::from_xyz(0.0, 0.5, 0.0),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
// light
|
||||||
|
commands.spawn(PointLightBundle {
|
||||||
|
point_light: PointLight {
|
||||||
|
shadows_enabled: true,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
transform: Transform::from_xyz(4.0, 8.0, 4.0),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
commands.spawn(Camera3dBundle {
|
||||||
|
transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||||
|
..default()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn suggest_action_bindings(
|
||||||
|
actions: Res<ControllerActions>,
|
||||||
|
mut bindings: EventWriter<OxrSuggestActionBinding>,
|
||||||
|
) {
|
||||||
|
bindings.send(OxrSuggestActionBinding {
|
||||||
|
action: actions.left.as_raw(),
|
||||||
|
interaction_profile: "/interaction_profiles/oculus/touch_controller".into(),
|
||||||
|
bindings: vec!["/user/hand/left/input/grip/pose".into()],
|
||||||
|
});
|
||||||
|
bindings.send(OxrSuggestActionBinding {
|
||||||
|
action: actions.right.as_raw(),
|
||||||
|
interaction_profile: "/interaction_profiles/oculus/touch_controller".into(),
|
||||||
|
bindings: vec!["/user/hand/right/input/grip/pose".into()],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
fn create_actions(instance: Res<OxrInstance>, mut cmds: Commands) {
|
||||||
|
let set = instance.create_action_set("hands", "Hands", 0).unwrap();
|
||||||
|
let left = set
|
||||||
|
.create_action("left_pose", "Left Hand Grip Pose", &[])
|
||||||
|
.unwrap();
|
||||||
|
let right = set
|
||||||
|
.create_action("right_pose", "Right Hand Grip Pose", &[])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
cmds.insert_resource(ControllerActions { set, left, right })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn spawn_hands(
|
||||||
|
actions: Res<ControllerActions>,
|
||||||
|
mut cmds: Commands,
|
||||||
|
root: Query<Entity, With<OxrTrackingRoot>>,
|
||||||
|
session: Res<OxrSession>,
|
||||||
|
mut meshes: ResMut<Assets<Mesh>>,
|
||||||
|
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||||
|
) {
|
||||||
|
let l = actions
|
||||||
|
.left
|
||||||
|
.create_space(
|
||||||
|
session.deref().deref().clone(),
|
||||||
|
openxr::Path::NULL,
|
||||||
|
Posef::IDENTITY,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let left_space = XrSpace::from_openxr_space(l);
|
||||||
|
// let left_space = session
|
||||||
|
// .create_action_space(&actions.left, openxr::Path::NULL, XrPose::IDENTITY)
|
||||||
|
// .unwrap();
|
||||||
|
let right_space = session
|
||||||
|
.create_action_space(&actions.right, openxr::Path::NULL, XrPose::IDENTITY)
|
||||||
|
.unwrap();
|
||||||
|
let left = cmds
|
||||||
|
.spawn((
|
||||||
|
PbrBundle {
|
||||||
|
mesh: meshes.add(Cuboid::new(0.1, 0.1, 0.05)),
|
||||||
|
material: materials.add(Color::rgb_u8(124, 144, 255)),
|
||||||
|
transform: Transform::from_xyz(0.0, 0.5, 0.0),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
XrSpatialTransform::from_space(left_space),
|
||||||
|
Controller,
|
||||||
|
))
|
||||||
|
.id();
|
||||||
|
let right = cmds
|
||||||
|
.spawn((
|
||||||
|
PbrBundle {
|
||||||
|
mesh: meshes.add(Cuboid::new(0.1, 0.1, 0.05)),
|
||||||
|
material: materials.add(Color::rgb_u8(124, 144, 255)),
|
||||||
|
transform: Transform::from_xyz(0.0, 0.5, 0.0),
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
XrSpatialTransform::from_space(right_space),
|
||||||
|
Controller,
|
||||||
|
))
|
||||||
|
.id();
|
||||||
|
|
||||||
|
cmds.entity(root.single()).push_children(&[left, right]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
struct Controller;
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::{action_binding::run_action_binding_sugestion, session::{OxrSession, OxrSessionStatusEvent}};
|
use crate::{
|
||||||
|
action_binding::run_action_binding_sugestion,
|
||||||
|
session::{OxrSession, OxrSessionStatusEvent},
|
||||||
|
};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
|
||||||
impl Plugin for OxrActionAttachingPlugin {
|
impl Plugin for OxrActionAttachingPlugin {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_xr::hands::{LeftHand, RightHand};
|
use bevy_xr::hands::{LeftHand, RightHand};
|
||||||
|
use bevy_xr::spaces::{XrPrimaryReferenceSpace, XrReferenceSpace};
|
||||||
use bevy_xr::{
|
use bevy_xr::{
|
||||||
hands::{HandBone, HandBoneRadius},
|
hands::{HandBone, HandBoneRadius},
|
||||||
session::{session_running, XrSessionCreated, XrSessionExiting},
|
session::{session_running, XrSessionCreated, XrSessionExiting},
|
||||||
@@ -9,7 +10,6 @@ use openxr::SpaceLocationFlags;
|
|||||||
use crate::resources::Pipelined;
|
use crate::resources::Pipelined;
|
||||||
use crate::{
|
use crate::{
|
||||||
init::OxrTrackingRoot,
|
init::OxrTrackingRoot,
|
||||||
reference_space::{OxrPrimaryReferenceSpace, OxrReferenceSpace},
|
|
||||||
resources::OxrFrameState,
|
resources::OxrFrameState,
|
||||||
session::OxrSession,
|
session::OxrSession,
|
||||||
};
|
};
|
||||||
@@ -130,21 +130,23 @@ pub struct OxrHandBoneEntities(pub [Entity; 26]);
|
|||||||
pub struct OxrHandTracker(pub openxr::HandTracker);
|
pub struct OxrHandTracker(pub openxr::HandTracker);
|
||||||
|
|
||||||
fn locate_hands(
|
fn locate_hands(
|
||||||
default_ref_space: Res<OxrPrimaryReferenceSpace>,
|
default_ref_space: Res<XrPrimaryReferenceSpace>,
|
||||||
frame_state: Res<OxrFrameState>,
|
frame_state: Res<OxrFrameState>,
|
||||||
tracker_query: Query<(
|
tracker_query: Query<(
|
||||||
&OxrHandTracker,
|
&OxrHandTracker,
|
||||||
Option<&OxrReferenceSpace>,
|
Option<&XrReferenceSpace>,
|
||||||
&OxrHandBoneEntities,
|
&OxrHandBoneEntities,
|
||||||
)>,
|
)>,
|
||||||
|
session: Res<OxrSession>,
|
||||||
mut bone_query: Query<(&HandBone, &mut HandBoneRadius, &mut Transform)>,
|
mut bone_query: Query<(&HandBone, &mut HandBoneRadius, &mut Transform)>,
|
||||||
pipelined: Option<Res<Pipelined>>,
|
pipelined: Option<Res<Pipelined>>,
|
||||||
) {
|
) {
|
||||||
for (tracker, ref_space, hand_entities) in &tracker_query {
|
for (tracker, ref_space, hand_entities) in &tracker_query {
|
||||||
let ref_space = ref_space.map(|v| &v.0).unwrap_or(&default_ref_space.0);
|
let ref_space = ref_space.map(|v| &v.0).unwrap_or(&default_ref_space.0);
|
||||||
// relate_hand_joints also provides velocities
|
// relate_hand_joints also provides velocities
|
||||||
let joints = match ref_space.locate_hand_joints(
|
let joints = match session.locate_hand_joints(
|
||||||
tracker,
|
tracker,
|
||||||
|
ref_space,
|
||||||
if pipelined.is_some() {
|
if pipelined.is_some() {
|
||||||
openxr::Time::from_nanos(
|
openxr::Time::from_nanos(
|
||||||
frame_state.predicted_display_time.as_nanos()
|
frame_state.predicted_display_time.as_nanos()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use bevy_xr::types::XrPose;
|
||||||
|
|
||||||
pub trait ToPosef {
|
pub trait ToPosef {
|
||||||
fn to_posef(&self) -> openxr::Posef;
|
fn to_posef(&self) -> openxr::Posef;
|
||||||
@@ -6,6 +7,9 @@ pub trait ToPosef {
|
|||||||
pub trait ToTransform {
|
pub trait ToTransform {
|
||||||
fn to_transform(&self) -> Transform;
|
fn to_transform(&self) -> Transform;
|
||||||
}
|
}
|
||||||
|
pub trait ToXrPose {
|
||||||
|
fn to_xr_pose(&self) -> XrPose;
|
||||||
|
}
|
||||||
pub trait ToQuaternionf {
|
pub trait ToQuaternionf {
|
||||||
fn to_quaternionf(&self) -> openxr::Quaternionf;
|
fn to_quaternionf(&self) -> openxr::Quaternionf;
|
||||||
}
|
}
|
||||||
@@ -38,6 +42,22 @@ impl ToTransform for openxr::Posef {
|
|||||||
.with_rotation(self.orientation.to_quat())
|
.with_rotation(self.orientation.to_quat())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
impl ToXrPose for openxr::Posef {
|
||||||
|
fn to_xr_pose(&self) -> XrPose {
|
||||||
|
XrPose {
|
||||||
|
position: self.position.to_vec3(),
|
||||||
|
rotation: self.orientation.to_quat(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl ToPosef for XrPose {
|
||||||
|
fn to_posef(&self) -> openxr::Posef {
|
||||||
|
openxr::Posef {
|
||||||
|
orientation: self.rotation.to_quaternionf(),
|
||||||
|
position: self.position.to_vector3f(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToQuaternionf for Quat {
|
impl ToQuaternionf for Quat {
|
||||||
fn to_quaternionf(&self) -> openxr::Quaternionf {
|
fn to_quaternionf(&self) -> openxr::Quaternionf {
|
||||||
@@ -51,7 +71,14 @@ impl ToQuaternionf for Quat {
|
|||||||
}
|
}
|
||||||
impl ToQuat for openxr::Quaternionf {
|
impl ToQuat for openxr::Quaternionf {
|
||||||
fn to_quat(&self) -> Quat {
|
fn to_quat(&self) -> Quat {
|
||||||
Quat::from_xyzw(self.x, self.y, self.z, self.w)
|
let mut quat = Quat::from_xyzw(self.x, self.y, self.z, self.w);
|
||||||
|
if quat.length() == 0.0 {
|
||||||
|
quat = Quat::IDENTITY;
|
||||||
|
}
|
||||||
|
if !quat.is_normalized() {
|
||||||
|
quat = quat.normalize();
|
||||||
|
}
|
||||||
|
quat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl ToVector3f for Vec3 {
|
impl ToVector3f for Vec3 {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use bevy::ecs::world::World;
|
use bevy::ecs::world::World;
|
||||||
use openxr::{sys, CompositionLayerFlags, Fovf, Posef, Rect2Di, Space};
|
use bevy_xr::spaces::{XrPrimaryReferenceSpace, XrSpace};
|
||||||
|
use openxr::{sys, CompositionLayerFlags, Fovf, Posef, Rect2Di};
|
||||||
|
|
||||||
use crate::graphics::graphics_match;
|
use crate::graphics::graphics_match;
|
||||||
use crate::reference_space::OxrPrimaryReferenceSpace;
|
|
||||||
use crate::resources::*;
|
use crate::resources::*;
|
||||||
|
use crate::spaces::OxrSpaceExt as _;
|
||||||
|
|
||||||
pub trait LayerProvider {
|
pub trait LayerProvider {
|
||||||
fn get<'a>(&'a self, world: &'a World) -> Option<Box<dyn CompositionLayer + '_>>;
|
fn get<'a>(&'a self, world: &'a World) -> Option<Box<dyn CompositionLayer + '_>>;
|
||||||
@@ -17,7 +18,7 @@ pub struct PassthroughLayer;
|
|||||||
|
|
||||||
impl LayerProvider for ProjectionLayer {
|
impl LayerProvider for ProjectionLayer {
|
||||||
fn get<'a>(&self, world: &'a World) -> Option<Box<dyn CompositionLayer<'a> + 'a>> {
|
fn get<'a>(&self, world: &'a World) -> Option<Box<dyn CompositionLayer<'a> + 'a>> {
|
||||||
let stage = world.get_resource::<OxrPrimaryReferenceSpace>()?;
|
let stage = world.get_resource::<XrPrimaryReferenceSpace>()?;
|
||||||
let openxr_views = world.get_resource::<OxrViews>()?;
|
let openxr_views = world.get_resource::<OxrViews>()?;
|
||||||
let swapchain = world.get_resource::<OxrSwapchain>()?;
|
let swapchain = world.get_resource::<OxrSwapchain>()?;
|
||||||
let graphics_info = world.get_resource::<OxrGraphicsInfo>()?;
|
let graphics_info = world.get_resource::<OxrGraphicsInfo>()?;
|
||||||
@@ -205,8 +206,8 @@ impl<'a> CompositionLayerProjection<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn space(mut self, value: &'a Space) -> Self {
|
pub fn space(mut self, value: &XrSpace) -> Self {
|
||||||
self.inner.space = value.as_raw();
|
self.inner.space = value.as_raw_openxr_space();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ pub mod render;
|
|||||||
pub mod resources;
|
pub mod resources;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub mod spaces;
|
||||||
|
|
||||||
pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
|
pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
|
||||||
plugins
|
plugins
|
||||||
@@ -50,6 +51,7 @@ pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
|
|||||||
.add(action_binding::OxrActionBindingPlugin)
|
.add(action_binding::OxrActionBindingPlugin)
|
||||||
.add(action_set_syncing::OxrActionSyncingPlugin)
|
.add(action_set_syncing::OxrActionSyncingPlugin)
|
||||||
.add(features::overlay::OxrOverlayPlugin)
|
.add(features::overlay::OxrOverlayPlugin)
|
||||||
|
.add(spaces::OxrSpatialPlugin)
|
||||||
// .add(XrActionPlugin)
|
// .add(XrActionPlugin)
|
||||||
// we should probably handle the exiting ourselfs so that we can correctly end the
|
// we should probably handle the exiting ourselfs so that we can correctly end the
|
||||||
// session and instance
|
// session and instance
|
||||||
|
|||||||
@@ -7,7 +7,10 @@ use bevy::{
|
|||||||
RenderApp,
|
RenderApp,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use bevy_xr::session::{XrSessionCreated, XrSessionExiting};
|
use bevy_xr::{
|
||||||
|
session::{XrSessionCreated, XrSessionExiting},
|
||||||
|
spaces::{XrPrimaryReferenceSpace, XrReferenceSpace},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::session::OxrSession;
|
use crate::session::OxrSession;
|
||||||
|
|
||||||
@@ -25,19 +28,19 @@ impl Default for OxrReferenceSpacePlugin {
|
|||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
struct OxrDefaultPrimaryReferenceSpaceType(openxr::ReferenceSpaceType);
|
struct OxrDefaultPrimaryReferenceSpaceType(openxr::ReferenceSpaceType);
|
||||||
/// The Default Reference space used for locating things
|
/// The Default Reference space used for locating things
|
||||||
#[derive(Resource, Deref, ExtractResource, Clone)]
|
// #[derive(Resource, Deref, ExtrctResource, Clone)]
|
||||||
pub struct OxrPrimaryReferenceSpace(pub Arc<openxr::Space>);
|
// pub struct OxrPrimaryReferenceSpace(pub Arc<openxr::Space>);
|
||||||
|
|
||||||
/// The Reference space used for locating spaces on this entity
|
/// The Reference space used for locating spaces on this entity
|
||||||
#[derive(Component)]
|
// #[derive(Component)]
|
||||||
pub struct OxrReferenceSpace(pub openxr::Space);
|
// pub struct OxrReferenceSpace(pub openxr::Space);
|
||||||
|
|
||||||
impl Plugin for OxrReferenceSpacePlugin {
|
impl Plugin for OxrReferenceSpacePlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.insert_resource(OxrDefaultPrimaryReferenceSpaceType(
|
app.insert_resource(OxrDefaultPrimaryReferenceSpaceType(
|
||||||
self.default_primary_ref_space,
|
self.default_primary_ref_space,
|
||||||
));
|
));
|
||||||
app.add_plugins(ExtractResourcePlugin::<OxrPrimaryReferenceSpace>::default());
|
app.add_plugins(ExtractResourcePlugin::<XrPrimaryReferenceSpace>::default());
|
||||||
app.add_systems(XrSessionCreated, set_primary_ref_space);
|
app.add_systems(XrSessionCreated, set_primary_ref_space);
|
||||||
app.add_systems(XrSessionExiting, cleanup);
|
app.add_systems(XrSessionExiting, cleanup);
|
||||||
app.sub_app_mut(RenderApp)
|
app.sub_app_mut(RenderApp)
|
||||||
@@ -45,10 +48,10 @@ impl Plugin for OxrReferenceSpacePlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cleanup(mut cmds: Commands, query: Query<Entity, With<OxrReferenceSpace>>) {
|
fn cleanup(mut cmds: Commands, query: Query<Entity, With<XrReferenceSpace>>) {
|
||||||
cmds.remove_resource::<OxrPrimaryReferenceSpace>();
|
cmds.remove_resource::<XrPrimaryReferenceSpace>();
|
||||||
for e in &query {
|
for e in &query {
|
||||||
cmds.entity(e).remove::<OxrReferenceSpace>();
|
cmds.entity(e).remove::<XrReferenceSpace>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,9 +60,9 @@ fn set_primary_ref_space(
|
|||||||
space_type: Res<OxrDefaultPrimaryReferenceSpaceType>,
|
space_type: Res<OxrDefaultPrimaryReferenceSpaceType>,
|
||||||
mut cmds: Commands,
|
mut cmds: Commands,
|
||||||
) {
|
) {
|
||||||
match session.create_reference_space(space_type.0, openxr::Posef::IDENTITY) {
|
match session.create_reference_space(space_type.0, Transform::IDENTITY) {
|
||||||
Ok(space) => {
|
Ok(space) => {
|
||||||
cmds.insert_resource(OxrPrimaryReferenceSpace(Arc::new(space)));
|
cmds.insert_resource(XrPrimaryReferenceSpace(space));
|
||||||
}
|
}
|
||||||
Err(openxr::sys::Result::ERROR_EXTENSION_NOT_PRESENT) => {
|
Err(openxr::sys::Result::ERROR_EXTENSION_NOT_PRESENT) => {
|
||||||
error!("Required Extension for Reference Space not loaded");
|
error!("Required Extension for Reference Space not loaded");
|
||||||
|
|||||||
@@ -15,15 +15,17 @@ use bevy::{
|
|||||||
use bevy_xr::{
|
use bevy_xr::{
|
||||||
camera::{XrCamera, XrCameraBundle, XrProjection},
|
camera::{XrCamera, XrCameraBundle, XrProjection},
|
||||||
session::{session_running, XrSessionExiting},
|
session::{session_running, XrSessionExiting},
|
||||||
|
spaces::XrPrimaryReferenceSpace,
|
||||||
};
|
};
|
||||||
use openxr::ViewStateFlags;
|
use openxr::ViewStateFlags;
|
||||||
|
|
||||||
|
use crate::resources::*;
|
||||||
|
use crate::spaces::OxrSpaceExt as _;
|
||||||
use crate::{
|
use crate::{
|
||||||
init::{session_started, OxrHandleEvents, OxrLast, OxrTrackingRoot},
|
init::{session_started, OxrHandleEvents, OxrLast, OxrTrackingRoot},
|
||||||
layer_builder::ProjectionLayer,
|
layer_builder::ProjectionLayer,
|
||||||
session::OxrSession,
|
session::OxrSession,
|
||||||
};
|
};
|
||||||
use crate::{reference_space::OxrPrimaryReferenceSpace, resources::*};
|
|
||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
|
||||||
pub struct OxrRenderBegin;
|
pub struct OxrRenderBegin;
|
||||||
@@ -273,7 +275,7 @@ pub fn update_cameras(
|
|||||||
|
|
||||||
pub fn locate_views(
|
pub fn locate_views(
|
||||||
session: Res<OxrSession>,
|
session: Res<OxrSession>,
|
||||||
ref_space: Res<OxrPrimaryReferenceSpace>,
|
ref_space: Res<XrPrimaryReferenceSpace>,
|
||||||
frame_state: Res<OxrFrameState>,
|
frame_state: Res<OxrFrameState>,
|
||||||
mut openxr_views: ResMut<OxrViews>,
|
mut openxr_views: ResMut<OxrViews>,
|
||||||
pipelined: Option<Res<Pipelined>>,
|
pipelined: Option<Res<Pipelined>>,
|
||||||
|
|||||||
@@ -6,11 +6,14 @@ use crate::resources::{
|
|||||||
OxrCleanupSession, OxrPassthrough, OxrPassthroughLayer, OxrSessionStarted, OxrSwapchain,
|
OxrCleanupSession, OxrPassthrough, OxrPassthroughLayer, OxrSessionStarted, OxrSwapchain,
|
||||||
};
|
};
|
||||||
use crate::types::{Result, SwapchainCreateInfo};
|
use crate::types::{Result, SwapchainCreateInfo};
|
||||||
|
use bevy::app::AppExit;
|
||||||
use bevy::ecs::event::ManualEventReader;
|
use bevy::ecs::event::ManualEventReader;
|
||||||
use bevy::ecs::system::RunSystemOnce;
|
use bevy::ecs::system::RunSystemOnce;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::render::RenderApp;
|
use bevy::render::RenderApp;
|
||||||
use bevy_xr::session::{status_changed_to, XrSessionCreated, XrSessionExiting, XrStatus};
|
use bevy_xr::session::{
|
||||||
|
session_running, status_changed_to, XrSessionCreated, XrSessionExiting, XrStatus,
|
||||||
|
};
|
||||||
use openxr::AnyGraphics;
|
use openxr::AnyGraphics;
|
||||||
|
|
||||||
use crate::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap};
|
use crate::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap};
|
||||||
@@ -28,6 +31,12 @@ impl Plugin for OxrSessionPlugin {
|
|||||||
app.init_non_send_resource::<OxrSessionCreateNextChain>();
|
app.init_non_send_resource::<OxrSessionCreateNextChain>();
|
||||||
app.add_event::<OxrSessionStatusEvent>();
|
app.add_event::<OxrSessionStatusEvent>();
|
||||||
app.add_systems(OxrLast, run_session_status_schedules.after(OxrHandleEvents));
|
app.add_systems(OxrLast, run_session_status_schedules.after(OxrHandleEvents));
|
||||||
|
app.add_systems(
|
||||||
|
OxrLast,
|
||||||
|
exits_session_on_app_exit
|
||||||
|
.before(OxrHandleEvents)
|
||||||
|
.run_if(on_event::<AppExit>().and_then(session_running)),
|
||||||
|
);
|
||||||
app.add_systems(XrSessionExiting, clean_session);
|
app.add_systems(XrSessionExiting, clean_session);
|
||||||
app.sub_app_mut(RenderApp)
|
app.sub_app_mut(RenderApp)
|
||||||
.add_systems(XrSessionExiting, |mut cmds: Commands| {
|
.add_systems(XrSessionExiting, |mut cmds: Commands| {
|
||||||
@@ -39,6 +48,9 @@ impl Plugin for OxrSessionPlugin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn exits_session_on_app_exit(session: Res<OxrSession>) {
|
||||||
|
session.request_exit().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_stopping_state(session: Res<OxrSession>, mut session_started: ResMut<OxrSessionStarted>) {
|
fn handle_stopping_state(session: Res<OxrSession>, mut session_started: ResMut<OxrSessionStarted>) {
|
||||||
session.end().expect("Failed to end session");
|
session.end().expect("Failed to end session");
|
||||||
|
|||||||
518
crates/bevy_openxr/src/openxr/spaces.rs
Normal file
518
crates/bevy_openxr/src/openxr/spaces.rs
Normal file
@@ -0,0 +1,518 @@
|
|||||||
|
use std::{mem::MaybeUninit, ptr, sync::Mutex};
|
||||||
|
|
||||||
|
use bevy::{prelude::*, utils::hashbrown::HashSet};
|
||||||
|
use bevy_xr::{
|
||||||
|
session::{session_available, session_running},
|
||||||
|
spaces::{
|
||||||
|
XrDestroySpace, XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace, XrSpatialTransform,
|
||||||
|
},
|
||||||
|
types::XrPose,
|
||||||
|
};
|
||||||
|
use openxr::{
|
||||||
|
sys, HandJointLocation, HandJointLocations, HandJointVelocities, HandJointVelocity,
|
||||||
|
ReferenceSpaceType, SpaceLocationFlags, HAND_JOINT_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
helper_traits::{ToPosef, ToQuat, ToVec3},
|
||||||
|
init::{OxrHandleEvents, OxrLast},
|
||||||
|
resources::{OxrFrameState, OxrInstance, Pipelined},
|
||||||
|
session::OxrSession,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct OxrSpatialPlugin;
|
||||||
|
impl Plugin for OxrSpatialPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_event::<XrDestroySpace>();
|
||||||
|
app.add_systems(PreUpdate, update_spatial_transforms.run_if(session_running));
|
||||||
|
app.add_systems(Startup, patch_destroy_space.run_if(session_available));
|
||||||
|
app.add_systems(OxrLast, destroy_space_event.before(OxrHandleEvents));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destroy_space_event(instance: Res<OxrInstance>, mut events: EventReader<XrDestroySpace>) {
|
||||||
|
for space in events.read() {
|
||||||
|
unsafe {
|
||||||
|
(instance.fp().destroy_space)(space.as_raw_openxr_space());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static OXR_DO_NOT_CALL_DESTOY_SPACE_FOR: Mutex<Option<HashSet<u64>>> = Mutex::new(None);
|
||||||
|
pub static OXR_ORIGINAL_DESTOY_SPACE: Mutex<Option<openxr::sys::pfn::DestroySpace>> =
|
||||||
|
Mutex::new(None);
|
||||||
|
|
||||||
|
fn patch_destroy_space(instance: ResMut<OxrInstance>) {
|
||||||
|
OXR_DO_NOT_CALL_DESTOY_SPACE_FOR
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.replace(HashSet::new());
|
||||||
|
let raw_instance_ptr = instance.fp() as *const _ as *mut openxr::raw::Instance;
|
||||||
|
unsafe {
|
||||||
|
OXR_ORIGINAL_DESTOY_SPACE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.replace((*raw_instance_ptr).destroy_space);
|
||||||
|
|
||||||
|
(*raw_instance_ptr).destroy_space = patched_destroy_space;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe extern "system" fn patched_destroy_space(space: openxr::sys::Space) -> openxr::sys::Result {
|
||||||
|
if !OXR_DO_NOT_CALL_DESTOY_SPACE_FOR
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.contains(&space.into_raw())
|
||||||
|
{
|
||||||
|
OXR_ORIGINAL_DESTOY_SPACE
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.expect("has to be initialized")(space)
|
||||||
|
} else {
|
||||||
|
info!("Inject Worked, not destroying space");
|
||||||
|
openxr::sys::Result::SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_spatial_transforms(
|
||||||
|
session: Res<OxrSession>,
|
||||||
|
default_ref_space: Res<XrPrimaryReferenceSpace>,
|
||||||
|
pipelined: Option<Res<Pipelined>>,
|
||||||
|
frame_state: Res<OxrFrameState>,
|
||||||
|
mut query: Query<(
|
||||||
|
&mut Transform,
|
||||||
|
&XrSpatialTransform,
|
||||||
|
Option<&XrReferenceSpace>,
|
||||||
|
)>,
|
||||||
|
) {
|
||||||
|
for (mut transform, spatial, ref_space) in &mut query {
|
||||||
|
let ref_space = ref_space.unwrap_or(&default_ref_space);
|
||||||
|
if let Ok(space_location) = session.locate_space(
|
||||||
|
&spatial.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 = spatial
|
||||||
|
.offset
|
||||||
|
.transform_point(space_location.pose.position.to_vec3())
|
||||||
|
}
|
||||||
|
if space_location
|
||||||
|
.location_flags
|
||||||
|
.contains(SpaceLocationFlags::ORIENTATION_VALID)
|
||||||
|
{
|
||||||
|
transform.rotation =
|
||||||
|
spatial.offset.rotation * space_location.pose.orientation.to_quat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OxrSession {
|
||||||
|
pub fn create_action_space<T: openxr::ActionTy>(
|
||||||
|
&self,
|
||||||
|
action: &openxr::Action<T>,
|
||||||
|
subaction_path: openxr::Path,
|
||||||
|
pose_in_space: XrPose,
|
||||||
|
) -> openxr::Result<XrSpace> {
|
||||||
|
let info = sys::ActionSpaceCreateInfo {
|
||||||
|
ty: sys::ActionSpaceCreateInfo::TYPE,
|
||||||
|
next: ptr::null(),
|
||||||
|
action: action.as_raw(),
|
||||||
|
subaction_path,
|
||||||
|
pose_in_action_space: pose_in_space.to_posef(),
|
||||||
|
};
|
||||||
|
let mut out = sys::Space::NULL;
|
||||||
|
unsafe {
|
||||||
|
cvt((self.instance().fp().create_action_space)(
|
||||||
|
self.as_raw(),
|
||||||
|
&info,
|
||||||
|
&mut out,
|
||||||
|
))?;
|
||||||
|
Ok(XrSpace::from_raw(out.into_raw()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn create_reference_space(
|
||||||
|
&self,
|
||||||
|
ref_space_type: ReferenceSpaceType,
|
||||||
|
pose_in_ref_space: Transform,
|
||||||
|
) -> openxr::Result<XrReferenceSpace> {
|
||||||
|
let info = sys::ReferenceSpaceCreateInfo {
|
||||||
|
ty: sys::ReferenceSpaceCreateInfo::TYPE,
|
||||||
|
next: ptr::null(),
|
||||||
|
reference_space_type: ref_space_type,
|
||||||
|
pose_in_reference_space: pose_in_ref_space.to_posef(),
|
||||||
|
};
|
||||||
|
let mut out = sys::Space::NULL;
|
||||||
|
unsafe {
|
||||||
|
cvt((self.instance().fp().create_reference_space)(
|
||||||
|
self.as_raw(),
|
||||||
|
&info,
|
||||||
|
&mut out,
|
||||||
|
))?;
|
||||||
|
Ok(XrReferenceSpace(XrSpace::from_raw(out.into_raw())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn locate_space(
|
||||||
|
instance: &openxr::Instance,
|
||||||
|
space: &XrSpace,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<openxr::SpaceLocation> {
|
||||||
|
unsafe {
|
||||||
|
let mut x = sys::SpaceLocation::out(ptr::null_mut());
|
||||||
|
cvt((instance.fp().locate_space)(
|
||||||
|
space.as_raw_openxr_space(),
|
||||||
|
base.as_raw_openxr_space(),
|
||||||
|
time,
|
||||||
|
x.as_mut_ptr(),
|
||||||
|
))?;
|
||||||
|
Ok(create_space_location(&x))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn locate_space_with_velocity(
|
||||||
|
instance: &openxr::Instance,
|
||||||
|
space: &XrSpace,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<(openxr::SpaceLocation, openxr::SpaceVelocity)> {
|
||||||
|
unsafe {
|
||||||
|
let mut velocity = sys::SpaceVelocity::out(ptr::null_mut());
|
||||||
|
let mut location = sys::SpaceLocation::out(&mut velocity as *mut _ as _);
|
||||||
|
cvt((instance.fp().locate_space)(
|
||||||
|
space.as_raw_openxr_space(),
|
||||||
|
base.as_raw_openxr_space(),
|
||||||
|
time,
|
||||||
|
location.as_mut_ptr(),
|
||||||
|
))?;
|
||||||
|
Ok((
|
||||||
|
create_space_location(&location),
|
||||||
|
create_space_velocity(&velocity),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn locate_hand_joints(
|
||||||
|
instance: &openxr::Instance,
|
||||||
|
tracker: &openxr::HandTracker,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<Option<HandJointLocations>> {
|
||||||
|
unsafe {
|
||||||
|
let locate_info = sys::HandJointsLocateInfoEXT {
|
||||||
|
ty: sys::HandJointsLocateInfoEXT::TYPE,
|
||||||
|
next: ptr::null(),
|
||||||
|
base_space: base.as_raw_openxr_space(),
|
||||||
|
time,
|
||||||
|
};
|
||||||
|
let mut locations =
|
||||||
|
MaybeUninit::<[openxr::HandJointLocation; openxr::HAND_JOINT_COUNT]>::uninit();
|
||||||
|
let mut location_info = sys::HandJointLocationsEXT {
|
||||||
|
ty: sys::HandJointLocationsEXT::TYPE,
|
||||||
|
next: ptr::null_mut(),
|
||||||
|
is_active: false.into(),
|
||||||
|
joint_count: openxr::HAND_JOINT_COUNT as u32,
|
||||||
|
joint_locations: locations.as_mut_ptr() as _,
|
||||||
|
};
|
||||||
|
cvt((instance
|
||||||
|
.exts()
|
||||||
|
.ext_hand_tracking
|
||||||
|
.as_ref()
|
||||||
|
.expect("Somehow created HandTracker without XR_EXT_hand_tracking being enabled")
|
||||||
|
.locate_hand_joints)(
|
||||||
|
tracker.as_raw(),
|
||||||
|
&locate_info,
|
||||||
|
&mut location_info,
|
||||||
|
))?;
|
||||||
|
Ok(if location_info.is_active.into() {
|
||||||
|
Some(locations.assume_init())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn locate_hand_joints_with_velocities(
|
||||||
|
instance: &openxr::Instance,
|
||||||
|
tracker: &openxr::HandTracker,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<Option<(HandJointLocations, HandJointVelocities)>> {
|
||||||
|
unsafe {
|
||||||
|
let locate_info = sys::HandJointsLocateInfoEXT {
|
||||||
|
ty: sys::HandJointsLocateInfoEXT::TYPE,
|
||||||
|
next: ptr::null(),
|
||||||
|
base_space: base.as_raw_openxr_space(),
|
||||||
|
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((instance
|
||||||
|
.exts()
|
||||||
|
.ext_hand_tracking
|
||||||
|
.as_ref()
|
||||||
|
.expect("Somehow created HandTracker without XR_EXT_hand_tracking being enabled")
|
||||||
|
.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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn destroy_space(instance: &openxr::Instance, space: sys::Space) -> openxr::Result<sys::Result> {
|
||||||
|
let result = unsafe { (instance.fp().destroy_space)(space) };
|
||||||
|
cvt(result)
|
||||||
|
}
|
||||||
|
impl OxrSession {
|
||||||
|
pub fn destroy_space(&self, space: XrSpace) {
|
||||||
|
let _ = destroy_space(self.instance(), space.as_raw_openxr_space());
|
||||||
|
}
|
||||||
|
pub fn destroy_openxr_space(&self, space: openxr::Space) {
|
||||||
|
let _ = destroy_space(self.instance(), space.as_raw());
|
||||||
|
}
|
||||||
|
pub fn locate_views(
|
||||||
|
&self,
|
||||||
|
view_configuration_type: openxr::ViewConfigurationType,
|
||||||
|
display_time: openxr::Time,
|
||||||
|
ref_space: &XrReferenceSpace,
|
||||||
|
) -> openxr::Result<(openxr::ViewStateFlags, Vec<openxr::View>)> {
|
||||||
|
let info = sys::ViewLocateInfo {
|
||||||
|
ty: sys::ViewLocateInfo::TYPE,
|
||||||
|
next: ptr::null(),
|
||||||
|
view_configuration_type,
|
||||||
|
display_time,
|
||||||
|
space: ref_space.as_raw_openxr_space(),
|
||||||
|
};
|
||||||
|
let (flags, raw) = unsafe {
|
||||||
|
let mut out = sys::ViewState::out(ptr::null_mut());
|
||||||
|
let raw = get_arr_init(sys::View::out(ptr::null_mut()), |cap, count, buf| {
|
||||||
|
(self.instance().fp().locate_views)(
|
||||||
|
self.as_raw(),
|
||||||
|
&info,
|
||||||
|
out.as_mut_ptr(),
|
||||||
|
cap,
|
||||||
|
count,
|
||||||
|
buf as _,
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
(out.assume_init().view_state_flags, raw)
|
||||||
|
};
|
||||||
|
Ok((
|
||||||
|
flags,
|
||||||
|
raw.into_iter()
|
||||||
|
.map(|x| unsafe { create_view(flags, &x) })
|
||||||
|
.collect(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
pub fn locate_space(
|
||||||
|
&self,
|
||||||
|
space: &XrSpace,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<openxr::SpaceLocation> {
|
||||||
|
locate_space(self.instance(), space, base, time)
|
||||||
|
}
|
||||||
|
pub fn locate_space_with_velocity(
|
||||||
|
&self,
|
||||||
|
space: &XrSpace,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<(openxr::SpaceLocation, openxr::SpaceVelocity)> {
|
||||||
|
locate_space_with_velocity(self.instance(), space, base, time)
|
||||||
|
}
|
||||||
|
pub fn locate_hand_joints(
|
||||||
|
&self,
|
||||||
|
tracker: &openxr::HandTracker,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<Option<openxr::HandJointLocations>> {
|
||||||
|
locate_hand_joints(self.instance(), tracker, base, time)
|
||||||
|
}
|
||||||
|
pub fn locate_hand_joints_with_velocities(
|
||||||
|
&self,
|
||||||
|
tracker: &openxr::HandTracker,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<Option<(HandJointLocations, HandJointVelocities)>> {
|
||||||
|
locate_hand_joints_with_velocities(self.instance(), tracker, base, time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl OxrInstance {
|
||||||
|
pub fn locate_space(
|
||||||
|
&self,
|
||||||
|
space: &XrSpace,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<openxr::SpaceLocation> {
|
||||||
|
locate_space(self, space, base, time)
|
||||||
|
}
|
||||||
|
pub fn locate_space_with_velocity(
|
||||||
|
&self,
|
||||||
|
space: &XrSpace,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<(openxr::SpaceLocation, openxr::SpaceVelocity)> {
|
||||||
|
locate_space_with_velocity(self, space, base, time)
|
||||||
|
}
|
||||||
|
pub fn locate_hand_joints(
|
||||||
|
&self,
|
||||||
|
tracker: &openxr::HandTracker,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<Option<openxr::HandJointLocations>> {
|
||||||
|
locate_hand_joints(self, tracker, base, time)
|
||||||
|
}
|
||||||
|
pub fn locate_hand_joints_with_velocities(
|
||||||
|
&self,
|
||||||
|
tracker: &openxr::HandTracker,
|
||||||
|
base: &XrSpace,
|
||||||
|
time: openxr::Time,
|
||||||
|
) -> openxr::Result<Option<(HandJointLocations, HandJointVelocities)>> {
|
||||||
|
locate_hand_joints_with_velocities(self, tracker, base, time)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # Safety
|
||||||
|
/// This is an Extension trait. DO NOT IMPLEMENT IT!
|
||||||
|
pub unsafe trait OxrSpaceExt {
|
||||||
|
fn as_raw_openxr_space(&self) -> sys::Space;
|
||||||
|
fn from_raw_openxr_space(space: sys::Space) -> Self;
|
||||||
|
fn from_openxr_space(space: openxr::Space) -> Self;
|
||||||
|
/// # Safety
|
||||||
|
/// Session has to be the session from which the space is from
|
||||||
|
unsafe fn to_openxr_space<T>(self, session: &openxr::Session<T>) -> openxr::Space;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl OxrSpaceExt for XrSpace {
|
||||||
|
fn as_raw_openxr_space(&self) -> sys::Space {
|
||||||
|
sys::Space::from_raw(self.as_raw())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_raw_openxr_space(space: sys::Space) -> Self {
|
||||||
|
let raw = space.into_raw();
|
||||||
|
OXR_DO_NOT_CALL_DESTOY_SPACE_FOR
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.insert(raw);
|
||||||
|
unsafe { XrSpace::from_raw(raw) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_openxr_space(space: openxr::Space) -> Self {
|
||||||
|
Self::from_raw_openxr_space(space.as_raw())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn to_openxr_space<T>(self, session: &openxr::Session<T>) -> openxr::Space {
|
||||||
|
unsafe { openxr::Space::reference_from_raw(session.clone(), self.as_raw_openxr_space()) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cvt(x: sys::Result) -> openxr::Result<sys::Result> {
|
||||||
|
if x.into_raw() >= 0 {
|
||||||
|
Ok(x)
|
||||||
|
} else {
|
||||||
|
Err(x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe fn create_view(flags: openxr::ViewStateFlags, raw: &MaybeUninit<sys::View>) -> openxr::View {
|
||||||
|
// Applications *must* not read invalid parts of a poses, i.e. they may be uninitialized
|
||||||
|
let ptr = raw.as_ptr();
|
||||||
|
openxr::View {
|
||||||
|
pose: openxr::Posef {
|
||||||
|
orientation: flags
|
||||||
|
.contains(sys::ViewStateFlags::ORIENTATION_VALID)
|
||||||
|
.then(|| *ptr::addr_of!((*ptr).pose.orientation))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
position: flags
|
||||||
|
.contains(sys::ViewStateFlags::POSITION_VALID)
|
||||||
|
.then(|| *ptr::addr_of!((*ptr).pose.position))
|
||||||
|
.unwrap_or_default(),
|
||||||
|
},
|
||||||
|
fov: *ptr::addr_of!((*ptr).fov),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe fn create_space_location(raw: &MaybeUninit<sys::SpaceLocation>) -> openxr::SpaceLocation {
|
||||||
|
// Applications *must* not read invalid parts of a pose, i.e. they may be uninitialized
|
||||||
|
let ptr = raw.as_ptr();
|
||||||
|
let flags = *ptr::addr_of!((*ptr).location_flags);
|
||||||
|
openxr::SpaceLocation {
|
||||||
|
location_flags: flags,
|
||||||
|
pose: openxr::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(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsafe fn create_space_velocity(raw: &MaybeUninit<sys::SpaceVelocity>) -> openxr::SpaceVelocity {
|
||||||
|
// Applications *must* not read invalid velocities, i.e. they may be uninitialized
|
||||||
|
let ptr = raw.as_ptr();
|
||||||
|
let flags = *ptr::addr_of!((*ptr).velocity_flags);
|
||||||
|
openxr::SpaceVelocity {
|
||||||
|
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(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn get_arr_init<T: Copy>(
|
||||||
|
init: T,
|
||||||
|
mut getter: impl FnMut(u32, &mut u32, *mut T) -> sys::Result,
|
||||||
|
) -> openxr::Result<Vec<T>> {
|
||||||
|
let mut output = 0;
|
||||||
|
cvt(getter(0, &mut output, std::ptr::null_mut()))?;
|
||||||
|
let mut buffer = vec![init; output as usize];
|
||||||
|
loop {
|
||||||
|
match cvt(getter(output, &mut output, buffer.as_mut_ptr() as _)) {
|
||||||
|
Ok(_) => {
|
||||||
|
buffer.truncate(output as usize);
|
||||||
|
return Ok(buffer);
|
||||||
|
}
|
||||||
|
Err(sys::Result::ERROR_SIZE_INSUFFICIENT) => {
|
||||||
|
buffer.resize(output as usize, init);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
return Err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,3 +3,4 @@ pub mod camera;
|
|||||||
pub mod hands;
|
pub mod hands;
|
||||||
pub mod session;
|
pub mod session;
|
||||||
pub mod types;
|
pub mod types;
|
||||||
|
pub mod spaces;
|
||||||
|
|||||||
46
crates/bevy_xr/src/spaces.rs
Normal file
46
crates/bevy_xr/src/spaces.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
use bevy::{
|
||||||
|
prelude::*,
|
||||||
|
render::{extract_component::ExtractComponent, extract_resource::ExtractResource},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Any Spaces will be invalid after the owning session exits
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug)]
|
||||||
|
pub struct XrSpace(u64);
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Reflect, Debug, Component, ExtractComponent)]
|
||||||
|
pub struct XrSpatialTransform {
|
||||||
|
pub space: XrSpace,
|
||||||
|
pub offset: Transform,
|
||||||
|
}
|
||||||
|
impl XrSpatialTransform {
|
||||||
|
pub const fn from_space(space: XrSpace) -> Self {
|
||||||
|
Self { space, offset: Transform::IDENTITY }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Event, Clone, Copy, Deref, DerefMut)]
|
||||||
|
pub struct XrDestroySpace(pub XrSpace);
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(
|
||||||
|
Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, Component, Deref, DerefMut, ExtractComponent,
|
||||||
|
)]
|
||||||
|
pub struct XrReferenceSpace(pub XrSpace);
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(
|
||||||
|
Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, Resource, Deref, DerefMut, ExtractResource,
|
||||||
|
)]
|
||||||
|
pub struct XrPrimaryReferenceSpace(pub XrReferenceSpace);
|
||||||
|
|
||||||
|
impl XrSpace {
|
||||||
|
/// # Safety
|
||||||
|
/// only call with known valid handles
|
||||||
|
pub unsafe fn from_raw(handle: u64) -> Self {
|
||||||
|
Self(handle)
|
||||||
|
}
|
||||||
|
pub fn as_raw(&self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,13 @@
|
|||||||
use bevy::math::{Quat, Vec3};
|
use bevy::math::{Quat, Vec3};
|
||||||
|
|
||||||
pub struct Pose {
|
pub struct XrPose {
|
||||||
pub position: Vec3,
|
pub position: Vec3,
|
||||||
pub orientation: Quat,
|
pub rotation: Quat,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XrPose {
|
||||||
|
pub const IDENTITY: XrPose = XrPose {
|
||||||
|
position: Vec3::ZERO,
|
||||||
|
rotation: Quat::IDENTITY,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,42 +56,59 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_openxr::{
|
use bevy_openxr::{
|
||||||
action_binding::OxrSuggestActionBinding, action_set_attaching::OxrAttachActionSet,
|
action_binding::OxrSuggestActionBinding, action_set_attaching::OxrAttachActionSet,
|
||||||
|
action_set_syncing::OxrActionSetSyncSet, action_set_syncing::OxrSyncActionSet,
|
||||||
resources::OxrInstance, session::OxrSession,
|
resources::OxrInstance, session::OxrSession,
|
||||||
};
|
};
|
||||||
use openxr::{ActiveActionSet, Path, Vector2f};
|
use bevy_xr::session::{session_available, session_running};
|
||||||
|
use openxr::{Path, Vector2f};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
|
|
||||||
pub struct XRUtilsActionsPlugin;
|
pub struct XRUtilsActionsPlugin;
|
||||||
impl Plugin for XRUtilsActionsPlugin {
|
impl Plugin for XRUtilsActionsPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
|
app.configure_sets(
|
||||||
|
Startup,
|
||||||
|
XRUtilsActionSystemSet::CreateEvents.run_if(session_available),
|
||||||
|
);
|
||||||
|
app.configure_sets(
|
||||||
|
PreUpdate,
|
||||||
|
XRUtilsActionSystemSet::SyncActionStates.run_if(session_running),
|
||||||
|
);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Startup,
|
Startup,
|
||||||
create_openxr_events.in_set(XRUtilsActionSystemSet::CreateEvents),
|
create_openxr_events.in_set(XRUtilsActionSystemSet::CreateEvents),
|
||||||
);
|
);
|
||||||
|
<<<<<<< HEAD
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Update,
|
Update,
|
||||||
sync_active_action_sets.run_if(resource_exists::<OxrSession>),
|
sync_active_action_sets.run_if(resource_exists::<OxrSession>),
|
||||||
);
|
);
|
||||||
|
=======
|
||||||
|
>>>>>>> 47b64a4 (add new XrSpace and impl that)
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Update,
|
PreUpdate,
|
||||||
|
sync_active_action_sets.before(OxrActionSetSyncSet),
|
||||||
|
);
|
||||||
|
app.add_systems(
|
||||||
|
PreUpdate,
|
||||||
sync_and_update_action_states_f32
|
sync_and_update_action_states_f32
|
||||||
.run_if(resource_exists::<OxrSession>)
|
.run_if(resource_exists::<OxrSession>)
|
||||||
.in_set(XRUtilsActionSystemSet::SyncActionStates)
|
.in_set(XRUtilsActionSystemSet::SyncActionStates)
|
||||||
.after(sync_active_action_sets),
|
.after(OxrActionSetSyncSet),
|
||||||
);
|
);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Update,
|
PreUpdate,
|
||||||
sync_and_update_action_states_bool
|
sync_and_update_action_states_bool
|
||||||
.run_if(resource_exists::<OxrSession>)
|
.run_if(resource_exists::<OxrSession>)
|
||||||
.in_set(XRUtilsActionSystemSet::SyncActionStates)
|
.in_set(XRUtilsActionSystemSet::SyncActionStates)
|
||||||
.after(sync_active_action_sets),
|
.after(OxrActionSetSyncSet),
|
||||||
);
|
);
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
Update,
|
PreUpdate,
|
||||||
sync_and_update_action_states_vector
|
sync_and_update_action_states_vector
|
||||||
.run_if(resource_exists::<OxrSession>)
|
.run_if(resource_exists::<OxrSession>)
|
||||||
.in_set(XRUtilsActionSystemSet::SyncActionStates)
|
.in_set(XRUtilsActionSystemSet::SyncActionStates)
|
||||||
.after(sync_active_action_sets),
|
.after(OxrActionSetSyncSet),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,9 +164,9 @@ fn create_openxr_events(
|
|||||||
//interaction profile
|
//interaction profile
|
||||||
//get the binding entity and stuff
|
//get the binding entity and stuff
|
||||||
let create_binding = bindings_query.get(bind).unwrap();
|
let create_binding = bindings_query.get(bind).unwrap();
|
||||||
let profile = Cow::from(create_binding.profile.clone());
|
let profile = create_binding.profile.clone();
|
||||||
//bindings
|
//bindings
|
||||||
let binding = vec![Cow::from(create_binding.binding.clone())];
|
let binding = vec![create_binding.binding.clone()];
|
||||||
let sugestion = OxrSuggestActionBinding {
|
let sugestion = OxrSuggestActionBinding {
|
||||||
action: action.as_raw(),
|
action: action.as_raw(),
|
||||||
interaction_profile: profile,
|
interaction_profile: profile,
|
||||||
@@ -186,9 +203,9 @@ fn create_openxr_events(
|
|||||||
//interaction profile
|
//interaction profile
|
||||||
//get the binding entity and stuff
|
//get the binding entity and stuff
|
||||||
let create_binding = bindings_query.get(bind).unwrap();
|
let create_binding = bindings_query.get(bind).unwrap();
|
||||||
let profile = Cow::from(create_binding.profile.clone());
|
let profile = create_binding.profile.clone();
|
||||||
//bindings
|
//bindings
|
||||||
let binding = vec![Cow::from(create_binding.binding.clone())];
|
let binding = vec![create_binding.binding.clone()];
|
||||||
let sugestion = OxrSuggestActionBinding {
|
let sugestion = OxrSuggestActionBinding {
|
||||||
action: action.as_raw(),
|
action: action.as_raw(),
|
||||||
interaction_profile: profile,
|
interaction_profile: profile,
|
||||||
@@ -225,9 +242,9 @@ fn create_openxr_events(
|
|||||||
//interaction profile
|
//interaction profile
|
||||||
//get the binding entity and stuff
|
//get the binding entity and stuff
|
||||||
let create_binding = bindings_query.get(bind).unwrap();
|
let create_binding = bindings_query.get(bind).unwrap();
|
||||||
let profile = Cow::from(create_binding.profile.clone());
|
let profile = create_binding.profile.clone();
|
||||||
//bindings
|
//bindings
|
||||||
let binding = vec![Cow::from(create_binding.binding.clone())];
|
let binding = vec![create_binding.binding.clone()];
|
||||||
let sugestion = OxrSuggestActionBinding {
|
let sugestion = OxrSuggestActionBinding {
|
||||||
action: action.as_raw(),
|
action: action.as_raw(),
|
||||||
interaction_profile: profile,
|
interaction_profile: profile,
|
||||||
@@ -245,9 +262,10 @@ fn create_openxr_events(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sync_active_action_sets(
|
fn sync_active_action_sets(
|
||||||
session: Res<OxrSession>,
|
mut sync_set: EventWriter<OxrSyncActionSet>,
|
||||||
active_action_set_query: Query<&XRUtilsActionSetReference, With<ActiveSet>>,
|
active_action_set_query: Query<&XRUtilsActionSetReference, With<ActiveSet>>,
|
||||||
) {
|
) {
|
||||||
|
<<<<<<< HEAD
|
||||||
let active_sets = active_action_set_query
|
let active_sets = active_action_set_query
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| ActiveActionSet::from(&v.0))
|
.map(|v| ActiveActionSet::from(&v.0))
|
||||||
@@ -256,6 +274,10 @@ fn sync_active_action_sets(
|
|||||||
match sync {
|
match sync {
|
||||||
Ok(_) => (),
|
Ok(_) => (),
|
||||||
Err(_) => error!("sync error"),
|
Err(_) => error!("sync error"),
|
||||||
|
=======
|
||||||
|
for set in &active_action_set_query {
|
||||||
|
sync_set.send(OxrSyncActionSet(set.0.clone()));
|
||||||
|
>>>>>>> 47b64a4 (add new XrSpace and impl that)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,7 +358,9 @@ fn sync_and_update_action_states_vector(
|
|||||||
|
|
||||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
|
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
|
||||||
pub enum XRUtilsActionSystemSet {
|
pub enum XRUtilsActionSystemSet {
|
||||||
|
/// Runs in Startup
|
||||||
CreateEvents,
|
CreateEvents,
|
||||||
|
/// Runs in PreUpdate
|
||||||
SyncActionStates,
|
SyncActionStates,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user