0.16 support

This commit is contained in:
Malek
2025-03-06 17:59:51 -05:00
committed by Schmarni
parent 9f6f5c0711
commit 4528529417
18 changed files with 1548 additions and 987 deletions

2377
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 = { git = "https://github.com/bevyengine/bevy", 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

@@ -26,6 +26,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

@@ -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_support::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;
@@ -29,7 +29,7 @@ pub(crate) fn run_action_binding_sugestion(world: &mut World) {
} }
fn bind_actions(instance: Res<OxrInstance>, mut actions: EventReader<OxrSuggestActionBinding>) { fn bind_actions(instance: Res<OxrInstance>, mut actions: EventReader<OxrSuggestActionBinding>) {
let mut bindings: HashMap<&str, Vec<ActionSuggestedBinding>> = HashMap::new(); let mut bindings: HashMap<&str, Vec<ActionSuggestedBinding>, _> = HashMap::new();
for e in actions.read() { for e in actions.read() {
bindings.entry(&e.interaction_profile).or_default().extend( bindings.entry(&e.interaction_profile).or_default().extend(
e.bindings e.bindings

View File

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

View File

@@ -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)> { ) -> crate::types::Result<(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,7 @@ pub fn create_passthrough(
} }
#[inline] #[inline]
pub fn supports_passthrough(instance: &OxrInstance, system: OxrSystemId) -> Result<bool> { pub fn supports_passthrough(instance: &OxrInstance, system: OxrSystemId) -> crate::types::Result<bool> {
if instance.exts().fb_passthrough.is_none() { if instance.exts().fb_passthrough.is_none() {
return Ok(false); return Ok(false);
} }

View File

@@ -3,6 +3,7 @@ use std::ffi::{c_void, CString};
use ash::vk::Handle; use ash::vk::Handle;
use bevy::log::{debug, error}; use bevy::log::{debug, error};
use bevy::math::UVec2; use bevy::math::UVec2;
use bevy::render::render_resource::TextureFormat;
use openxr::{sys, Version}; use openxr::{sys, Version};
use wgpu_hal::api::Vulkan; use wgpu_hal::api::Vulkan;
use wgpu_hal::Api; use wgpu_hal::Api;
@@ -115,7 +116,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,
@@ -756,5 +756,8 @@ fn wgpu_to_vulkan(format: wgpu::TextureFormat) -> Option<ash::vk::Format> {
AstcBlock::B12x12 => F::ASTC_12X12_SFLOAT_BLOCK_EXT, AstcBlock::B12x12 => F::ASTC_12X12_SFLOAT_BLOCK_EXT,
}, },
}, },
TextureFormat::R64Uint => {
panic!()
}
}) })
} }

View File

@@ -104,6 +104,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: Default::default(),
}, },
ExtractResourcePlugin::<OxrSessionStarted>::default(), ExtractResourcePlugin::<OxrSessionStarted>::default(),
)) ))
@@ -206,7 +207,7 @@ fn detect_session_destroyed(
impl OxrInitPlugin { impl OxrInitPlugin {
fn init_xr( fn init_xr(
&self, &self,
) -> Result<( ) -> crate::types::Result<(
OxrInstance, OxrInstance,
OxrSystemId, OxrSystemId,
WgpuGraphics, WgpuGraphics,
@@ -350,7 +351,7 @@ fn init_xr_session(
resolutions, resolutions,
graphics_info, graphics_info,
}: SessionConfigInfo, }: SessionConfigInfo,
) -> Result<( ) -> crate::types::Result<(
OxrSession, OxrSession,
OxrFrameWaiter, OxrFrameWaiter,
OxrFrameStream, OxrFrameStream,

View File

@@ -6,6 +6,7 @@ use bevy::{
utils::default, utils::default,
window::{PresentMode, Window, WindowPlugin}, window::{PresentMode, Window, WindowPlugin},
}; };
use bevy::render::camera::CameraPlugin;
use bevy_mod_xr::session::XrSessionPlugin; use bevy_mod_xr::session::XrSessionPlugin;
use bevy_mod_xr::{camera::XrCameraPlugin, session::XrState}; use bevy_mod_xr::{camera::XrCameraPlugin, session::XrState};
use init::OxrInitPlugin; use init::OxrInitPlugin;

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

@@ -1,10 +1,11 @@
use bevy::render::camera::CustomProjection;
use bevy::{ use bevy::{
prelude::*, prelude::*,
render::{ render::{
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,
@@ -170,6 +171,8 @@ pub fn init_views<const SPAWN_CAMERAS: bool>(
..Default::default() ..Default::default()
}, },
XrCamera(index), XrCamera(index),
Projection::custom(XrProjection::default()),
NoFrustumCulling,
)); ));
} }
} }
@@ -244,13 +247,18 @@ 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() {
println!("we have this query");
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,
@@ -263,6 +271,11 @@ pub fn update_views(
); );
projection.projection_matrix = projection_matrix; projection.projection_matrix = projection_matrix;
println!(
"Updateing projectinon matrix to: {:#?}",
projection.projection_matrix
);
let openxr::Quaternionf { x, y, z, w } = view.pose.orientation; let openxr::Quaternionf { x, y, z, w } = view.pose.orientation;
let rotation = Quat::from_xyzw(x, y, z, w); let rotation = Quat::from_xyzw(x, y, z, w);
transform.rotation = rotation; transform.rotation = rotation;

