Merge pull request #178 from awtterpip/bevy-0.16

0.16 support
This commit is contained in:
Schmarni
2025-04-26 16:19:23 +02:00
committed by GitHub
29 changed files with 1589 additions and 1046 deletions

2316
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,7 +10,7 @@ resolver = "2"
members = ["crates/*", "crates/bevy_openxr/examples/android"] members = ["crates/*", "crates/bevy_openxr/examples/android"]
[workspace.dependencies] [workspace.dependencies]
bevy = { version = "0.15", default-features = false, features = [ bevy = { version = "0.16.0", default-features = false, features = [
"bevy_render", "bevy_render",
"bevy_core_pipeline", "bevy_core_pipeline",
"bevy_winit", "bevy_winit",
@@ -23,5 +23,5 @@ bevy_mod_openxr = { path = "crates/bevy_openxr", version = "0.2.1" }
bevy_xr_utils = { path = "crates/bevy_xr_utils", version = "0.2.1" } bevy_xr_utils = { path = "crates/bevy_xr_utils", version = "0.2.1" }
openxr = "0.19.0" openxr = "0.19.0"
thiserror = "2.0.3" thiserror = "2.0.3"
wgpu = "23" wgpu = "24.0.1"
wgpu-hal = "23" wgpu-hal = "24.0.2"

View File

@@ -21,8 +21,8 @@ fn main() {
.add_systems(Update, handle_flight_input) .add_systems(Update, handle_flight_input)
// 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(),
brightness: 500.0, brightness: 500.0,
..AmbientLight::default()
}) })
.run(); .run();
} }
@@ -48,7 +48,7 @@ fn setup_scene(
commands.spawn(( commands.spawn((
Camera3d::default(), Camera3d::default(),
Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y), Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
)); ));
} }
@@ -132,14 +132,15 @@ fn handle_flight_input(
//hard code speed for now //hard code speed for now
let speed = 5.0; let speed = 5.0;
let root = oxr_root.get_single_mut(); let root = oxr_root.single_mut();
match root { match root {
Ok(mut root_position) => { Ok(mut root_position) => {
//lets assume HMD based direction for now //lets assume HMD based direction for now
let view = views.first(); let view = views.first();
match view { match view {
Some(v) => { Some(v) => {
let reference_quat = root_position.rotation * v.pose.orientation.to_quat(); let reference_quat =
root_position.rotation * v.pose.orientation.to_quat();
let locomotion_vector = reference_quat.mul_vec3(input_vector); let locomotion_vector = reference_quat.mul_vec3(input_vector);
root_position.translation += root_position.translation +=

View File

@@ -7,18 +7,13 @@ use bevy_mod_openxr::{add_xr_plugins, init::OxrInitPlugin, types::OxrExtensions}
fn main() { fn main() {
App::new() App::new()
.add_plugins(add_xr_plugins(DefaultPlugins).set(OxrInitPlugin { .add_plugins(add_xr_plugins(DefaultPlugins).set(OxrInitPlugin {
app_info: default(),
exts: { exts: {
let mut exts = OxrExtensions::default(); let mut exts = OxrExtensions::default();
exts.enable_fb_passthrough(); exts.enable_fb_passthrough();
exts.enable_hand_tracking(); exts.enable_hand_tracking();
exts exts
}, },
blend_modes: default(), ..default()
backends: default(),
formats: default(),
resolutions: default(),
synchronous_pipeline_compilation: default(),
})) }))
.add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin) .add_plugins(bevy_xr_utils::hand_gizmos::HandGizmosPlugin)
.add_systems(Startup, setup) .add_systems(Startup, setup)
@@ -26,6 +21,7 @@ fn main() {
.insert_resource(AmbientLight { .insert_resource(AmbientLight {
color: Default::default(), color: Default::default(),
brightness: 500.0, brightness: 500.0,
affects_lightmapped_meshes: false,
}) })
.insert_resource(ClearColor(Color::NONE)) .insert_resource(ClearColor(Color::NONE))
.run(); .run();

View File

@@ -49,23 +49,23 @@ fn handle_input(
) { ) {
if keys.just_pressed(KeyCode::KeyE) { if keys.just_pressed(KeyCode::KeyE) {
info!("sending end"); info!("sending end");
end.send_default(); end.write_default();
} }
if keys.just_pressed(KeyCode::KeyC) { if keys.just_pressed(KeyCode::KeyC) {
info!("sending create"); info!("sending create");
create.send_default(); create.write_default();
} }
if keys.just_pressed(KeyCode::KeyD) { if keys.just_pressed(KeyCode::KeyD) {
info!("sending destroy"); info!("sending destroy");
destroy.send_default(); destroy.write_default();
} }
if keys.just_pressed(KeyCode::KeyB) { if keys.just_pressed(KeyCode::KeyB) {
info!("sending begin"); info!("sending begin");
begin.send_default(); begin.write_default();
} }
if keys.just_pressed(KeyCode::KeyR) { if keys.just_pressed(KeyCode::KeyR) {
info!("sending request exit"); info!("sending request exit");
request_exit.send_default(); request_exit.write_default();
} }
} }

View File

@@ -35,7 +35,7 @@ fn main() {
} }
fn attach_set(actions: Res<ControllerActions>, mut attach: EventWriter<OxrAttachActionSet>) { fn attach_set(actions: Res<ControllerActions>, mut attach: EventWriter<OxrAttachActionSet>) {
attach.send(OxrAttachActionSet(actions.set.clone())); attach.write(OxrAttachActionSet(actions.set.clone()));
} }
#[derive(Resource)] #[derive(Resource)]
@@ -45,7 +45,7 @@ struct ControllerActions {
right: openxr::Action<Posef>, right: openxr::Action<Posef>,
} }
fn sync_actions(actions: Res<ControllerActions>, mut sync: EventWriter<OxrSyncActionSet>) { fn sync_actions(actions: Res<ControllerActions>, mut sync: EventWriter<OxrSyncActionSet>) {
sync.send(OxrSyncActionSet(actions.set.clone())); sync.write(OxrSyncActionSet(actions.set.clone()));
} }
/// set up a simple 3D scene /// set up a simple 3D scene
fn setup( fn setup(
@@ -82,12 +82,12 @@ fn suggest_action_bindings(
actions: Res<ControllerActions>, actions: Res<ControllerActions>,
mut bindings: EventWriter<OxrSuggestActionBinding>, mut bindings: EventWriter<OxrSuggestActionBinding>,
) { ) {
bindings.send(OxrSuggestActionBinding { bindings.write(OxrSuggestActionBinding {
action: actions.left.as_raw(), action: actions.left.as_raw(),
interaction_profile: "/interaction_profiles/oculus/touch_controller".into(), interaction_profile: "/interaction_profiles/oculus/touch_controller".into(),
bindings: vec!["/user/hand/left/input/grip/pose".into()], bindings: vec!["/user/hand/left/input/grip/pose".into()],
}); });
bindings.send(OxrSuggestActionBinding { bindings.write(OxrSuggestActionBinding {
action: actions.right.as_raw(), action: actions.right.as_raw(),
interaction_profile: "/interaction_profiles/oculus/touch_controller".into(), interaction_profile: "/interaction_profiles/oculus/touch_controller".into(),
bindings: vec!["/user/hand/right/input/grip/pose".into()], bindings: vec!["/user/hand/right/input/grip/pose".into()],

View File

@@ -32,23 +32,23 @@ fn handle_input(
) { ) {
if keys.just_pressed(KeyCode::KeyE) { if keys.just_pressed(KeyCode::KeyE) {
info!("sending end"); info!("sending end");
end.send_default(); end.write_default();
} }
if keys.just_pressed(KeyCode::KeyC) { if keys.just_pressed(KeyCode::KeyC) {
info!("sending create"); info!("sending create");
create.send_default(); create.write_default();
} }
if keys.just_pressed(KeyCode::KeyD) { if keys.just_pressed(KeyCode::KeyD) {
info!("sending destroy"); info!("sending destroy");
destroy.send_default(); destroy.write_default();
} }
if keys.just_pressed(KeyCode::KeyB) { if keys.just_pressed(KeyCode::KeyB) {
info!("sending begin"); info!("sending begin");
begin.send_default(); begin.write_default();
} }
if keys.just_pressed(KeyCode::KeyR) { if keys.just_pressed(KeyCode::KeyR) {
info!("sending request exit"); info!("sending request exit");
request_exit.send_default(); request_exit.write_default();
} }
if keys.just_pressed(KeyCode::KeyI) { if keys.just_pressed(KeyCode::KeyI) {
info!("current state: {:?}", *state); info!("current state: {:?}", *state);

View File

@@ -28,8 +28,8 @@ fn main() {
send_recenter.after(XRUtilsActionSystemSet::SyncActionStates), send_recenter.after(XRUtilsActionSystemSet::SyncActionStates),
) )
.insert_resource(AmbientLight { .insert_resource(AmbientLight {
color: Default::default(),
brightness: 500.0, brightness: 500.0,
..AmbientLight::default()
}) })
.run(); .run();
} }
@@ -161,7 +161,7 @@ fn send_look_at_red_cube_event(
info!("send facing"); info!("send facing");
let quat = Transform::default() let quat = Transform::default()
.looking_at(Transform::from_xyz(4.0, 0.0, 0.0).translation, Vec3::Y); //this is a transform facing the red cube from the center of the scene, you should use the HMD posision but I was lazy. .looking_at(Transform::from_xyz(4.0, 0.0, 0.0).translation, Vec3::Y); //this is a transform facing the red cube from the center of the scene, you should use the HMD posision but I was lazy.
event_writer.send(SnapToRotation(quat.rotation)); event_writer.write(SnapToRotation(quat.rotation));
} }
} }
XRUtilsActionState::Float(_) => (), XRUtilsActionState::Float(_) => (),
@@ -185,7 +185,7 @@ fn send_recenter(
if send { if send {
let center = Transform::default().translation; let center = Transform::default().translation;
event_writer.send(SnapToPosition(center)); event_writer.write(SnapToPosition(center));
} }
} }
XRUtilsActionState::Float(_) => (), XRUtilsActionState::Float(_) => (),

View File

@@ -3,8 +3,8 @@ use std::ptr;
use bevy::ecs::schedule::ScheduleLabel; use bevy::ecs::schedule::ScheduleLabel;
use bevy::ecs::system::RunSystemOnce; use bevy::ecs::system::RunSystemOnce;
use bevy::platform::collections::HashMap;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::utils::HashMap;
use bevy_mod_xr::session::XrSessionCreatedEvent; use bevy_mod_xr::session::XrSessionCreatedEvent;
use openxr::sys::ActionSuggestedBinding; use openxr::sys::ActionSuggestedBinding;

View File

@@ -1,7 +1,4 @@
use bevy::{ use bevy::prelude::{Deref, DerefMut, Resource};
ecs::system::Resource,
prelude::{Deref, DerefMut},
};
use openxr::ExtensionSet; use openxr::ExtensionSet;
#[derive(Clone, Debug, Eq, PartialEq, Deref, DerefMut, Resource)] #[derive(Clone, Debug, Eq, PartialEq, Deref, DerefMut, Resource)]

View File

@@ -110,7 +110,7 @@ fn clean_up_default_hands(
) { ) {
for e in &query { for e in &query {
debug!("removing default hand entity"); debug!("removing default hand entity");
cmds.entity(e).despawn_recursive(); cmds.entity(e).despawn();
} }
} }

View File

@@ -27,7 +27,7 @@ impl Plugin for OxrOverlayPlugin {
fn handle_overlay_event(event: OxrEventIn, mut writer: EventWriter<OxrOverlaySessionEvent>) { fn handle_overlay_event(event: OxrEventIn, mut writer: EventWriter<OxrOverlaySessionEvent>) {
if let Event::MainSessionVisibilityChangedEXTX(event) = *event { if let Event::MainSessionVisibilityChangedEXTX(event) = *event {
writer.send(OxrOverlaySessionEvent::MainSessionVisibilityChanged { writer.write(OxrOverlaySessionEvent::MainSessionVisibilityChanged {
visible: event.visible(), visible: event.visible(),
flags: event.flags(), flags: event.flags(),
}); });

View File

@@ -8,7 +8,7 @@ use openxr::PassthroughCapabilityFlagsFB;
use crate::layer_builder::PassthroughLayer; use crate::layer_builder::PassthroughLayer;
use crate::resources::*; use crate::resources::*;
use crate::session::OxrSession; use crate::session::OxrSession;
use crate::types::*; use crate::types::Result as OxrResult;
pub struct OxrPassthroughPlugin; pub struct OxrPassthroughPlugin;
@@ -73,7 +73,7 @@ pub fn create_passthrough(
session: &OxrSession, session: &OxrSession,
flags: openxr::PassthroughFlagsFB, flags: openxr::PassthroughFlagsFB,
purpose: openxr::PassthroughLayerPurposeFB, purpose: openxr::PassthroughLayerPurposeFB,
) -> Result<(OxrPassthrough, OxrPassthroughLayer)> { ) -> OxrResult<(OxrPassthrough, OxrPassthroughLayer)> {
let passthrough = session.create_passthrough(flags)?; let passthrough = session.create_passthrough(flags)?;
let passthrough_layer = session.create_passthrough_layer(&passthrough, purpose)?; let passthrough_layer = session.create_passthrough_layer(&passthrough, purpose)?;
@@ -82,7 +82,10 @@ pub fn create_passthrough(
} }
#[inline] #[inline]
pub fn supports_passthrough(instance: &OxrInstance, system: OxrSystemId) -> Result<bool> { pub fn supports_passthrough(
instance: &OxrInstance,
system: OxrSystemId,
) -> OxrResult<bool> {
if instance.exts().fb_passthrough.is_none() { if instance.exts().fb_passthrough.is_none() {
return Ok(false); return Ok(false);
} }

View File

@@ -115,7 +115,6 @@ unsafe impl GraphicsExt for openxr::Vulkan {
<Vulkan as Api>::Instance::desired_extensions(&vk_entry, VK_TARGET_VERSION_ASH, flags)?; <Vulkan as Api>::Instance::desired_extensions(&vk_entry, VK_TARGET_VERSION_ASH, flags)?;
let device_extensions = [ let device_extensions = [
ash::khr::swapchain::NAME, ash::khr::swapchain::NAME,
#[cfg(target_os = "android")]
ash::khr::draw_indirect_count::NAME, ash::khr::draw_indirect_count::NAME,
ash::khr::timeline_semaphore::NAME, ash::khr::timeline_semaphore::NAME,
ash::khr::imageless_framebuffer::NAME, ash::khr::imageless_framebuffer::NAME,
@@ -197,8 +196,7 @@ unsafe impl GraphicsExt for openxr::Vulkan {
"Couldn't parse Android's ", "Couldn't parse Android's ",
"ro.build.version.sdk system property ({}): {}", "ro.build.version.sdk system property ({}): {}",
), ),
val, val, err,
err,
); );
0 0
} }
@@ -652,6 +650,7 @@ fn wgpu_to_vulkan(format: wgpu::TextureFormat) -> Option<ash::vk::Format> {
Tf::R32Uint => F::R32_UINT, Tf::R32Uint => F::R32_UINT,
Tf::R32Sint => F::R32_SINT, Tf::R32Sint => F::R32_SINT,
Tf::R32Float => F::R32_SFLOAT, Tf::R32Float => F::R32_SFLOAT,
Tf::R64Uint => F::R64_UINT,
Tf::Rg16Uint => F::R16G16_UINT, Tf::Rg16Uint => F::R16G16_UINT,
Tf::Rg16Sint => F::R16G16_SINT, Tf::Rg16Sint => F::R16G16_SINT,
Tf::Rg16Float => F::R16G16_SFLOAT, Tf::Rg16Float => F::R16G16_SFLOAT,

View File

@@ -13,6 +13,7 @@ use bevy::render::settings::RenderCreation;
use bevy::render::MainWorld; use bevy::render::MainWorld;
use bevy::render::Render; use bevy::render::Render;
use bevy::render::RenderApp; use bevy::render::RenderApp;
use bevy::render::RenderDebugFlags;
use bevy::render::RenderPlugin; use bevy::render::RenderPlugin;
use bevy::winit::UpdateMode; use bevy::winit::UpdateMode;
use bevy::winit::WinitSettings; use bevy::winit::WinitSettings;
@@ -24,11 +25,12 @@ use crate::graphics::*;
use crate::resources::*; use crate::resources::*;
use crate::session::OxrSession; use crate::session::OxrSession;
use crate::session::OxrSessionCreateNextChain; use crate::session::OxrSessionCreateNextChain;
use crate::types::Result as OxrResult;
use crate::types::*; use crate::types::*;
use super::exts::OxrEnabledExtensions; use super::exts::OxrEnabledExtensions;
use super::poll_events::OxrEventIn;
use super::poll_events::OxrEventHandlerExt; use super::poll_events::OxrEventHandlerExt;
use super::poll_events::OxrEventIn;
pub fn session_started(started: Option<Res<OxrSessionStarted>>) -> bool { pub fn session_started(started: Option<Res<OxrSessionStarted>>) -> bool {
started.is_some_and(|started| started.0) started.is_some_and(|started| started.0)
@@ -62,6 +64,7 @@ pub struct OxrInitPlugin {
pub resolutions: Option<Vec<UVec2>>, pub resolutions: Option<Vec<UVec2>>,
/// Passed into the render plugin when added to the app. /// Passed into the render plugin when added to the app.
pub synchronous_pipeline_compilation: bool, pub synchronous_pipeline_compilation: bool,
pub render_debug_flags: RenderDebugFlags,
} }
impl Default for OxrInitPlugin { impl Default for OxrInitPlugin {
fn default() -> Self { fn default() -> Self {
@@ -73,11 +76,12 @@ impl Default for OxrInitPlugin {
exts.enable_hand_tracking(); exts.enable_hand_tracking();
exts exts
}, },
blend_modes: default(), blend_modes: Some(vec![openxr::EnvironmentBlendMode::OPAQUE]),
backends: default(), backends: default(),
formats: Some(vec![wgpu::TextureFormat::Rgba8UnormSrgb]), formats: Some(vec![wgpu::TextureFormat::Rgba8UnormSrgb]),
resolutions: default(), resolutions: default(),
synchronous_pipeline_compilation: false, synchronous_pipeline_compilation: false,
render_debug_flags: default(),
} }
} }
} }
@@ -104,6 +108,7 @@ impl Plugin for OxrInitPlugin {
RenderInstance(Arc::new(WgpuWrapper::new(wgpu_instance))), RenderInstance(Arc::new(WgpuWrapper::new(wgpu_instance))),
), ),
synchronous_pipeline_compilation: self.synchronous_pipeline_compilation, synchronous_pipeline_compilation: self.synchronous_pipeline_compilation,
debug_flags: self.render_debug_flags,
}, },
ExtractResourcePlugin::<OxrSessionStarted>::default(), ExtractResourcePlugin::<OxrSessionStarted>::default(),
)) ))
@@ -197,7 +202,7 @@ fn detect_session_destroyed(
let state = state.0.load(Ordering::Relaxed); let state = state.0.load(Ordering::Relaxed);
if *last_state && !state { if *last_state && !state {
debug!("XrSession was fully destroyed!"); debug!("XrSession was fully destroyed!");
sender.send_default(); sender.write_default();
cmds.insert_resource(XrState::Available); cmds.insert_resource(XrState::Available);
} }
*last_state = state; *last_state = state;
@@ -206,7 +211,7 @@ fn detect_session_destroyed(
impl OxrInitPlugin { impl OxrInitPlugin {
fn init_xr( fn init_xr(
&self, &self,
) -> Result<( ) -> OxrResult<(
OxrInstance, OxrInstance,
OxrSystemId, OxrSystemId,
WgpuGraphics, WgpuGraphics,
@@ -326,14 +331,14 @@ pub fn handle_events(
}, },
_ => unreachable!(), _ => unreachable!(),
}; };
changed_event.send(XrStateChanged(new_status)); changed_event.write(XrStateChanged(new_status));
*status = new_status; *status = new_status;
} }
InstanceLossPending(_) => {} InstanceLossPending(_) => {}
EventsLost(e) => warn!("lost {} XR events", e.lost_event_count()), EventsLost(e) => warn!("lost {} XR events", e.lost_event_count()),
// we might want to check if this is the correct session? // we might want to check if this is the correct session?
Event::InteractionProfileChanged(_) => { Event::InteractionProfileChanged(_) => {
interaction_profile_changed_event.send_default(); interaction_profile_changed_event.write_default();
} }
_ => {} _ => {}
} }
@@ -350,7 +355,7 @@ fn init_xr_session(
resolutions, resolutions,
graphics_info, graphics_info,
}: SessionConfigInfo, }: SessionConfigInfo,
) -> Result<( ) -> OxrResult<(
OxrSession, OxrSession,
OxrFrameWaiter, OxrFrameWaiter,
OxrFrameStream, OxrFrameStream,
@@ -456,7 +461,7 @@ fn init_xr_session(
} else { } else {
available_blend_modes.first().copied() available_blend_modes.first().copied()
} }
.ok_or(OxrError::NoAvailableBackend)?; .ok_or(OxrError::NoAvailableBlendMode)?;
let graphics_info = OxrGraphicsInfo { let graphics_info = OxrGraphicsInfo {
blend_mode, blend_mode,

View File

@@ -9,7 +9,7 @@ use crate::resources::*;
use crate::spaces::OxrSpaceExt as _; 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<'a> + 'a>>;
} }
pub struct ProjectionLayer; pub struct ProjectionLayer;
@@ -63,7 +63,7 @@ impl LayerProvider for ProjectionLayer {
} }
impl LayerProvider for PassthroughLayer { impl LayerProvider for PassthroughLayer {
fn get<'a>(&'a self, world: &'a World) -> Option<Box<dyn CompositionLayer + '_>> { fn get(&self, world: &World) -> Option<Box<dyn CompositionLayer>> {
Some(Box::new( Some(Box::new(
CompositionLayerPassthrough::new() CompositionLayerPassthrough::new()
.layer_handle(world.get_resource::<OxrPassthroughLayer>()?) .layer_handle(world.get_resource::<OxrPassthroughLayer>()?)
@@ -117,7 +117,7 @@ impl<'a> SwapchainSubImage<'a> {
} }
} }
impl<'a> Default for SwapchainSubImage<'a> { impl Default for SwapchainSubImage<'_> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
@@ -165,11 +165,15 @@ impl<'a> CompositionLayerProjectionView<'a> {
self self
} }
} }
impl<'a> Default for CompositionLayerProjectionView<'a> { impl Default for CompositionLayerProjectionView<'_> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
/// # Safety
/// the header function must return a ref to a valid Composition Layer struct.
/// it has to use `repr(C)` and it has to follow the shape of a Composition Layer struct from the
/// OpenXR specification
pub unsafe trait CompositionLayer<'a> { pub unsafe trait CompositionLayer<'a> {
fn swapchain(&self) -> Option<&'a OxrSwapchain>; fn swapchain(&self) -> Option<&'a OxrSwapchain>;
fn header(&self) -> &sys::CompositionLayerBaseHeader; fn header(&self) -> &sys::CompositionLayerBaseHeader;
@@ -227,7 +231,7 @@ unsafe impl<'a> CompositionLayer<'a> for CompositionLayerProjection<'a> {
unsafe { mem::transmute(&self.inner) } unsafe { mem::transmute(&self.inner) }
} }
} }
impl<'a> Default for CompositionLayerProjection<'a> { impl Default for CompositionLayerProjection<'_> {
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }

View File

@@ -1,3 +1,4 @@
use super::{openxr_session_available, resources::OxrInstance};
use bevy::{ecs::system::SystemId, prelude::*}; use bevy::{ecs::system::SystemId, prelude::*};
use bevy_mod_xr::session::{XrFirst, XrHandleEvents}; use bevy_mod_xr::session::{XrFirst, XrHandleEvents};
use openxr::{Event, EventDataBuffer}; use openxr::{Event, EventDataBuffer};
@@ -30,7 +31,7 @@ pub fn poll_events(world: &mut World) {
.iter() .iter()
.map(|v| SystemId::<OxrEventIn, ()>::from_entity(*v)) .map(|v| SystemId::<OxrEventIn, ()>::from_entity(*v))
{ {
if let Err(err) = world.run_system_with_input(handler, event) { if let Err(err) = world.run_system_with(handler, event) {
error!("error when running oxr event handler: {err}"); error!("error when running oxr event handler: {err}");
}; };
} }
@@ -38,7 +39,6 @@ pub fn poll_events(world: &mut World) {
world.insert_resource(handlers); world.insert_resource(handlers);
} }
use super::{openxr_session_available, resources::OxrInstance};
#[derive(Resource, Debug, Default)] #[derive(Resource, Debug, Default)]
pub struct OxrEventHandlers(Vec<Entity>); pub struct OxrEventHandlers(Vec<Entity>);
pub trait OxrEventHandlerExt { pub trait OxrEventHandlerExt {

View File

@@ -20,18 +20,10 @@ impl Default for OxrReferenceSpacePlugin {
} }
} }
/// Resource specifying what the type should be for [`OxrPrimaryReferenceSpace`]. Set through [`OxrReferenceSpacePlugin`]. /// Resource specifying what the type should used be for the [`XrPrimaryReferenceSpace`]. Set through [`OxrReferenceSpacePlugin`].
#[derive(Resource)] #[derive(Resource)]
struct OxrDefaultPrimaryReferenceSpaceType(openxr::ReferenceSpaceType); struct OxrDefaultPrimaryReferenceSpaceType(openxr::ReferenceSpaceType);
/// The Default Reference space used for locating things
// #[derive(Resource, Deref, ExtrctResource, Clone)]
// pub struct OxrPrimaryReferenceSpace(pub Arc<openxr::Space>);
/// The Reference space used for locating spaces on this entity
#[derive(Component)]
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.add_plugins(ExtractResourcePlugin::<XrPrimaryReferenceSpace>::default()) app.add_plugins(ExtractResourcePlugin::<XrPrimaryReferenceSpace>::default())

View File

@@ -4,7 +4,7 @@ use bevy::{
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget}, camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
extract_resource::ExtractResourcePlugin, extract_resource::ExtractResourcePlugin,
pipelined_rendering::PipelinedRenderingPlugin, pipelined_rendering::PipelinedRenderingPlugin,
view::ExtractedView, view::{ExtractedView, NoFrustumCulling},
Render, RenderApp, Render, RenderApp,
}, },
transform::TransformSystem, transform::TransformSystem,
@@ -146,7 +146,7 @@ pub fn clean_views(
) { ) {
for (e, cam) in &cam_query { for (e, cam) in &cam_query {
manual_texture_views.remove(&ManualTextureViewHandle(XR_TEXTURE_INDEX + cam.0)); manual_texture_views.remove(&ManualTextureViewHandle(XR_TEXTURE_INDEX + cam.0));
commands.entity(e).despawn_recursive(); commands.entity(e).despawn();
} }
} }
@@ -170,6 +170,8 @@ pub fn init_views<const SPAWN_CAMERAS: bool>(
..Default::default() ..Default::default()
}, },
XrCamera(index), XrCamera(index),
Projection::custom(XrProjection::default()),
NoFrustumCulling,
)); ));
} }
} }
@@ -244,13 +246,17 @@ pub fn locate_views(
} }
pub fn update_views( pub fn update_views(
mut query: Query<(&mut Transform, &mut XrProjection, &XrCamera)>, mut query: Query<(&mut Transform, &mut Projection, &XrCamera)>,
views: ResMut<OxrViews>, views: ResMut<OxrViews>,
) { ) {
for (mut transform, mut projection, camera) in query.iter_mut() { for (mut transform, mut projection, camera) in query.iter_mut() {
let Some(view) = views.get(camera.0 as usize) else { let Some(view) = views.get(camera.0 as usize) else {
continue; continue;
}; };
let projection = match projection.as_mut() {
Projection::Custom(custom) => custom.get_mut::<XrProjection>().unwrap(),
_ => unreachable!(),
};
let projection_matrix = calculate_projection( let projection_matrix = calculate_projection(
projection.near, projection.near,

View File

@@ -5,6 +5,7 @@ use crate::error::OxrError;
use crate::graphics::*; use crate::graphics::*;
use crate::layer_builder::{CompositionLayer, LayerProvider}; use crate::layer_builder::{CompositionLayer, LayerProvider};
use crate::session::{OxrSession, OxrSessionCreateNextChain}; use crate::session::{OxrSession, OxrSessionCreateNextChain};
use crate::types::Result as OxrResult;
use crate::types::*; use crate::types::*;
/// Wrapper around an [`Entry`](openxr::Entry) with some methods overridden to use bevy types. /// Wrapper around an [`Entry`](openxr::Entry) with some methods overridden to use bevy types.
@@ -15,7 +16,7 @@ pub struct OxrEntry(pub openxr::Entry);
impl OxrEntry { impl OxrEntry {
/// Enumerate available extensions for this OpenXR runtime. /// Enumerate available extensions for this OpenXR runtime.
pub fn enumerate_extensions(&self) -> Result<OxrExtensions> { pub fn enumerate_extensions(&self) -> OxrResult<OxrExtensions> {
Ok(self.0.enumerate_extensions().map(Into::into)?) Ok(self.0.enumerate_extensions().map(Into::into)?)
} }
@@ -28,7 +29,7 @@ impl OxrEntry {
exts: OxrExtensions, exts: OxrExtensions,
layers: &[&str], layers: &[&str],
backend: GraphicsBackend, backend: GraphicsBackend,
) -> Result<OxrInstance> { ) -> OxrResult<OxrInstance> {
let available_exts = self.enumerate_extensions()?; let available_exts = self.enumerate_extensions()?;
if !backend.is_available(&available_exts) { if !backend.is_available(&available_exts) {
@@ -53,7 +54,7 @@ impl OxrEntry {
} }
/// Returns a list of all of the backends the OpenXR runtime supports. /// Returns a list of all of the backends the OpenXR runtime supports.
pub fn available_backends(&self) -> Result<Vec<GraphicsBackend>> { pub fn available_backends(&self) -> OxrResult<Vec<GraphicsBackend>> {
Ok(GraphicsBackend::available_backends( Ok(GraphicsBackend::available_backends(
&self.enumerate_extensions()?, &self.enumerate_extensions()?,
)) ))
@@ -105,7 +106,7 @@ impl OxrInstance {
pub fn init_graphics( pub fn init_graphics(
&self, &self,
system_id: openxr::SystemId, system_id: openxr::SystemId,
) -> Result<(WgpuGraphics, SessionCreateInfo)> { ) -> OxrResult<(WgpuGraphics, SessionCreateInfo)> {
graphics_match!( graphics_match!(
self.1; self.1;
_ => { _ => {
@@ -128,9 +129,9 @@ impl OxrInstance {
system_id: openxr::SystemId, system_id: openxr::SystemId,
info: SessionCreateInfo, info: SessionCreateInfo,
chain: &mut OxrSessionCreateNextChain, chain: &mut OxrSessionCreateNextChain,
) -> Result<(OxrSession, OxrFrameWaiter, OxrFrameStream)> { ) -> OxrResult<(OxrSession, OxrFrameWaiter, OxrFrameStream)> {
if !info.0.using_graphics_of_val(&self.1) { if !info.0.using_graphics_of_val(&self.1) {
return Err(OxrError::GraphicsBackendMismatch { return OxrResult::Err(OxrError::GraphicsBackendMismatch {
item: std::any::type_name::<SessionCreateInfo>(), item: std::any::type_name::<SessionCreateInfo>(),
backend: info.0.graphics_name(), backend: info.0.graphics_name(),
expected_backend: self.1.graphics_name(), expected_backend: self.1.graphics_name(),
@@ -180,7 +181,7 @@ impl OxrFrameStream {
display_time: openxr::Time, display_time: openxr::Time,
environment_blend_mode: openxr::EnvironmentBlendMode, environment_blend_mode: openxr::EnvironmentBlendMode,
layers: &[&dyn CompositionLayer], layers: &[&dyn CompositionLayer],
) -> Result<()> { ) -> OxrResult<()> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
stream => { stream => {
@@ -233,7 +234,7 @@ impl OxrSwapchain {
/// Determine the index of the next image to render to in the swapchain image array. /// Determine the index of the next image to render to in the swapchain image array.
/// ///
/// Calls [`acquire_image`](openxr::Swapchain::acquire_image) internally. /// Calls [`acquire_image`](openxr::Swapchain::acquire_image) internally.
pub fn acquire_image(&mut self) -> Result<u32> { pub fn acquire_image(&mut self) -> OxrResult<u32> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
swap => Ok(swap.acquire_image()?) swap => Ok(swap.acquire_image()?)
@@ -243,7 +244,7 @@ impl OxrSwapchain {
/// Wait for the compositor to finish reading from the oldest unwaited acquired image. /// Wait for the compositor to finish reading from the oldest unwaited acquired image.
/// ///
/// Calls [`wait_image`](openxr::Swapchain::wait_image) internally. /// Calls [`wait_image`](openxr::Swapchain::wait_image) internally.
pub fn wait_image(&mut self, timeout: openxr::Duration) -> Result<()> { pub fn wait_image(&mut self, timeout: openxr::Duration) -> OxrResult<()> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
swap => Ok(swap.wait_image(timeout)?) swap => Ok(swap.wait_image(timeout)?)
@@ -253,7 +254,7 @@ impl OxrSwapchain {
/// Release the oldest acquired image. /// Release the oldest acquired image.
/// ///
/// Calls [`release_image`](openxr::Swapchain::release_image) internally. /// Calls [`release_image`](openxr::Swapchain::release_image) internally.
pub fn release_image(&mut self) -> Result<()> { pub fn release_image(&mut self) -> OxrResult<()> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
swap => Ok(swap.release_image()?) swap => Ok(swap.release_image()?)
@@ -268,7 +269,7 @@ impl OxrSwapchain {
device: &wgpu::Device, device: &wgpu::Device,
format: wgpu::TextureFormat, format: wgpu::TextureFormat,
resolution: UVec2, resolution: UVec2,
) -> Result<OxrSwapchainImages> { ) -> OxrResult<OxrSwapchainImages> {
graphics_match!( graphics_match!(
&self.0; &self.0;
swap => { swap => {
@@ -288,10 +289,6 @@ impl OxrSwapchain {
#[derive(Debug, Deref, Resource, Clone, Copy, ExtractResource)] #[derive(Debug, Deref, Resource, Clone, Copy, ExtractResource)]
pub struct OxrSwapchainImages(pub &'static [wgpu::Texture]); pub struct OxrSwapchainImages(pub &'static [wgpu::Texture]);
/// Thread safe wrapper around [openxr::Space] representing the stage.
// #[derive(Deref, Clone, Resource)]
// pub struct OxrStage(pub Arc<openxr::Space>);
/// Stores the latest generated [OxrViews] /// Stores the latest generated [OxrViews]
#[derive(Clone, Resource, ExtractResource, Deref, DerefMut, Default)] #[derive(Clone, Resource, ExtractResource, Deref, DerefMut, Default)]
pub struct OxrViews(pub Vec<openxr::View>); pub struct OxrViews(pub Vec<openxr::View>);

View File

@@ -1,6 +1,6 @@
use std::{mem::MaybeUninit, ptr, sync::Mutex}; use std::{mem::MaybeUninit, ptr, sync::Mutex};
use bevy::{prelude::*, utils::hashbrown::HashSet}; use bevy::{platform::collections::hash_set::HashSet, prelude::*};
use bevy_mod_xr::{ use bevy_mod_xr::{
session::{XrFirst, XrHandleEvents}, session::{XrFirst, XrHandleEvents},
spaces::{ spaces::{

View File

@@ -10,7 +10,7 @@ keywords = ["gamedev", "bevy", "Xr", "Vr"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bevy.workspace = true bevy = { workspace = true, features = ["bevy_log"] }
[lints.clippy] [lints.clippy]
too_many_arguments = "allow" too_many_arguments = "allow"

View File

@@ -1,8 +1,8 @@
use std::{any::TypeId, marker::PhantomData}; use std::{any::TypeId, marker::PhantomData};
use bevy::app::{App, Plugin}; use bevy::app::{App, Plugin};
use bevy::ecs::system::Resource;
use bevy::math::Vec2; use bevy::math::Vec2;
use bevy::prelude::Resource;
pub struct ActionPlugin<A: Action>(PhantomData<A>); pub struct ActionPlugin<A: Action>(PhantomData<A>);

View File

@@ -1,19 +1,14 @@
use core::panic; use core::panic;
use bevy::app::{App, Plugin, PostUpdate}; use bevy::app::{App, Plugin};
use bevy::core_pipeline::core_3d::Camera3d; use bevy::core_pipeline::core_3d::Camera3d;
use bevy::ecs::component::{Component, StorageType}; use bevy::ecs::component::Component;
use bevy::ecs::reflect::ReflectComponent;
use bevy::ecs::schedule::IntoSystemConfigs;
use bevy::math::{Mat4, Vec3A, Vec4}; use bevy::math::{Mat4, Vec3A, Vec4};
use bevy::pbr::{PbrPlugin, PbrProjectionPlugin}; use bevy::prelude::SystemSet;
use bevy::prelude::{Projection, SystemSet};
use bevy::reflect::std_traits::ReflectDefault; use bevy::reflect::std_traits::ReflectDefault;
use bevy::reflect::Reflect; use bevy::reflect::Reflect;
use bevy::render::camera::{CameraProjection, CameraProjectionPlugin}; use bevy::render::camera::CameraProjection;
use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin}; use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin};
use bevy::render::view::{update_frusta, VisibilitySystems};
use bevy::transform::TransformSystem;
use crate::session::XrTracker; use crate::session::XrTracker;
@@ -21,41 +16,19 @@ pub struct XrCameraPlugin;
impl Plugin for XrCameraPlugin { impl Plugin for XrCameraPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_plugins(CameraProjectionPlugin::<XrProjection>::default()); app.add_plugins(ExtractComponentPlugin::<XrCamera>::default());
app.add_systems(
PostUpdate,
update_frusta::<XrProjection>
.after(TransformSystem::TransformPropagate)
.before(VisibilitySystems::UpdateFrusta),
);
if app.is_plugin_added::<PbrPlugin>() {
app.add_plugins(PbrProjectionPlugin::<XrProjection>::default());
}
app.add_plugins((
ExtractComponentPlugin::<XrProjection>::default(),
ExtractComponentPlugin::<XrCamera>::default(),
));
} }
} }
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, SystemSet)] #[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, SystemSet)]
pub struct XrViewInit; pub struct XrViewInit;
#[derive(Debug, Clone, Reflect, ExtractComponent)] #[derive(Debug, Clone, Reflect)]
#[reflect(Component, Default)] #[reflect(Default)]
pub struct XrProjection { pub struct XrProjection {
pub projection_matrix: Mat4, pub projection_matrix: Mat4,
pub near: f32, pub near: f32,
} }
impl Component for XrProjection {
const STORAGE_TYPE: StorageType = StorageType::Table;
fn register_component_hooks(hooks: &mut bevy::ecs::component::ComponentHooks) {
hooks.on_add(|mut world, entity, _| {
world.commands().entity(entity).remove::<Projection>();
});
}
}
impl Default for XrProjection { impl Default for XrProjection {
fn default() -> Self { fn default() -> Self {
@@ -68,7 +41,7 @@ impl Default for XrProjection {
/// Marker component for an XR view. It is the backends responsibility to update this. /// Marker component for an XR view. It is the backends responsibility to update this.
#[derive(Clone, Copy, Component, ExtractComponent, Debug, Default)] #[derive(Clone, Copy, Component, ExtractComponent, Debug, Default)]
#[require(Camera3d, XrProjection, XrTracker)] #[require(Camera3d, XrTracker)]
pub struct XrCamera(pub u32); pub struct XrCamera(pub u32);
impl CameraProjection for XrProjection { impl CameraProjection for XrProjection {
@@ -132,7 +105,6 @@ pub fn calculate_projection(near_z: f32, fov: Fov) -> Mat4 {
// let y_fov = (self.fov.angle_up.abs() + self.fov.angle_down.abs()); // let y_fov = (self.fov.angle_up.abs() + self.fov.angle_down.abs());
// return Mat4::perspective_infinite_reverse_rh(y_fov, x_fov / y_fov, self.near); // return Mat4::perspective_infinite_reverse_rh(y_fov, x_fov / y_fov, self.near);
let is_vulkan_api = false; // FIXME wgpu probably abstracts this
let far_z = -1.; // use infinite proj let far_z = -1.; // use infinite proj
// let far_z = self.far; // let far_z = self.far;
@@ -149,11 +121,7 @@ pub fn calculate_projection(near_z: f32, fov: Fov) -> Mat4 {
// positive Y up (OpenGL / D3D / Metal). // positive Y up (OpenGL / D3D / Metal).
// const float tanAngleHeight = // const float tanAngleHeight =
// graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown); // graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown);
let tan_angle_height = if is_vulkan_api { let tan_angle_height = tan_angle_up - tan_angle_down;
tan_angle_down - tan_angle_up
} else {
tan_angle_up - tan_angle_down
};
// Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES). // Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES).
// Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal). // Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal).

View File

@@ -1,10 +1,9 @@
use bevy::{ use bevy::{
ecs::{component::Component, entity::Entity, world::Command}, ecs::{component::Component, entity::Entity},
log::warn, log::warn,
math::bool, math::bool,
prelude::{Bundle, Commands, Deref, DerefMut, Resource, Transform, Visibility, World}, prelude::{Bundle, Command, Commands, Deref, DerefMut, Resource, Transform, Visibility, World},
}; };
use crate::{session::XrTracker, spaces::XrSpaceLocationFlags}; use crate::{session::XrTracker, spaces::XrSpaceLocationFlags};
pub const HAND_JOINT_COUNT: usize = 26; pub const HAND_JOINT_COUNT: usize = 26;
@@ -182,7 +181,7 @@ pub struct SpawnHandTracker<B: Bundle> {
} }
impl<B: Bundle> Command for SpawnHandTracker<B> { impl<B: Bundle> Command for SpawnHandTracker<B> {
fn apply(self, world: &mut bevy::prelude::World) { fn apply(self, world: &mut World) {
let Some(executor) = world.remove_resource::<SpawnHandTrackerCommandExecutor>() else { let Some(executor) = world.remove_resource::<SpawnHandTrackerCommandExecutor>() else {
warn!("no SpawnHandTracker executor defined, skipping handtracker creation"); warn!("no SpawnHandTracker executor defined, skipping handtracker creation");
return; return;

View File

@@ -3,8 +3,9 @@ use std::sync::atomic::AtomicBool;
use std::sync::Arc; use std::sync::Arc;
use bevy::app::{AppExit, MainScheduleOrder}; use bevy::app::{AppExit, MainScheduleOrder};
use bevy::ecs::component::StorageType; use bevy::ecs::component::HookContext;
use bevy::ecs::schedule::ScheduleLabel; use bevy::ecs::schedule::ScheduleLabel;
use bevy::ecs::world::DeferredWorld;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin}; use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin};
use bevy::render::{Render, RenderApp, RenderSet}; use bevy::render::{Render, RenderApp, RenderSet};
@@ -96,26 +97,21 @@ pub struct XrTrackingRoot;
struct TrackingRootRes(Entity); struct TrackingRootRes(Entity);
/// Makes the entity a child of the XrTrackingRoot if the entity has no parent /// Makes the entity a child of the XrTrackingRoot if the entity has no parent
#[derive(Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, Default)] #[derive(Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, Default, Component)]
#[component(on_add = on_tracker_add)]
pub struct XrTracker; pub struct XrTracker;
impl Component for XrTracker { fn on_tracker_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
const STORAGE_TYPE: StorageType = StorageType::SparseSet; if world
.entity(entity)
fn register_component_hooks(hooks: &mut bevy::ecs::component::ComponentHooks) { .get_components::<Has<Children>>()
hooks.on_add(|mut world, entity, _| { .is_some_and(identity)
if world {
.entity(entity) return;
.get_components::<Has<Parent>>()
.is_some_and(identity)
{
return;
}
let Some(root) = world.get_resource::<TrackingRootRes>().map(|r| r.0) else {
return;
};
world.commands().entity(root).add_child(entity);
});
} }
let Some(root) = world.get_resource::<TrackingRootRes>().map(|r| r.0) else {
return;
};
world.commands().entity(root).add_child(entity);
} }
pub struct XrSessionPlugin { pub struct XrSessionPlugin {
@@ -220,7 +216,7 @@ impl Plugin for XrSessionPlugin {
} }
fn exits_session_on_app_exit(mut request_exit: EventWriter<XrRequestExitEvent>) { fn exits_session_on_app_exit(mut request_exit: EventWriter<XrRequestExitEvent>) {
request_exit.send_default(); request_exit.write_default();
} }
/// Event sent by backends whenever [`XrState`] is changed. /// Event sent by backends whenever [`XrState`] is changed.
@@ -262,18 +258,18 @@ pub fn auto_handle_session(
match state { match state {
XrState::Available => { XrState::Available => {
if !*no_auto_restart { if !*no_auto_restart {
create_session.send_default(); create_session.write_default();
} }
} }
XrState::Ready => { XrState::Ready => {
begin_session.send_default(); begin_session.write_default();
} }
XrState::Stopping => { XrState::Stopping => {
end_session.send_default(); end_session.write_default();
} }
XrState::Exiting { should_restart } => { XrState::Exiting { should_restart } => {
*no_auto_restart = !should_restart; *no_auto_restart = !should_restart;
destroy_session.send_default(); destroy_session.write_default();
} }
_ => (), _ => (),
} }
@@ -284,7 +280,7 @@ pub fn update_root_transform(
mut root_transform: ResMut<XrRootTransform>, mut root_transform: ResMut<XrRootTransform>,
root: Query<&GlobalTransform, With<XrTrackingRoot>>, root: Query<&GlobalTransform, With<XrTrackingRoot>>,
) { ) {
let Ok(transform) = root.get_single() else { let Ok(transform) = root.single() else {
return; return;
}; };

View File

@@ -83,7 +83,7 @@ fn update_stage(
root_query: Query<&Transform, (With<XrTrackingRoot>, Without<XrTrackedStage>)>, root_query: Query<&Transform, (With<XrTrackingRoot>, Without<XrTrackedStage>)>,
mut stage_query: Query<&mut Transform, (With<XrTrackedStage>, Without<XrTrackingRoot>)>, mut stage_query: Query<&mut Transform, (With<XrTrackedStage>, Without<XrTrackingRoot>)>,
) { ) {
if let Ok(root) = root_query.get_single() { if let Ok(root) = root_query.single() {
for mut transform in &mut stage_query { for mut transform in &mut stage_query {
*transform = *root; *transform = *root;
} }
@@ -129,7 +129,7 @@ fn update_view(
mut head_query: Query<&mut Transform, (With<HeadXRSpace>, Without<XrTrackedView>)>, mut head_query: Query<&mut Transform, (With<HeadXRSpace>, Without<XrTrackedView>)>,
mut view_query: Query<&mut Transform, (With<XrTrackedView>, Without<HeadXRSpace>)>, mut view_query: Query<&mut Transform, (With<XrTrackedView>, Without<HeadXRSpace>)>,
) { ) {
let head_transform = head_query.get_single_mut(); let head_transform = head_query.single_mut();
if let Ok(root) = head_transform { if let Ok(root) = head_transform {
for mut transform in &mut view_query { for mut transform in &mut view_query {
*transform = *root; *transform = *root;
@@ -142,7 +142,7 @@ fn update_local_floor_transforms(
mut head_space: Query<&mut Transform, (With<HeadXRSpace>, Without<XrTrackedLocalFloor>)>, mut head_space: Query<&mut Transform, (With<HeadXRSpace>, Without<XrTrackedLocalFloor>)>,
mut local_floor: Query<&mut Transform, (With<XrTrackedLocalFloor>, Without<HeadXRSpace>)>, mut local_floor: Query<&mut Transform, (With<XrTrackedLocalFloor>, Without<HeadXRSpace>)>,
) { ) {
let head_transform = head_space.get_single_mut(); let head_transform = head_space.single_mut();
if let Ok(head) = head_transform { if let Ok(head) = head_transform {
let mut calc_floor = *head; let mut calc_floor = *head;
calc_floor.translation.y = 0.0; calc_floor.translation.y = 0.0;
@@ -164,7 +164,7 @@ fn update_left_grip(
mut left_grip: Query<&mut Transform, (With<LeftGrip>, Without<XrTrackedLeftGrip>)>, mut left_grip: Query<&mut Transform, (With<LeftGrip>, Without<XrTrackedLeftGrip>)>,
mut tracked_left_grip: Query<&mut Transform, (With<XrTrackedLeftGrip>, Without<LeftGrip>)>, mut tracked_left_grip: Query<&mut Transform, (With<XrTrackedLeftGrip>, Without<LeftGrip>)>,
) { ) {
let head_transform = left_grip.get_single_mut(); let head_transform = left_grip.single_mut();
if let Ok(head) = head_transform { if let Ok(head) = head_transform {
for mut transform in &mut tracked_left_grip { for mut transform in &mut tracked_left_grip {
*transform = *head; *transform = *head;
@@ -180,7 +180,7 @@ fn update_right_grip(
mut right_grip: Query<&mut Transform, (With<RightGrip>, Without<XrTrackedRightGrip>)>, mut right_grip: Query<&mut Transform, (With<RightGrip>, Without<XrTrackedRightGrip>)>,
mut tracked_right_grip: Query<&mut Transform, (With<XrTrackedRightGrip>, Without<RightGrip>)>, mut tracked_right_grip: Query<&mut Transform, (With<XrTrackedRightGrip>, Without<RightGrip>)>,
) { ) {
let head_transform = right_grip.get_single_mut(); let head_transform = right_grip.single_mut();
if let Ok(head) = head_transform { if let Ok(head) = head_transform {
for mut transform in &mut tracked_right_grip { for mut transform in &mut tracked_right_grip {
*transform = *head; *transform = *head;
@@ -229,12 +229,12 @@ pub fn suggest_action_bindings(
actions: Res<ControllerActions>, actions: Res<ControllerActions>,
mut bindings: EventWriter<OxrSuggestActionBinding>, mut bindings: EventWriter<OxrSuggestActionBinding>,
) { ) {
bindings.send(OxrSuggestActionBinding { bindings.write(OxrSuggestActionBinding {
action: actions.left.as_raw(), action: actions.left.as_raw(),
interaction_profile: "/interaction_profiles/oculus/touch_controller".into(), interaction_profile: "/interaction_profiles/oculus/touch_controller".into(),
bindings: vec!["/user/hand/left/input/grip/pose".into()], bindings: vec!["/user/hand/left/input/grip/pose".into()],
}); });
bindings.send(OxrSuggestActionBinding { bindings.write(OxrSuggestActionBinding {
action: actions.right.as_raw(), action: actions.right.as_raw(),
interaction_profile: "/interaction_profiles/oculus/touch_controller".into(), interaction_profile: "/interaction_profiles/oculus/touch_controller".into(),
bindings: vec!["/user/hand/right/input/grip/pose".into()], bindings: vec!["/user/hand/right/input/grip/pose".into()],
@@ -242,11 +242,11 @@ pub fn suggest_action_bindings(
} }
fn sync_actions(actions: Res<ControllerActions>, mut sync: EventWriter<OxrSyncActionSet>) { fn sync_actions(actions: Res<ControllerActions>, mut sync: EventWriter<OxrSyncActionSet>) {
sync.send(OxrSyncActionSet(actions.set.clone())); sync.write(OxrSyncActionSet(actions.set.clone()));
} }
fn attach_set(actions: Res<ControllerActions>, mut attach: EventWriter<OxrAttachActionSet>) { fn attach_set(actions: Res<ControllerActions>, mut attach: EventWriter<OxrAttachActionSet>) {
attach.send(OxrAttachActionSet(actions.set.clone())); attach.write(OxrAttachActionSet(actions.set.clone()));
} }
fn create_actions(instance: Res<OxrInstance>, mut cmds: Commands) { fn create_actions(instance: Res<OxrInstance>, mut cmds: Commands) {

View File

@@ -28,7 +28,7 @@ pub fn handle_transform_events(
mut position_reader: EventReader<SnapToPosition>, mut position_reader: EventReader<SnapToPosition>,
mut rotation_reader: EventReader<SnapToRotation>, mut rotation_reader: EventReader<SnapToRotation>,
) { ) {
let result = root_query.get_single_mut(); let result = root_query.single_mut();
match result { match result {
Ok(mut root_transform) => { Ok(mut root_transform) => {
let view = views.first(); let view = views.first();
@@ -45,7 +45,7 @@ pub fn handle_transform_events(
} }
//rotation //rotation
let root_local = root_transform.translation.clone(); let root_local = root_transform.translation;
let hmd_global = let hmd_global =
root_transform.rotation.mul_vec3(view_translation) + root_local; root_transform.rotation.mul_vec3(view_translation) + root_local;
let view_rot = view.pose.orientation.to_quat(); let view_rot = view.pose.orientation.to_quat();

View File

@@ -131,7 +131,7 @@ fn create_openxr_events(
commands.entity(id).insert(oxr_action_set); commands.entity(id).insert(oxr_action_set);
//since the actions are made from the sets lets go //since the actions are made from the sets lets go
for &child in children.iter() { for child in children.iter() {
//first get the action entity and stuff //first get the action entity and stuff
let (create_action, bindings) = actions_query.get(child).unwrap(); let (create_action, bindings) = actions_query.get(child).unwrap();
//lets create dat action //lets create dat action
@@ -158,7 +158,7 @@ fn create_openxr_events(
}), }),
)); ));
//since we need actions for bindings lets go!! //since we need actions for bindings lets go!!
for &bind in bindings.iter() { for bind in bindings.iter() {
//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();
@@ -171,7 +171,7 @@ fn create_openxr_events(
bindings: binding, bindings: binding,
}; };
//finally send the suggestion //finally send the suggestion
binding_writer.send(sugestion); binding_writer.write(sugestion);
} }
} }
bevy_mod_xr::actions::ActionType::Float => { bevy_mod_xr::actions::ActionType::Float => {
@@ -197,7 +197,7 @@ fn create_openxr_events(
}), }),
)); ));
//since we need actions for bindings lets go!! //since we need actions for bindings lets go!!
for &bind in bindings.iter() { for bind in bindings.iter() {
//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();
@@ -210,7 +210,7 @@ fn create_openxr_events(
bindings: binding, bindings: binding,
}; };
//finally send the suggestion //finally send the suggestion
binding_writer.send(sugestion); binding_writer.write(sugestion);
} }
} }
bevy_mod_xr::actions::ActionType::Vector => { bevy_mod_xr::actions::ActionType::Vector => {
@@ -236,7 +236,7 @@ fn create_openxr_events(
}), }),
)); ));
//since we need actions for bindings lets go!! //since we need actions for bindings lets go!!
for &bind in bindings.iter() { for bind in bindings.iter() {
//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();
@@ -249,13 +249,13 @@ fn create_openxr_events(
bindings: binding, bindings: binding,
}; };
//finally send the suggestion //finally send the suggestion
binding_writer.send(sugestion); binding_writer.write(sugestion);
} }
} }
}; };
} }
attach_writer.send(OxrAttachActionSet(action_set)); attach_writer.write(OxrAttachActionSet(action_set));
} }
} }
@@ -264,7 +264,7 @@ fn sync_active_action_sets(
active_action_set_query: Query<&XRUtilsActionSetReference, With<ActiveSet>>, active_action_set_query: Query<&XRUtilsActionSetReference, With<ActiveSet>>,
) { ) {
for set in &active_action_set_query { for set in &active_action_set_query {
sync_set.send(OxrSyncActionSet(set.0.clone())); sync_set.write(OxrSyncActionSet(set.0.clone()));
} }
} }