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"]
[workspace.dependencies]
bevy = { version = "0.15", default-features = false, features = [
bevy = { git = "https://github.com/bevyengine/bevy", default-features = false, features = [
"bevy_render",
"bevy_core_pipeline",
"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" }
openxr = "0.19.0"
thiserror = "2.0.3"
wgpu = "23"
wgpu-hal = "23"
wgpu = "24.0.1"
wgpu-hal = "24.0.2"

View File

@@ -26,6 +26,7 @@ fn main() {
.insert_resource(AmbientLight {
color: Default::default(),
brightness: 500.0,
affects_lightmapped_meshes: false,
})
.insert_resource(ClearColor(Color::NONE))
.run();

View File

@@ -3,8 +3,8 @@ use std::ptr;
use bevy::ecs::schedule::ScheduleLabel;
use bevy::ecs::system::RunSystemOnce;
use bevy::platform_support::collections::HashMap;
use bevy::prelude::*;
use bevy::utils::HashMap;
use bevy_mod_xr::session::XrSessionCreatedEvent;
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>) {
let mut bindings: HashMap<&str, Vec<ActionSuggestedBinding>> = HashMap::new();
let mut bindings: HashMap<&str, Vec<ActionSuggestedBinding>, _> = HashMap::new();
for e in actions.read() {
bindings.entry(&e.interaction_profile).or_default().extend(
e.bindings

View File

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

View File

@@ -73,7 +73,7 @@ pub fn create_passthrough(
session: &OxrSession,
flags: openxr::PassthroughFlagsFB,
purpose: openxr::PassthroughLayerPurposeFB,
) -> Result<(OxrPassthrough, OxrPassthroughLayer)> {
) -> crate::types::Result<(OxrPassthrough, OxrPassthroughLayer)> {
let passthrough = session.create_passthrough(flags)?;
let passthrough_layer = session.create_passthrough_layer(&passthrough, purpose)?;
@@ -82,7 +82,7 @@ pub fn create_passthrough(
}
#[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() {
return Ok(false);
}

View File

@@ -3,6 +3,7 @@ use std::ffi::{c_void, CString};
use ash::vk::Handle;
use bevy::log::{debug, error};
use bevy::math::UVec2;
use bevy::render::render_resource::TextureFormat;
use openxr::{sys, Version};
use wgpu_hal::api::Vulkan;
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)?;
let device_extensions = [
ash::khr::swapchain::NAME,
#[cfg(target_os = "android")]
ash::khr::draw_indirect_count::NAME,
ash::khr::timeline_semaphore::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,
},
},
TextureFormat::R64Uint => {
panic!()
}
})
}

View File

@@ -104,6 +104,7 @@ impl Plugin for OxrInitPlugin {
RenderInstance(Arc::new(WgpuWrapper::new(wgpu_instance))),
),
synchronous_pipeline_compilation: self.synchronous_pipeline_compilation,
debug_flags: Default::default(),
},
ExtractResourcePlugin::<OxrSessionStarted>::default(),
))
@@ -206,7 +207,7 @@ fn detect_session_destroyed(
impl OxrInitPlugin {
fn init_xr(
&self,
) -> Result<(
) -> crate::types::Result<(
OxrInstance,
OxrSystemId,
WgpuGraphics,
@@ -350,7 +351,7 @@ fn init_xr_session(
resolutions,
graphics_info,
}: SessionConfigInfo,
) -> Result<(
) -> crate::types::Result<(
OxrSession,
OxrFrameWaiter,
OxrFrameStream,

View File

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

View File

@@ -1,3 +1,4 @@
use super::{openxr_session_available, resources::OxrInstance};
use bevy::{ecs::system::SystemId, prelude::*};
use bevy_mod_xr::session::{XrFirst, XrHandleEvents};
use openxr::{Event, EventDataBuffer};
@@ -30,7 +31,7 @@ pub fn poll_events(world: &mut World) {
.iter()
.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}");
};
}
@@ -38,7 +39,6 @@ pub fn poll_events(world: &mut World) {
world.insert_resource(handlers);
}
use super::{openxr_session_available, resources::OxrInstance};
#[derive(Resource, Debug, Default)]
pub struct OxrEventHandlers(Vec<Entity>);
pub trait OxrEventHandlerExt {

View File

@@ -1,10 +1,11 @@
use bevy::render::camera::CustomProjection;
use bevy::{
prelude::*,
render::{
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget},
extract_resource::ExtractResourcePlugin,
pipelined_rendering::PipelinedRenderingPlugin,
view::ExtractedView,
view::{ExtractedView, NoFrustumCulling},
Render, RenderApp,
},
transform::TransformSystem,
@@ -170,6 +171,8 @@ pub fn init_views<const SPAWN_CAMERAS: bool>(
..Default::default()
},
XrCamera(index),
Projection::custom(XrProjection::default()),
NoFrustumCulling,
));
}
}
@@ -244,13 +247,18 @@ pub fn locate_views(
}
pub fn update_views(
mut query: Query<(&mut Transform, &mut XrProjection, &XrCamera)>,
mut query: Query<(&mut Transform, &mut Projection, &XrCamera)>,
views: ResMut<OxrViews>,
) {
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 {
continue;
};
let projection = match projection.as_mut() {
Projection::Custom(custom) => custom.get_mut::<XrProjection>().unwrap(),
_ => unreachable!(),
};
let projection_matrix = calculate_projection(
projection.near,
@@ -263,6 +271,11 @@ pub fn update_views(
);
projection.projection_matrix = projection_matrix;
println!(
"Updateing projectinon matrix to: {:#?}",
projection.projection_matrix
);
let openxr::Quaternionf { x, y, z, w } = view.pose.orientation;
let rotation = Quat::from_xyzw(x, y, z, w);
transform.rotation = rotation;

View File

@@ -15,7 +15,7 @@ pub struct OxrEntry(pub openxr::Entry);
impl OxrEntry {
/// 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)?)
}
@@ -28,7 +28,7 @@ impl OxrEntry {
exts: OxrExtensions,
layers: &[&str],
backend: GraphicsBackend,
) -> Result<OxrInstance> {
) -> crate::types::Result<OxrInstance> {
let available_exts = self.enumerate_extensions()?;
if !backend.is_available(&available_exts) {
@@ -53,7 +53,7 @@ impl OxrEntry {
}
/// 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(
&self.enumerate_extensions()?,
))
@@ -105,7 +105,7 @@ impl OxrInstance {
pub fn init_graphics(
&self,
system_id: openxr::SystemId,
) -> Result<(WgpuGraphics, SessionCreateInfo)> {
) -> crate::types::Result<(WgpuGraphics, SessionCreateInfo)> {
graphics_match!(
self.1;
_ => {
@@ -128,9 +128,9 @@ impl OxrInstance {
system_id: openxr::SystemId,
info: SessionCreateInfo,
chain: &mut OxrSessionCreateNextChain,
) -> Result<(OxrSession, OxrFrameWaiter, OxrFrameStream)> {
) -> crate::types::Result<(OxrSession, OxrFrameWaiter, OxrFrameStream)> {
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>(),
backend: info.0.graphics_name(),
expected_backend: self.1.graphics_name(),
@@ -180,7 +180,7 @@ impl OxrFrameStream {
display_time: openxr::Time,
environment_blend_mode: openxr::EnvironmentBlendMode,
layers: &[&dyn CompositionLayer],
) -> Result<()> {
) -> crate::types::Result<()> {
graphics_match!(
&mut self.0;
stream => {
@@ -233,7 +233,7 @@ impl OxrSwapchain {
/// Determine the index of the next image to render to in the swapchain image array.
///
/// 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!(
&mut self.0;
swap => Ok(swap.acquire_image()?)
@@ -243,7 +243,7 @@ impl OxrSwapchain {
/// Wait for the compositor to finish reading from the oldest unwaited acquired image.
///
/// 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!(
&mut self.0;
swap => Ok(swap.wait_image(timeout)?)
@@ -253,7 +253,7 @@ impl OxrSwapchain {
/// Release the oldest acquired image.
///
/// 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!(
&mut self.0;
swap => Ok(swap.release_image()?)
@@ -268,7 +268,7 @@ impl OxrSwapchain {
device: &wgpu::Device,
format: wgpu::TextureFormat,
resolution: UVec2,
) -> Result<OxrSwapchainImages> {
) -> crate::types::Result<OxrSwapchainImages> {
graphics_match!(
&self.0;
swap => {

View File

@@ -1,6 +1,8 @@
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::{
session::{XrFirst, XrHandleEvents},
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>> =
Mutex::new(None);
@@ -72,7 +74,7 @@ fn patch_destroy_space(instance: ResMut<OxrInstance>) {
OXR_DO_NOT_CALL_DESTOY_SPACE_FOR_SPACES
.lock()
.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;
unsafe {
OXR_ORIGINAL_DESTOY_SPACE

View File

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

View File

@@ -2,15 +2,15 @@ use core::panic;
use bevy::app::{App, Plugin, PostUpdate};
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::schedule::IntoSystemConfigs;
use bevy::ecs::world::DeferredWorld;
use bevy::math::{Mat4, Vec3A, Vec4};
use bevy::pbr::{PbrPlugin, PbrProjectionPlugin};
use bevy::prelude::{Projection, SystemSet};
use bevy::reflect::std_traits::ReflectDefault;
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::view::{update_frusta, VisibilitySystems};
use bevy::transform::TransformSystem;
@@ -21,7 +21,7 @@ pub struct XrCameraPlugin;
impl Plugin for XrCameraPlugin {
fn build(&self, app: &mut App) {
app.add_plugins(CameraProjectionPlugin::<XrProjection>::default());
/*app.add_plugins(CameraProjectionPlugin::<XrProjection>::default());
app.add_systems(
PostUpdate,
update_frusta::<XrProjection>
@@ -30,31 +30,23 @@ impl Plugin for XrCameraPlugin {
);
if app.is_plugin_added::<PbrPlugin>() {
app.add_plugins(PbrProjectionPlugin::<XrProjection>::default());
}
app.add_plugins((
ExtractComponentPlugin::<XrProjection>::default(),
ExtractComponentPlugin::<XrCamera>::default(),
));
}*/
app.add_plugins((ExtractComponentPlugin::<XrCamera>::default(),));
}
}
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, SystemSet)]
pub struct XrViewInit;
#[derive(Debug, Clone, Reflect, ExtractComponent)]
#[reflect(Component, Default)]
#[derive(Debug, Clone, Reflect)]
#[reflect(Default)]
pub struct XrProjection {
pub projection_matrix: Mat4,
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, _| {
fn on_projection_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
world.commands().entity(entity).remove::<Projection>();
});
}
}
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.
#[derive(Clone, Copy, Component, ExtractComponent, Debug, Default)]
#[require(Camera3d, XrProjection, XrTracker)]
#[require(Camera3d, XrTracker)]
pub struct XrCamera(pub u32);
impl CameraProjection for XrProjection {

View File

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

View File

@@ -3,8 +3,9 @@ use std::sync::atomic::AtomicBool;
use std::sync::Arc;
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::world::DeferredWorld;
use bevy::prelude::*;
use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin};
use bevy::render::{Render, RenderApp, RenderSet};
@@ -96,16 +97,13 @@ pub struct XrTrackingRoot;
struct TrackingRootRes(Entity);
/// 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;
impl Component for XrTracker {
const STORAGE_TYPE: StorageType = StorageType::SparseSet;
fn register_component_hooks(hooks: &mut bevy::ecs::component::ComponentHooks) {
hooks.on_add(|mut world, entity, _| {
fn on_tracker_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
if world
.entity(entity)
.get_components::<Has<Parent>>()
.get_components::<Has<Children>>()
.is_some_and(identity)
{
return;
@@ -114,8 +112,6 @@ impl Component for XrTracker {
return;
};
world.commands().entity(root).add_child(entity);
});
}
}
pub struct XrSessionPlugin {

View File

@@ -131,7 +131,7 @@ fn create_openxr_events(
commands.entity(id).insert(oxr_action_set);
//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
let (create_action, bindings) = actions_query.get(child).unwrap();
//lets create dat action
@@ -158,7 +158,7 @@ fn create_openxr_events(
}),
));
//since we need actions for bindings lets go!!
for &bind in bindings.iter() {
for bind in bindings.iter() {
//interaction profile
//get the binding entity and stuff
let create_binding = bindings_query.get(bind).unwrap();
@@ -197,7 +197,7 @@ fn create_openxr_events(
}),
));
//since we need actions for bindings lets go!!
for &bind in bindings.iter() {
for bind in bindings.iter() {
//interaction profile
//get the binding entity and stuff
let create_binding = bindings_query.get(bind).unwrap();
@@ -236,7 +236,7 @@ fn create_openxr_events(
}),
));
//since we need actions for bindings lets go!!
for &bind in bindings.iter() {
for bind in bindings.iter() {
//interaction profile
//get the binding entity and stuff
let create_binding = bindings_query.get(bind).unwrap();