View File

@@ -15,7 +15,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) -> crate::types::Result<OxrExtensions> {
Ok(self.0.enumerate_extensions().map(Into::into)?) Ok(self.0.enumerate_extensions().map(Into::into)?)
} }
@@ -28,7 +28,7 @@ impl OxrEntry {
exts: OxrExtensions, exts: OxrExtensions,
layers: &[&str], layers: &[&str],
backend: GraphicsBackend, backend: GraphicsBackend,
) -> Result<OxrInstance> { ) -> crate::types::Result<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 +53,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) -> crate::types::Result<Vec<GraphicsBackend>> {
Ok(GraphicsBackend::available_backends( Ok(GraphicsBackend::available_backends(
&self.enumerate_extensions()?, &self.enumerate_extensions()?,
)) ))
@@ -105,7 +105,7 @@ impl OxrInstance {
pub fn init_graphics( pub fn init_graphics(
&self, &self,
system_id: openxr::SystemId, system_id: openxr::SystemId,
) -> Result<(WgpuGraphics, SessionCreateInfo)> { ) -> crate::types::Result<(WgpuGraphics, SessionCreateInfo)> {
graphics_match!( graphics_match!(
self.1; self.1;
_ => { _ => {
@@ -128,9 +128,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)> { ) -> crate::types::Result<(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 crate::types::Result::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 +180,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<()> { ) -> crate::types::Result<()> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
stream => { stream => {
@@ -233,7 +233,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) -> crate::types::Result<u32> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
swap => Ok(swap.acquire_image()?) swap => Ok(swap.acquire_image()?)
@@ -243,7 +243,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) -> crate::types::Result<()> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
swap => Ok(swap.wait_image(timeout)?) swap => Ok(swap.wait_image(timeout)?)
@@ -253,7 +253,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) -> crate::types::Result<()> {
graphics_match!( graphics_match!(
&mut self.0; &mut self.0;
swap => Ok(swap.release_image()?) swap => Ok(swap.release_image()?)
@@ -268,7 +268,7 @@ impl OxrSwapchain {
device: &wgpu::Device, device: &wgpu::Device,
format: wgpu::TextureFormat, format: wgpu::TextureFormat,
resolution: UVec2, resolution: UVec2,
) -> Result<OxrSwapchainImages> { ) -> crate::types::Result<OxrSwapchainImages> {
graphics_match!( graphics_match!(
&self.0; &self.0;
swap => { swap => {

View File

@@ -1,6 +1,8 @@
use std::{mem::MaybeUninit, ptr, sync::Mutex}; use std::{mem::MaybeUninit, ptr, sync::Mutex};
use bevy::{prelude::*, utils::hashbrown::HashSet}; use bevy::{prelude::*};
use bevy::platform_support::*;
use bevy::platform_support::hash::FixedHasher;
use bevy_mod_xr::{ use bevy_mod_xr::{
session::{XrFirst, XrHandleEvents}, session::{XrFirst, XrHandleEvents},
spaces::{ spaces::{
@@ -64,7 +66,7 @@ fn destroy_space_event(instance: Res<OxrInstance>, mut events: EventReader<XrDes
} }
} }
pub static OXR_DO_NOT_CALL_DESTOY_SPACE_FOR_SPACES: Mutex<Option<HashSet<u64>>> = Mutex::new(None); pub static OXR_DO_NOT_CALL_DESTOY_SPACE_FOR_SPACES: Mutex<Option<bevy::platform_support::collections::hash_set::HashSet<u64, bevy::platform_support::hash::RandomState>>> = Mutex::new(None);
pub static OXR_ORIGINAL_DESTOY_SPACE: Mutex<Option<openxr::sys::pfn::DestroySpace>> = pub static OXR_ORIGINAL_DESTOY_SPACE: Mutex<Option<openxr::sys::pfn::DestroySpace>> =
Mutex::new(None); Mutex::new(None);
@@ -72,7 +74,7 @@ fn patch_destroy_space(instance: ResMut<OxrInstance>) {
OXR_DO_NOT_CALL_DESTOY_SPACE_FOR_SPACES OXR_DO_NOT_CALL_DESTOY_SPACE_FOR_SPACES
.lock() .lock()
.unwrap() .unwrap()
.replace(HashSet::new()); .replace(bevy::platform_support::collections::hash_set::HashSet::new());
let raw_instance_ptr = instance.fp() as *const _ as *mut openxr::raw::Instance; let raw_instance_ptr = instance.fp() as *const _ as *mut openxr::raw::Instance;
unsafe { unsafe {
OXR_ORIGINAL_DESTOY_SPACE OXR_ORIGINAL_DESTOY_SPACE

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

@@ -2,15 +2,15 @@ use core::panic;
use bevy::app::{App, Plugin, PostUpdate}; use bevy::app::{App, Plugin, PostUpdate};
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, HookContext, Mutable, StorageType};
use bevy::ecs::reflect::ReflectComponent; use bevy::ecs::reflect::ReflectComponent;
use bevy::ecs::schedule::IntoSystemConfigs; use bevy::ecs::world::DeferredWorld;
use bevy::math::{Mat4, Vec3A, Vec4}; use bevy::math::{Mat4, Vec3A, Vec4};
use bevy::pbr::{PbrPlugin, PbrProjectionPlugin}; use bevy::pbr::{PbrPlugin, PbrProjectionPlugin};
use bevy::prelude::{Projection, 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, CameraProjectionPlugin, CustomProjection};
use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin}; use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin};
use bevy::render::view::{update_frusta, VisibilitySystems}; use bevy::render::view::{update_frusta, VisibilitySystems};
use bevy::transform::TransformSystem; use bevy::transform::TransformSystem;
@@ -21,7 +21,7 @@ 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(CameraProjectionPlugin::<XrProjection>::default());
app.add_systems( app.add_systems(
PostUpdate, PostUpdate,
update_frusta::<XrProjection> update_frusta::<XrProjection>
@@ -30,31 +30,23 @@ impl Plugin for XrCameraPlugin {
); );
if app.is_plugin_added::<PbrPlugin>() { if app.is_plugin_added::<PbrPlugin>() {
app.add_plugins(PbrProjectionPlugin::<XrProjection>::default()); app.add_plugins(PbrProjectionPlugin::<XrProjection>::default());
} }*/
app.add_plugins(( app.add_plugins((ExtractComponentPlugin::<XrCamera>::default(),));
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) { fn on_projection_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
hooks.on_add(|mut world, entity, _| { world.commands().entity(entity).remove::<Projection>();
world.commands().entity(entity).remove::<Projection>();
});
}
} }
impl Default for XrProjection { impl Default for XrProjection {
@@ -68,7 +60,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 {

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, 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;
@@ -181,7 +180,7 @@ pub struct SpawnHandTracker<B: Bundle> {
pub side: HandSide, pub side: HandSide,
} }
impl<B: Bundle> Command for SpawnHandTracker<B> { impl<B: Bundle> bevy::prelude::Command for SpawnHandTracker<B> {
fn apply(self, world: &mut bevy::prelude::World) { fn apply(self, world: &mut bevy::prelude::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");

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, Mutable, StorageType};
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 {

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();
@@ -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();
@@ -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();