From d98b9a4455964cc0a6a9f5045d2c149edabdb6f0 Mon Sep 17 00:00:00 2001 From: awtterpip Date: Thu, 18 Apr 2024 16:30:18 -0500 Subject: [PATCH] Revert "move to single crate for webxr and openxr" This reverts commit 5e769ef52bcbf86415749b22d0f7ffbbaedabbc9. --- Cargo.toml | 168 +++++++------- crates/bevy_openxr/Cargo.toml | 25 +++ crates/bevy_openxr/examples/3d_scene.rs | 79 +++++++ crates/bevy_openxr/src/actions.rs | 205 ++++++++++++++++++ .../bevy_openxr/src/camera.rs | 0 {src/oxr => crates/bevy_openxr/src}/error.rs | 58 +---- .../bevy_openxr/src/extensions.rs | 16 +- .../bevy_openxr/src/graphics.rs | 80 ++----- .../bevy_openxr/src}/graphics/vulkan.rs | 136 ++++++------ {src/oxr => crates/bevy_openxr/src}/init.rs | 185 ++++++++-------- .../bevy_openxr/src}/layer_builder.rs | 16 +- .../mod.rs => crates/bevy_openxr/src/lib.rs | 33 +-- {src/oxr => crates/bevy_openxr/src}/render.rs | 64 +++--- .../bevy_openxr/src}/resources.rs | 195 +++++++++-------- {src/oxr => crates/bevy_openxr/src}/types.rs | 47 ++-- {bevy_xr_api => crates/bevy_xr}/Cargo.toml | 2 +- .../bevy_xr}/macros/Cargo.toml | 0 .../bevy_xr}/macros/src/lib.rs | 0 .../bevy_xr}/src/actions.rs | 0 {bevy_xr_api => crates/bevy_xr}/src/camera.rs | 0 {bevy_xr_api => crates/bevy_xr}/src/lib.rs | 0 .../bevy_xr}/src/session.rs | 0 {bevy_xr_api => crates/bevy_xr}/src/types.rs | 0 examples/3d_scene.rs | 5 +- src/lib.rs | 9 +- 25 files changed, 747 insertions(+), 576 deletions(-) create mode 100644 crates/bevy_openxr/Cargo.toml create mode 100644 crates/bevy_openxr/examples/3d_scene.rs create mode 100644 crates/bevy_openxr/src/actions.rs rename src/webxr/mod.rs => crates/bevy_openxr/src/camera.rs (100%) rename {src/oxr => crates/bevy_openxr/src}/error.rs (56%) rename src/oxr/exts.rs => crates/bevy_openxr/src/extensions.rs (96%) rename src/oxr/graphics/mod.rs => crates/bevy_openxr/src/graphics.rs (51%) rename {src/oxr => crates/bevy_openxr/src}/graphics/vulkan.rs (97%) rename {src/oxr => crates/bevy_openxr/src}/init.rs (78%) rename {src/oxr => crates/bevy_openxr/src}/layer_builder.rs (91%) rename src/oxr/mod.rs => crates/bevy_openxr/src/lib.rs (83%) rename {src/oxr => crates/bevy_openxr/src}/render.rs (88%) rename {src/oxr => crates/bevy_openxr/src}/resources.rs (61%) rename {src/oxr => crates/bevy_openxr/src}/types.rs (54%) rename {bevy_xr_api => crates/bevy_xr}/Cargo.toml (90%) rename {bevy_xr_api => crates/bevy_xr}/macros/Cargo.toml (100%) rename {bevy_xr_api => crates/bevy_xr}/macros/src/lib.rs (100%) rename {bevy_xr_api => crates/bevy_xr}/src/actions.rs (100%) rename {bevy_xr_api => crates/bevy_xr}/src/camera.rs (100%) rename {bevy_xr_api => crates/bevy_xr}/src/lib.rs (100%) rename {bevy_xr_api => crates/bevy_xr}/src/session.rs (100%) rename {bevy_xr_api => crates/bevy_xr}/src/types.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index e9b3c92..157b840 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,114 +1,98 @@ [package] -name = "bevy_xr" +name = "bevy_oxr" version = "0.1.0" edition = "2021" -description = "Community crate for XR in Bevy" +description = "Community crate for OpenXR in Bevy" repository = "https://github.com/awtterpip/bevy_oxr" license = "MIT/Apache-2.0" [features] -default = ["vulkan"] +default = ["linked", "vulkan"] +linked = ["openxr/linked"] vulkan = ["dep:ash"] [dependencies] +bevy_openxr.path = "./crates/bevy_openxr" +bevy_xr.path = "./crates/bevy_xr" +anyhow = "1.0.79" +async-std = "1.12.0" bevy = "0.13.0" +paste = "1.0.14" +thiserror = "1.0.57" wgpu = "0.19.3" wgpu-hal = "0.19.3" -thiserror = "1.0.57" -bevy_xr_api.path = "bevy_xr_api" +winit = "0.28.7" + +[target.'cfg(target_family = "unix")'.dependencies] +openxr = { version = "0.17.1", features = ["mint"] } + +[target.'cfg(target_family = "windows")'.dependencies] +openxr = { version = "0.17.1", features = ["mint", "static"] } [target.'cfg(not(target_family = "wasm"))'.dependencies] ash = { version = "0.37.3", optional = true } -[target.'cfg(target_family = "unix")'.dependencies] -openxr = { version = "0.18.0", features = ["mint"] } - -[target.'cfg(target_family = "windows")'.dependencies] -openxr = { version = "0.18.0", features = ["mint", "static"] } - - -# [dependencies] -# bevy_openxr.path = "./crates/bevy_openxr" -# bevy_xr.path = "./crates/bevy_xr" -# anyhow = "1.0.79" -# async-std = "1.12.0" -# bevy = "0.13.0" -# paste = "1.0.14" -# thiserror = "1.0.57" -# wgpu = "0.19.3" -# wgpu-hal = "0.19.3" -# winit = "0.28.7" - -# [target.'cfg(target_family = "unix")'.dependencies] -# openxr = { version = "0.17.1", features = ["mint"] } - -# [target.'cfg(target_family = "windows")'.dependencies] -# openxr = { version = "0.17.1", features = ["mint", "static"] } - -# [target.'cfg(not(target_family = "wasm"))'.dependencies] -# ash = { version = "0.37.3", optional = true } - -# [target.'cfg(target_family = "wasm")'.dependencies] -# js-sys = "0.3" -# wasm-bindgen = "0.2.91" -# glow = "0.12.1" -# web-sys = { version = "0.3.67", features = [ -# # STANDARD -# 'console', -# 'Document', -# 'Element', -# 'Headers', -# 'Navigator', -# 'Window', -# # IO -# # 'Url', -# # WEBGL -# 'Gpu', -# 'HtmlCanvasElement', -# 'WebGl2RenderingContext', -# 'WebGlFramebuffer', -# 'GamepadHapticActuator', -# ## XR -# 'DomPointReadOnly', -# 'XrWebGlLayer', -# 'XrBoundedReferenceSpace', -# 'XrEye', -# 'XrFrame', -# 'XrHandedness', -# 'XrInputSource', -# 'XrInputSourceArray', -# 'XrInputSourceEvent', -# 'XrInputSourceEventInit', -# 'XrInputSourcesChangeEvent', -# 'XrJointPose', -# 'XrJointSpace', -# 'XrPose', -# 'XrReferenceSpace', -# 'XrReferenceSpaceEvent', -# 'XrReferenceSpaceEventInit', -# 'XrReferenceSpaceType', -# 'XrRenderState', -# 'XrRenderStateInit', -# 'XrRigidTransform', -# 'XrSession', -# 'XrSessionEvent', -# 'XrSessionEventInit', -# 'XrSessionInit', -# 'XrSessionMode', -# 'XrSpace', -# 'XrTargetRayMode', -# 'XrView', -# 'XrViewerPose', -# 'XrViewport', -# 'XrVisibilityState', -# 'XrWebGlLayer', -# 'XrWebGlLayerInit', -# 'XrSystem', -# ] } -# wasm-bindgen-futures = "0.4" +[target.'cfg(target_family = "wasm")'.dependencies] +js-sys = "0.3" +wasm-bindgen = "0.2.91" +glow = "0.12.1" +web-sys = { version = "0.3.67", features = [ + # STANDARD + 'console', + 'Document', + 'Element', + 'Headers', + 'Navigator', + 'Window', + # IO + # 'Url', + # WEBGL + 'Gpu', + 'HtmlCanvasElement', + 'WebGl2RenderingContext', + 'WebGlFramebuffer', + 'GamepadHapticActuator', + ## XR + 'DomPointReadOnly', + 'XrWebGlLayer', + 'XrBoundedReferenceSpace', + 'XrEye', + 'XrFrame', + 'XrHandedness', + 'XrInputSource', + 'XrInputSourceArray', + 'XrInputSourceEvent', + 'XrInputSourceEventInit', + 'XrInputSourcesChangeEvent', + 'XrJointPose', + 'XrJointSpace', + 'XrPose', + 'XrReferenceSpace', + 'XrReferenceSpaceEvent', + 'XrReferenceSpaceEventInit', + 'XrReferenceSpaceType', + 'XrRenderState', + 'XrRenderStateInit', + 'XrRigidTransform', + 'XrSession', + 'XrSessionEvent', + 'XrSessionEventInit', + 'XrSessionInit', + 'XrSessionMode', + 'XrSpace', + 'XrTargetRayMode', + 'XrView', + 'XrViewerPose', + 'XrViewport', + 'XrVisibilityState', + 'XrWebGlLayer', + 'XrWebGlLayerInit', + 'XrSystem', +] } +wasm-bindgen-futures = "0.4" [workspace] -members = ["bevy_xr_api"] +members = ["crates/*"] [workspace.dependencies] bevy = "0.13.0" diff --git a/crates/bevy_openxr/Cargo.toml b/crates/bevy_openxr/Cargo.toml new file mode 100644 index 0000000..c9e8514 --- /dev/null +++ b/crates/bevy_openxr/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "bevy_openxr" +version = "0.1.0" +edition = "2021" + +[features] +default = ["vulkan"] +vulkan = ["dep:ash"] + +[dependencies] +thiserror = "1.0.57" +wgpu = "0.19.3" +wgpu-hal = "0.19.3" + +bevy_xr.path = "../bevy_xr" +bevy.workspace = true + + +ash = { version = "0.37.3", optional = true } + +[target.'cfg(target_family = "unix")'.dependencies] +openxr = { version = "0.18.0", features = ["mint"] } + +[target.'cfg(target_family = "windows")'.dependencies] +openxr = { version = "0.18.0", features = ["mint", "static"] } diff --git a/crates/bevy_openxr/examples/3d_scene.rs b/crates/bevy_openxr/examples/3d_scene.rs new file mode 100644 index 0000000..fe150d9 --- /dev/null +++ b/crates/bevy_openxr/examples/3d_scene.rs @@ -0,0 +1,79 @@ +//! A simple 3D scene with light shining over a cube sitting on a plane. + +use std::any::TypeId; + +use bevy::prelude::*; +use bevy_openxr::{ + actions::{create_action_sets, ActionApp}, + add_xr_plugins, resources::{TypedAction, XrActions, XrInstance}, +}; +use bevy_xr::actions::{Action, ActionState}; +use openxr::Binding; + +#[derive(Action)] +#[action(action_type = bool, name = "jump")] +pub struct Jump; + +fn main() { + App::new() + .add_plugins(add_xr_plugins(DefaultPlugins)) + .add_systems(Startup, setup.after(create_action_sets)) + .add_systems(Update, read_action_state) + .register_action::() + .run(); +} + +/// set up a simple 3D scene +fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + actions: Res, + instance: Res, +) { + let TypedAction::Bool(action) = actions.get(&TypeId::of::()).unwrap() else { + unreachable!() + }; + instance.suggest_interaction_profile_bindings(instance.string_to_path("/interaction_profiles/oculus/touch_controller").unwrap(), &[ + Binding::new(action, instance.string_to_path("/user/hand/right/input/a/click").unwrap()) + ]).unwrap(); + // circular base + commands.spawn(PbrBundle { + mesh: meshes.add(Circle::new(4.0)), + material: materials.add(Color::WHITE), + transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)), + ..default() + }); + // cube + commands.spawn(PbrBundle { + mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)), + material: materials.add(Color::rgb_u8(124, 144, 255)), + transform: Transform::from_xyz(0.0, 0.5, 0.0), + ..default() + }); + // light + commands.spawn(PointLightBundle { + point_light: PointLight { + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }); + // // camera + // commands.spawn(XrCameraBundle { + // transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y), + // camera: Camera { + // target: RenderTarget::TextureView(ManualTextureViewHandle(XR_TEXTURE_INDEX + 1)), + // ..default() + // }, + // ..default() + // }); +} + +fn read_action_state( + state: Res> +) { + info!("{}", state.pressed()) +} + diff --git a/crates/bevy_openxr/src/actions.rs b/crates/bevy_openxr/src/actions.rs new file mode 100644 index 0000000..12770f1 --- /dev/null +++ b/crates/bevy_openxr/src/actions.rs @@ -0,0 +1,205 @@ +use std::any::TypeId; +use std::marker::PhantomData; + +use crate::init::XrPreUpdateSet; +use crate::resources::*; +use crate::types::*; +use bevy::app::{App, Plugin, PreUpdate, Startup}; +use bevy::ecs::schedule::common_conditions::resource_added; +use bevy::ecs::schedule::IntoSystemConfigs; +use bevy::ecs::system::{Commands, Res, ResMut}; +use bevy::input::InputSystem; +use bevy::log::error; +use bevy::math::{vec2, Vec2}; +use bevy::utils::hashbrown::HashMap; +use bevy_xr::actions::ActionPlugin; +use bevy_xr::actions::{Action, ActionList, ActionState}; +use bevy_xr::session::session_available; +use bevy_xr::session::session_running; + +pub struct XrActionPlugin; + +impl Plugin for XrActionPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, create_action_sets.run_if(session_available)) + .add_systems( + PreUpdate, + sync_actions.run_if(session_running).before(InputSystem), + ) + .add_systems( + PreUpdate, + attach_action_sets + .after(XrPreUpdateSet::HandleEvents) + .run_if(resource_added::), + ); + } +} + +pub fn create_action_sets( + instance: Res, + action_list: Res, + mut commands: Commands, +) { + let (action_set, actions) = + initialize_action_sets(&instance, &action_list).expect("Failed to initialize action set"); + + commands.insert_resource(action_set); + commands.insert_resource(actions); +} + +pub fn attach_action_sets(mut action_set: ResMut, session: Res) { + session + .attach_action_sets(&[&action_set]) + .expect("Failed to attach action sets"); + action_set.attach(); +} + +pub fn sync_actions(session: Res, action_set: Res) { + session + .sync_actions(&[openxr::ActiveActionSet::new(&action_set)]) + .expect("Failed to sync actions"); +} + +fn initialize_action_sets( + instance: &XrInstance, + action_info: &ActionList, +) -> Result<(XrActionSet, XrActions)> { + let action_set = instance.create_action_set("actions", "actions", 0)?; + let mut actions = HashMap::new(); + for action_info in action_info.0.iter() { + use bevy_xr::actions::ActionType::*; + let action = match action_info.action_type { + Bool => TypedAction::Bool(action_set.create_action( + action_info.name, + action_info.pretty_name, + &[], + )?), + Float => TypedAction::Float(action_set.create_action( + action_info.name, + action_info.pretty_name, + &[], + )?), + Vector => TypedAction::Vector(action_set.create_action( + action_info.name, + action_info.pretty_name, + &[], + )?), + }; + actions.insert(action_info.type_id, action); + } + Ok((XrActionSet::new(action_set), XrActions(actions))) +} + +pub struct XrActionUpdatePlugin(PhantomData); + +impl Plugin for XrActionUpdatePlugin +where + A: Action, + A::ActionType: XrActionTy, +{ + fn build(&self, app: &mut App) { + app.add_systems(PreUpdate, update_action_state::.in_set(InputSystem).run_if(session_running)); + } +} + +impl Default for XrActionUpdatePlugin { + fn default() -> Self { + Self(Default::default()) + } +} + +pub trait XrActionTy: Sized { + fn get_action_state( + action: &TypedAction, + session: &XrSession, + subaction_path: Option, + ) -> Option; +} + +impl XrActionTy for bool { + fn get_action_state( + action: &TypedAction, + session: &XrSession, + subaction_path: Option, + ) -> Option { + match action { + TypedAction::Bool(action) => action + .state(session, subaction_path.unwrap_or(openxr::Path::NULL)) + .ok() + .map(|state| state.current_state), + _ => None, + } + } +} + +impl XrActionTy for f32 { + fn get_action_state( + action: &TypedAction, + session: &XrSession, + subaction_path: Option, + ) -> Option { + match action { + TypedAction::Float(action) => action + .state(session, subaction_path.unwrap_or(openxr::Path::NULL)) + .ok() + .map(|state| state.current_state), + _ => None, + } + } +} + +impl XrActionTy for Vec2 { + fn get_action_state( + action: &TypedAction, + session: &XrSession, + subaction_path: Option, + ) -> Option { + match action { + TypedAction::Vector(action) => action + .state(session, subaction_path.unwrap_or(openxr::Path::NULL)) + .ok() + .map(|state| vec2(state.current_state.x, state.current_state.y)), + _ => None, + } + } +} + +pub fn update_action_state( + mut action_state: ResMut>, + session: Res, + actions: Res, +) where + A: Action, + A::ActionType: XrActionTy, +{ + if let Some(action) = actions.get(&TypeId::of::()) { + if let Some(state) = A::ActionType::get_action_state(action, &session, None) { + action_state.set(state); + } else { + error!( + "Failed to update value for action '{}'", + std::any::type_name::() + ); + } + } +} + +pub trait ActionApp { + fn register_action(&mut self) -> &mut Self + where + A: Action, + A::ActionType: XrActionTy; +} + +impl ActionApp for App { + fn register_action(&mut self) -> &mut Self + where + A: Action, + A::ActionType: XrActionTy, + { + self.add_plugins(( + ActionPlugin::::default(), + XrActionUpdatePlugin::::default(), + )) + } +} diff --git a/src/webxr/mod.rs b/crates/bevy_openxr/src/camera.rs similarity index 100% rename from src/webxr/mod.rs rename to crates/bevy_openxr/src/camera.rs diff --git a/src/oxr/error.rs b/crates/bevy_openxr/src/error.rs similarity index 56% rename from src/oxr/error.rs rename to crates/bevy_openxr/src/error.rs index 2bf1236..cf18d49 100644 --- a/src/oxr/error.rs +++ b/crates/bevy_openxr/src/error.rs @@ -1,12 +1,10 @@ +use crate::graphics::GraphicsBackend; use std::borrow::Cow; use std::fmt; - -use super::graphics::GraphicsBackend; - use thiserror::Error; #[derive(Error, Debug)] -pub enum OXrError { +pub enum XrError { #[error("OpenXR error: {0}")] OpenXrError(#[from] openxr::sys::Result), #[error("OpenXR loading error: {0}")] @@ -19,6 +17,10 @@ pub enum OXrError { WgpuRequestDeviceError(#[from] wgpu::RequestDeviceError), #[error("Unsupported texture format: {0:?}")] UnsupportedTextureFormat(wgpu::TextureFormat), + #[error("Vulkan error: {0}")] + VulkanError(#[from] ash::vk::Result), + #[error("Vulkan loading error: {0}")] + VulkanLoadingError(#[from] ash::LoadingError), #[error("Graphics backend '{0:?}' is not available")] UnavailableBackend(GraphicsBackend), #[error("No compatible backend available")] @@ -43,55 +45,9 @@ pub enum OXrError { }, #[error("Failed to create CString: {0}")] NulError(#[from] std::ffi::NulError), - #[error("Graphics init error: {0}")] - InitError(InitError), } -pub use init_error::InitError; - -/// This module is needed because thiserror does not allow conditional compilation within enums for some reason, -/// so graphics api specific errors are implemented here. -mod init_error { - use super::OXrError; - use std::fmt; - - #[derive(Debug)] - pub enum InitError { - #[cfg(feature = "vulkan")] - VulkanError(ash::vk::Result), - #[cfg(feature = "vulkan")] - VulkanLoadingError(ash::LoadingError), - } - - impl fmt::Display for InitError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - #[cfg(feature = "vulkan")] - InitError::VulkanError(error) => write!(f, "Vulkan error: {}", error), - #[cfg(feature = "vulkan")] - InitError::VulkanLoadingError(error) => { - write!(f, "Vulkan loading error: {}", error) - } - } - } - } - - #[cfg(feature = "vulkan")] - impl From for OXrError { - fn from(value: ash::vk::Result) -> Self { - Self::InitError(InitError::VulkanError(value)) - } - } - - #[cfg(feature = "vulkan")] - impl From for OXrError { - fn from(value: ash::LoadingError) -> Self { - Self::InitError(InitError::VulkanLoadingError(value)) - } - } -} - -impl From>> for OXrError { +impl From>> for XrError { fn from(value: Vec>) -> Self { Self::UnavailableExtensions(UnavailableExts(value)) } diff --git a/src/oxr/exts.rs b/crates/bevy_openxr/src/extensions.rs similarity index 96% rename from src/oxr/exts.rs rename to crates/bevy_openxr/src/extensions.rs index 509f498..7c0ab27 100644 --- a/src/oxr/exts.rs +++ b/crates/bevy_openxr/src/extensions.rs @@ -2,8 +2,8 @@ use bevy::prelude::{Deref, DerefMut}; use openxr::ExtensionSet; #[derive(Clone, Debug, Eq, PartialEq, Deref, DerefMut)] -pub struct OXrExtensions(ExtensionSet); -impl OXrExtensions { +pub struct XrExtensions(ExtensionSet); +impl XrExtensions { pub fn raw_mut(&mut self) -> &mut ExtensionSet { &mut self.0 } @@ -27,21 +27,21 @@ impl OXrExtensions { self } /// returns true if all of the extensions enabled are also available in `available_exts` - pub fn is_available(&self, available_exts: &OXrExtensions) -> bool { + pub fn is_available(&self, available_exts: &XrExtensions) -> bool { self.clone() & available_exts.clone() == *self } } -impl From for OXrExtensions { +impl From for XrExtensions { fn from(value: ExtensionSet) -> Self { Self(value) } } -impl From for ExtensionSet { - fn from(val: OXrExtensions) -> Self { +impl From for ExtensionSet { + fn from(val: XrExtensions) -> Self { val.0 } } -impl Default for OXrExtensions { +impl Default for XrExtensions { fn default() -> Self { let exts = ExtensionSet::default(); //exts.ext_hand_tracking = true; @@ -165,7 +165,7 @@ macro_rules! impl_ext { ) => { $( $macro! { - OXrExtensions; + XrExtensions; almalence_digital_lens_control, bd_controller_interaction, epic_view_configuration_fov, diff --git a/src/oxr/graphics/mod.rs b/crates/bevy_openxr/src/graphics.rs similarity index 51% rename from src/oxr/graphics/mod.rs rename to crates/bevy_openxr/src/graphics.rs index 6684958..4d1e86b 100644 --- a/src/oxr/graphics/mod.rs +++ b/crates/bevy_openxr/src/graphics.rs @@ -5,51 +5,32 @@ use std::any::TypeId; use bevy::math::UVec2; -use crate::oxr::types::{AppInfo, OXrExtensions, Result, WgpuGraphics}; +use crate::extensions::XrExtensions; +use crate::types::*; -/// This is an extension trait to the [`Graphics`](openxr::Graphics) trait and is how the graphics API should be interacted with. pub unsafe trait GraphicsExt: openxr::Graphics { /// Wrap the graphics specific type into the [GraphicsWrap] enum fn wrap(item: T::Inner) -> GraphicsWrap; - /// Returns all of the required openxr extensions to use this graphics API. - fn required_exts() -> OXrExtensions; /// Convert from wgpu format to the graphics format fn from_wgpu_format(format: wgpu::TextureFormat) -> Option; /// Convert from the graphics format to wgpu format - fn into_wgpu_format(format: Self::Format) -> Option; - /// Convert an API specific swapchain image to a [`Texture`](wgpu::Texture). - /// - /// # Safety - /// - /// The `image` argument must be a valid handle. + fn to_wgpu_format(format: Self::Format) -> Option; + /// Initialize graphics for this backend + fn init_graphics( + app_info: &AppInfo, + instance: &openxr::Instance, + system_id: openxr::SystemId, + ) -> Result<(WgpuGraphics, Self::SessionCreateInfo)>; + /// Convert a swapchain function unsafe fn to_wgpu_img( image: Self::SwapchainImage, device: &wgpu::Device, format: wgpu::TextureFormat, resolution: UVec2, ) -> Result; - /// Initialize graphics for this backend and return a [`WgpuGraphics`] for bevy and an API specific [Self::SessionCreateInfo] for openxr - fn init_graphics( - app_info: &AppInfo, - instance: &openxr::Instance, - system_id: openxr::SystemId, - ) -> Result<(WgpuGraphics, Self::SessionCreateInfo)>; + fn required_exts() -> XrExtensions; } -/// A type that can be used in [`GraphicsWrap`]. -/// -/// # Example -/// -/// ``` -/// pub struct XrSession(GraphicsWrap); -/// -/// impl GraphicsType for XrSession { -/// type Inner = openxr::Session; -/// } -/// -/// ``` -/// -/// In this example, `GraphicsWrap` is now an enum with variants for each graphics API. The enum can be matched to get the graphics specific inner type. pub trait GraphicsType { type Inner; } @@ -58,13 +39,12 @@ impl GraphicsType for () { type Inner = (); } -/// This is a special variant of [GraphicsWrap] using the unit struct as the inner type. This is to simply represent a graphics backend without storing data. pub type GraphicsBackend = GraphicsWrap<()>; impl GraphicsBackend { const ALL: &'static [Self] = &[Self::Vulkan(())]; - pub fn available_backends(exts: &OXrExtensions) -> Vec { + pub fn available_backends(exts: &XrExtensions) -> Vec { Self::ALL .iter() .copied() @@ -72,11 +52,11 @@ impl GraphicsBackend { .collect() } - pub fn is_available(&self, exts: &OXrExtensions) -> bool { + pub fn is_available(&self, exts: &XrExtensions) -> bool { self.required_exts().is_available(exts) } - pub fn required_exts(&self) -> OXrExtensions { + pub fn required_exts(&self) -> XrExtensions { graphics_match!( self; _ => Api::required_exts() @@ -84,7 +64,6 @@ impl GraphicsBackend { } } -/// This struct is for creating agnostic objects for OpenXR graphics API specific structs. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum GraphicsWrap { #[cfg(feature = "vulkan")] @@ -118,33 +97,6 @@ impl GraphicsWrap { } } -/// This macro can be used to quickly run the same code for every variant of [GraphicsWrap]. -/// The first argument should be an expression that returns either a reference or owned value of [GraphicsWrap]. -/// The second argument should be a match arm with the pattern for the inner type. -/// -/// # Example -/// -/// ``` -/// pub struct OXrFrameStream(GraphicsWrap); -/// -/// impl GraphicsType for OXrFrameStream { -/// // Here is the inner type -/// type Inner = openxr::FrameStream; -/// } -/// -/// fn begin(frame_stream: &mut XrFrameStream) { -/// graphics_match! { -/// // get the inner 'GraphicsWrap' struct -/// &mut frame_stream.0; -/// // now we can handle every match arm with a single arm -/// // important: the first pattern here represents the inner type of `GraphicsWrap` -/// // it is already destructured for you. -/// stream => stream.begin(); -/// } -/// } -/// ``` -/// -/// Additionally, if you want the type that implements `GraphicsExt` in the scope of the match body, you can access that type through the type alias `Api`. macro_rules! graphics_match { ( $field:expr; @@ -152,7 +104,7 @@ macro_rules! graphics_match { ) => { match $field { #[cfg(feature = "vulkan")] - $crate::oxr::graphics::GraphicsWrap::Vulkan($var) => { + $crate::graphics::GraphicsWrap::Vulkan($var) => { #[allow(unused)] type Api = openxr::Vulkan; graphics_match!(@arm_impl Vulkan; $expr $(=> $($return)*)?) @@ -165,7 +117,7 @@ macro_rules! graphics_match { $variant:ident; $expr:expr => $wrap_ty:ty ) => { - $crate::oxr::graphics::GraphicsWrap::<$wrap_ty>::$variant($expr) + GraphicsWrap::<$wrap_ty>::$variant($expr) }; ( diff --git a/src/oxr/graphics/vulkan.rs b/crates/bevy_openxr/src/graphics/vulkan.rs similarity index 97% rename from src/oxr/graphics/vulkan.rs rename to crates/bevy_openxr/src/graphics/vulkan.rs index de3b143..469815e 100644 --- a/src/oxr/graphics/vulkan.rs +++ b/crates/bevy_openxr/src/graphics/vulkan.rs @@ -7,9 +7,11 @@ use openxr::Version; use wgpu_hal::api::Vulkan; use wgpu_hal::Api; -use super::{GraphicsExt, GraphicsType, GraphicsWrap}; -use crate::oxr::error::OXrError; -use crate::oxr::types::{AppInfo, OXrExtensions, Result, WgpuGraphics}; +use crate::error::XrError; +use crate::extensions::XrExtensions; +use crate::types::*; + +use super::GraphicsExt; #[cfg(not(target_os = "android"))] const VK_TARGET_VERSION: Version = Version::new(1, 2, 0); @@ -24,74 +26,14 @@ const VK_TARGET_VERSION_ASH: u32 = ash::vk::make_api_version( ); unsafe impl GraphicsExt for openxr::Vulkan { - fn wrap(item: T::Inner) -> GraphicsWrap { - GraphicsWrap::Vulkan(item) - } - - fn required_exts() -> OXrExtensions { - let mut extensions = openxr::ExtensionSet::default(); - extensions.khr_vulkan_enable2 = true; - extensions.into() - } - fn from_wgpu_format(format: wgpu::TextureFormat) -> Option { wgpu_to_vulkan(format).map(|f| f.as_raw() as _) } - fn into_wgpu_format(format: Self::Format) -> Option { + fn to_wgpu_format(format: Self::Format) -> Option { vulkan_to_wgpu(ash::vk::Format::from_raw(format as _)) } - unsafe fn to_wgpu_img( - color_image: Self::SwapchainImage, - device: &wgpu::Device, - format: wgpu::TextureFormat, - resolution: UVec2, - ) -> Result { - let color_image = ash::vk::Image::from_raw(color_image); - let wgpu_hal_texture = unsafe { - ::Device::texture_from_raw( - color_image, - &wgpu_hal::TextureDescriptor { - label: Some("VR Swapchain"), - size: wgpu::Extent3d { - width: resolution.x, - height: resolution.y, - depth_or_array_layers: 2, - }, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: format, - usage: wgpu_hal::TextureUses::COLOR_TARGET | wgpu_hal::TextureUses::COPY_DST, - memory_flags: wgpu_hal::MemoryFlags::empty(), - view_formats: vec![], - }, - None, - ) - }; - let texture = unsafe { - device.create_texture_from_hal::( - wgpu_hal_texture, - &wgpu::TextureDescriptor { - label: Some("VR Swapchain"), - size: wgpu::Extent3d { - width: resolution.x, - height: resolution.y, - depth_or_array_layers: 2, - }, - mip_level_count: 1, - sample_count: 1, - dimension: wgpu::TextureDimension::D2, - format: format, - usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST, - view_formats: &[], - }, - ) - }; - Ok(texture) - } - fn init_graphics( app_info: &AppInfo, instance: &openxr::Instance, @@ -106,7 +48,7 @@ unsafe impl GraphicsExt for openxr::Vulkan { reqs.min_api_version_supported, reqs.max_api_version_supported.major() + 1 ); - return Err(OXrError::FailedGraphicsRequirements); + return Err(XrError::FailedGraphicsRequirements); }; let vk_entry = unsafe { ash::Entry::load() }?; let flags = wgpu::InstanceFlags::empty(); @@ -165,7 +107,7 @@ unsafe impl GraphicsExt for openxr::Vulkan { VK_TARGET_VERSION.minor(), VK_TARGET_VERSION.patch() ); - return Err(OXrError::FailedGraphicsRequirements); + return Err(XrError::FailedGraphicsRequirements); } let wgpu_vk_instance = unsafe { @@ -189,7 +131,7 @@ unsafe impl GraphicsExt for openxr::Vulkan { let Some(wgpu_exposed_adapter) = wgpu_vk_instance.expose_adapter(vk_physical_device) else { error!("WGPU failed to provide an adapter"); - return Err(OXrError::FailedGraphicsRequirements); + return Err(XrError::FailedGraphicsRequirements); }; let enabled_extensions = wgpu_exposed_adapter @@ -292,6 +234,66 @@ unsafe impl GraphicsExt for openxr::Vulkan { }, )) } + + unsafe fn to_wgpu_img( + color_image: Self::SwapchainImage, + device: &wgpu::Device, + format: wgpu::TextureFormat, + resolution: UVec2, + ) -> Result { + let color_image = ash::vk::Image::from_raw(color_image); + let wgpu_hal_texture = unsafe { + ::Device::texture_from_raw( + color_image, + &wgpu_hal::TextureDescriptor { + label: Some("VR Swapchain"), + size: wgpu::Extent3d { + width: resolution.x, + height: resolution.y, + depth_or_array_layers: 2, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: format, + usage: wgpu_hal::TextureUses::COLOR_TARGET | wgpu_hal::TextureUses::COPY_DST, + memory_flags: wgpu_hal::MemoryFlags::empty(), + view_formats: vec![], + }, + None, + ) + }; + let texture = unsafe { + device.create_texture_from_hal::( + wgpu_hal_texture, + &wgpu::TextureDescriptor { + label: Some("VR Swapchain"), + size: wgpu::Extent3d { + width: resolution.x, + height: resolution.y, + depth_or_array_layers: 2, + }, + mip_level_count: 1, + sample_count: 1, + dimension: wgpu::TextureDimension::D2, + format: format, + usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::COPY_DST, + view_formats: &[], + }, + ) + }; + Ok(texture) + } + + fn required_exts() -> XrExtensions { + let mut extensions = openxr::ExtensionSet::default(); + extensions.khr_vulkan_enable2 = true; + extensions.into() + } + + fn wrap(item: T::Inner) -> super::GraphicsWrap { + super::GraphicsWrap::Vulkan(item) + } } fn vulkan_to_wgpu(format: ash::vk::Format) -> Option { diff --git a/src/oxr/init.rs b/crates/bevy_openxr/src/init.rs similarity index 78% rename from src/oxr/init.rs rename to crates/bevy_openxr/src/init.rs index 14124bf..2142197 100644 --- a/src/oxr/init.rs +++ b/crates/bevy_openxr/src/init.rs @@ -1,51 +1,41 @@ +use bevy::math::uvec2; use bevy::prelude::*; use bevy::render::extract_resource::ExtractResourcePlugin; -use bevy::render::renderer::RenderAdapter; -use bevy::render::renderer::RenderAdapterInfo; -use bevy::render::renderer::RenderDevice; -use bevy::render::renderer::RenderInstance; -use bevy::render::renderer::RenderQueue; +use bevy::render::renderer::{ + RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue, +}; use bevy::render::settings::RenderCreation; -use bevy::render::MainWorld; -use bevy::render::Render; -use bevy::render::RenderApp; -use bevy::render::RenderPlugin; -use bevy::render::RenderSet; +use bevy::render::{MainWorld, Render, RenderApp, RenderPlugin, RenderSet}; use bevy::transform::TransformSystem; -use bevy::winit::UpdateMode; -use bevy::winit::WinitSettings; -use bevy_xr_api::session::handle_session; -use bevy_xr_api::session::session_available; -use bevy_xr_api::session::session_running; -use bevy_xr_api::session::status_equals; -use bevy_xr_api::session::BeginXrSession; -use bevy_xr_api::session::CreateXrSession; -use bevy_xr_api::session::DestroyXrSession; -use bevy_xr_api::session::EndXrSession; -use bevy_xr_api::session::XrSharedStatus; -use bevy_xr_api::session::XrStatus; +use bevy::winit::{UpdateMode, WinitSettings}; +use bevy_xr::session::{ + handle_session, session_available, session_running, status_equals, BeginXrSession, + CreateXrSession, DestroyXrSession, EndXrSession, XrSharedStatus, XrStatus, +}; -use crate::oxr::error::OXrError; -use crate::oxr::graphics::*; -use crate::oxr::resources::*; -use crate::oxr::types::*; +use crate::graphics::*; +use crate::resources::*; +use crate::types::*; -pub fn session_started(started: Option>) -> bool { +pub fn session_started(started: Option>) -> bool { started.is_some_and(|started| started.get()) } #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)] -pub enum OXrPreUpdateSet { +pub enum XrPreUpdateSet { PollEvents, HandleEvents, } -pub struct OXrInitPlugin { +#[derive(Component)] +pub struct XrTrackingRoot; + +pub struct XrInitPlugin { /// Information about the app this is being used to build. pub app_info: AppInfo, /// Extensions wanted for this session. // TODO!() This should be changed to take a simpler list of features wanted that this crate supports. i.e. hand tracking - pub exts: OXrExtensions, + pub exts: XrExtensions, /// List of blend modes the openxr session can use. If [None], pick the first available blend mode. pub blend_modes: Option>, /// List of backends the openxr session can use. If [None], pick the first available backend. @@ -58,10 +48,7 @@ pub struct OXrInitPlugin { pub synchronous_pipeline_compilation: bool, } -#[derive(Component)] -pub struct OXrTrackingRoot; - -impl Plugin for OXrInitPlugin { +impl Plugin for XrInitPlugin { fn build(&self, app: &mut App) { match self.init_xr() { Ok(( @@ -83,9 +70,9 @@ impl Plugin for OXrInitPlugin { ), synchronous_pipeline_compilation: self.synchronous_pipeline_compilation, }, - ExtractResourcePlugin::::default(), - ExtractResourcePlugin::::default(), - ExtractResourcePlugin::::default(), + ExtractResourcePlugin::::default(), + ExtractResourcePlugin::::default(), + ExtractResourcePlugin::::default(), )) .add_systems(First, reset_per_frame_resources) .add_systems( @@ -93,7 +80,7 @@ impl Plugin for OXrInitPlugin { ( poll_events .run_if(session_available) - .in_set(OXrPreUpdateSet::PollEvents), + .in_set(XrPreUpdateSet::PollEvents), ( (create_xr_session, apply_deferred) .chain() @@ -109,7 +96,7 @@ impl Plugin for OXrInitPlugin { .run_if(on_event::()) .run_if(status_equals(XrStatus::Exiting)), ) - .in_set(OXrPreUpdateSet::HandleEvents), + .in_set(XrPreUpdateSet::HandleEvents), ), ) .add_systems( @@ -123,24 +110,24 @@ impl Plugin for OXrInitPlugin { focused_mode: UpdateMode::Continuous, unfocused_mode: UpdateMode::Continuous, }) - .init_resource::() - .init_resource::() + .init_resource::() + .init_resource::() .insert_non_send_resource(session_create_info); app.world - .spawn((TransformBundle::default(), OXrTrackingRoot)); + .spawn((TransformBundle::default(), XrTrackingRoot)); let render_app = app.sub_app_mut(RenderApp); render_app .insert_resource(instance) .insert_resource(system_id) .insert_resource(status) - .init_resource::() - .init_resource::() + .init_resource::() + .init_resource::() .add_systems( Render, destroy_xr_session_render - .run_if(resource_equals(OXrCleanupSession(true))) + .run_if(resource_equals(XrCleanupSession(true))) .after(RenderSet::ExtractCommands), ) .add_systems( @@ -164,12 +151,12 @@ impl Plugin for OXrInitPlugin { app.configure_sets( PreUpdate, ( - OXrPreUpdateSet::PollEvents.before(handle_session), - OXrPreUpdateSet::HandleEvents.after(handle_session), + XrPreUpdateSet::PollEvents.before(handle_session), + XrPreUpdateSet::HandleEvents.after(handle_session), ), ); - let session_started = OXrSessionStarted::default(); + let session_started = XrSessionStarted::default(); app.insert_resource(session_started.clone()); @@ -180,24 +167,24 @@ impl Plugin for OXrInitPlugin { } pub fn update_root_transform( - mut root_transform: ResMut, - root: Query<&GlobalTransform, With>, + mut root_transform: ResMut, + root: Query<&GlobalTransform, With>, ) { let transform = root.single(); root_transform.0 = *transform; } -fn xr_entry() -> Result { +fn xr_entry() -> Result { #[cfg(windows)] let entry = openxr::Entry::linked(); #[cfg(not(windows))] let entry = unsafe { openxr::Entry::load()? }; - Ok(OXrEntry(entry)) + Ok(XrEntry(entry)) } -impl OXrInitPlugin { - fn init_xr(&self) -> Result<(OXrInstance, OXrSystemId, WgpuGraphics, SessionConfigInfo)> { +impl XrInitPlugin { + fn init_xr(&self) -> Result<(XrInstance, XrSystemId, WgpuGraphics, XrSessionCreateInfo)> { let entry = xr_entry()?; let available_exts = entry.enumerate_extensions()?; @@ -224,7 +211,7 @@ impl OXrInitPlugin { } else { available_backends.first().copied() } - .ok_or(OXrError::NoAvailableBackend)?; + .ok_or(XrError::NoAvailableBackend)?; let exts = self.exts.clone() & available_exts; @@ -256,7 +243,7 @@ impl OXrInitPlugin { let (graphics, graphics_info) = instance.init_graphics(system_id)?; - let session_create_info = SessionConfigInfo { + let session_create_info = XrSessionCreateInfo { blend_modes: self.blend_modes.clone(), formats: self.formats.clone(), resolutions: self.resolutions.clone(), @@ -265,7 +252,7 @@ impl OXrInitPlugin { Ok(( instance, - OXrSystemId(system_id), + XrSystemId(system_id), graphics, session_create_info, )) @@ -274,22 +261,22 @@ impl OXrInitPlugin { fn init_xr_session( device: &wgpu::Device, - instance: &OXrInstance, + instance: &XrInstance, system_id: openxr::SystemId, - SessionConfigInfo { + XrSessionCreateInfo { blend_modes, formats, resolutions, graphics_info, - }: SessionConfigInfo, + }: XrSessionCreateInfo, ) -> Result<( - OXrSession, - OXrFrameWaiter, - OXrFrameStream, - OXrSwapchain, - OXrSwapchainImages, - OXrGraphicsInfo, - OXrStage, + XrSession, + XrFrameWaiter, + XrFrameStream, + XrSwapchain, + XrSwapchainImages, + XrGraphicsInfo, + XrStage, )> { let (session, frame_waiter, frame_stream) = unsafe { instance.create_session(system_id, graphics_info)? }; @@ -297,7 +284,7 @@ fn init_xr_session( // TODO!() support other view configurations let available_view_configurations = instance.enumerate_view_configurations(system_id)?; if !available_view_configurations.contains(&openxr::ViewConfigurationType::PRIMARY_STEREO) { - return Err(OXrError::NoAvailableViewConfiguration); + return Err(XrError::NoAvailableViewConfiguration); } let view_configuration_type = openxr::ViewConfigurationType::PRIMARY_STEREO; @@ -333,7 +320,7 @@ fn init_xr_session( } else { if let Some(config) = view_configuration_views.first() { Some(( - UVec2::new( + uvec2( config.recommended_image_rect_width, config.recommended_image_rect_height, ), @@ -343,7 +330,7 @@ fn init_xr_session( None } } - .ok_or(OXrError::NoAvailableViewConfiguration)?; + .ok_or(XrError::NoAvailableViewConfiguration)?; let available_formats = session.enumerate_swapchain_formats()?; @@ -358,7 +345,7 @@ fn init_xr_session( } else { available_formats.first().copied() } - .ok_or(OXrError::NoAvailableFormat)?; + .ok_or(XrError::NoAvailableFormat)?; let swapchain = session.create_swapchain(SwapchainCreateInfo { create_flags: SwapchainCreateFlags::EMPTY, @@ -391,15 +378,15 @@ fn init_xr_session( } else { available_blend_modes.first().copied() } - .ok_or(OXrError::NoAvailableBackend)?; + .ok_or(XrError::NoAvailableBackend)?; - let stage = OXrStage( + let stage = XrStage( session .create_reference_space(openxr::ReferenceSpaceType::STAGE, openxr::Posef::IDENTITY)? .into(), ); - let graphics_info = OXrGraphicsInfo { + let graphics_info = XrGraphicsInfo { blend_mode, resolution, format, @@ -419,19 +406,19 @@ fn init_xr_session( /// This is used solely to transport resources from the main world to the render world. #[derive(Resource)] struct XrRenderResources { - session: OXrSession, - frame_stream: OXrFrameStream, - swapchain: OXrSwapchain, - images: OXrSwapchainImages, - graphics_info: OXrGraphicsInfo, - stage: OXrStage, + session: XrSession, + frame_stream: XrFrameStream, + swapchain: XrSwapchain, + images: XrSwapchainImages, + graphics_info: XrGraphicsInfo, + stage: XrStage, } pub fn create_xr_session( device: Res, - instance: Res, - create_info: NonSend, - system_id: Res, + instance: Res, + create_info: NonSend, + system_id: Res, mut commands: Commands, ) { match init_xr_session( @@ -459,7 +446,7 @@ pub fn create_xr_session( } } -pub fn begin_xr_session(session: Res, session_started: Res) { +pub fn begin_xr_session(session: Res, session_started: Res) { let _span = info_span!("xr_begin_session"); session .begin(openxr::ViewConfigurationType::PRIMARY_STEREO) @@ -467,7 +454,7 @@ pub fn begin_xr_session(session: Res, session_started: Res, session_started: Res) { +pub fn end_xr_session(session: Res, session_started: Res) { let _span = info_span!("xr_end_session"); session.end().expect("Failed to end session"); session_started.set(false); @@ -496,7 +483,7 @@ pub fn transfer_xr_resources(mut commands: Commands, mut world: ResMut, status: Res) { +pub fn poll_events(instance: Res, status: Res) { let _span = info_span!("xr_poll_events"); let mut buffer = Default::default(); while let Some(event) = instance @@ -532,24 +519,24 @@ pub fn poll_events(instance: Res, status: Res) { } } -pub fn reset_per_frame_resources(mut cleanup: ResMut) { +pub fn reset_per_frame_resources(mut cleanup: ResMut) { **cleanup = false; } pub fn destroy_xr_session(mut commands: Commands) { - commands.remove_resource::(); - commands.remove_resource::(); - commands.remove_resource::(); - commands.remove_resource::(); - commands.remove_resource::(); - commands.insert_resource(OXrCleanupSession(true)); + commands.remove_resource::(); + commands.remove_resource::(); + commands.remove_resource::(); + commands.remove_resource::(); + commands.remove_resource::(); + commands.insert_resource(XrCleanupSession(true)); } pub fn destroy_xr_session_render(world: &mut World) { - world.remove_resource::(); - world.remove_resource::(); - world.remove_resource::(); - world.remove_resource::(); - world.remove_resource::(); - world.remove_resource::(); + world.remove_resource::(); + world.remove_resource::(); + world.remove_resource::(); + world.remove_resource::(); + world.remove_resource::(); + world.remove_resource::(); } diff --git a/src/oxr/layer_builder.rs b/crates/bevy_openxr/src/layer_builder.rs similarity index 91% rename from src/oxr/layer_builder.rs rename to crates/bevy_openxr/src/layer_builder.rs index ccf0c50..08257bf 100644 --- a/src/oxr/layer_builder.rs +++ b/crates/bevy_openxr/src/layer_builder.rs @@ -2,13 +2,13 @@ use std::mem; use openxr::{sys, CompositionLayerFlags, Fovf, Posef, Rect2Di, Space}; -use crate::oxr::graphics::graphics_match; -use crate::oxr::resources::OXrSwapchain; +use crate::graphics::graphics_match; +use crate::resources::XrSwapchain; #[derive(Copy, Clone)] pub struct SwapchainSubImage<'a> { inner: sys::SwapchainSubImage, - swapchain: Option<&'a OXrSwapchain>, + swapchain: Option<&'a XrSwapchain>, } impl<'a> SwapchainSubImage<'a> { @@ -30,7 +30,7 @@ impl<'a> SwapchainSubImage<'a> { &self.inner } #[inline] - pub fn swapchain(mut self, value: &'a OXrSwapchain) -> Self { + pub fn swapchain(mut self, value: &'a XrSwapchain) -> Self { graphics_match!( &value.0; swap => self.inner.swapchain = swap.as_raw() @@ -59,7 +59,7 @@ impl<'a> Default for SwapchainSubImage<'a> { #[derive(Copy, Clone)] pub struct CompositionLayerProjectionView<'a> { inner: sys::CompositionLayerProjectionView, - swapchain: Option<&'a OXrSwapchain>, + swapchain: Option<&'a XrSwapchain>, } impl<'a> CompositionLayerProjectionView<'a> { @@ -104,13 +104,13 @@ impl<'a> Default for CompositionLayerProjectionView<'a> { } } pub unsafe trait CompositionLayer<'a> { - fn swapchain(&self) -> Option<&'a OXrSwapchain>; + fn swapchain(&self) -> Option<&'a XrSwapchain>; fn header(&self) -> &'a sys::CompositionLayerBaseHeader; } #[derive(Clone)] pub struct CompositionLayerProjection<'a> { inner: sys::CompositionLayerProjection, - swapchain: Option<&'a OXrSwapchain>, + swapchain: Option<&'a XrSwapchain>, views: Vec, } impl<'a> CompositionLayerProjection<'a> { @@ -154,7 +154,7 @@ impl<'a> CompositionLayerProjection<'a> { } } unsafe impl<'a> CompositionLayer<'a> for CompositionLayerProjection<'a> { - fn swapchain(&self) -> Option<&'a OXrSwapchain> { + fn swapchain(&self) -> Option<&'a XrSwapchain> { self.swapchain } diff --git a/src/oxr/mod.rs b/crates/bevy_openxr/src/lib.rs similarity index 83% rename from src/oxr/mod.rs rename to crates/bevy_openxr/src/lib.rs index 19f0916..fb8289d 100644 --- a/src/oxr/mod.rs +++ b/crates/bevy_openxr/src/lib.rs @@ -1,5 +1,18 @@ +use actions::XrActionPlugin; +use bevy::{ + app::{PluginGroup, PluginGroupBuilder}, + render::{pipelined_rendering::PipelinedRenderingPlugin, RenderPlugin}, + utils::default, + window::{PresentMode, Window, WindowPlugin}, +}; +use bevy_xr::camera::XrCameraPlugin; +use init::XrInitPlugin; +use render::XrRenderPlugin; + +pub mod actions; +pub mod camera; pub mod error; -mod exts; +pub mod extensions; pub mod graphics; pub mod init; pub mod layer_builder; @@ -7,25 +20,13 @@ pub mod render; pub mod resources; pub mod types; -// use actions::XrActionPlugin; -use bevy::{ - app::{PluginGroup, PluginGroupBuilder}, - render::{pipelined_rendering::PipelinedRenderingPlugin, RenderPlugin}, - utils::default, - window::{PresentMode, Window, WindowPlugin}, -}; -use bevy_xr_api::camera::XrCameraPlugin; -use bevy_xr_api::session::XrSessionPlugin; -use init::OXrInitPlugin; -use render::XrRenderPlugin; - pub fn add_xr_plugins(plugins: G) -> PluginGroupBuilder { plugins .build() .disable::() .disable::() - .add_before::(XrSessionPlugin) - .add_before::(OXrInitPlugin { + .add_before::(bevy_xr::session::XrSessionPlugin) + .add_before::(XrInitPlugin { app_info: default(), exts: default(), blend_modes: default(), @@ -36,7 +37,7 @@ pub fn add_xr_plugins(plugins: G) -> PluginGroupBuilder { }) .add(XrRenderPlugin) .add(XrCameraPlugin) - // .add(XrActionPlugin) + .add(XrActionPlugin) .set(WindowPlugin { #[cfg(not(target_os = "android"))] primary_window: Some(Window { diff --git a/src/oxr/render.rs b/crates/bevy_openxr/src/render.rs similarity index 88% rename from src/oxr/render.rs rename to crates/bevy_openxr/src/render.rs index 21ee8d6..543f2d0 100644 --- a/src/oxr/render.rs +++ b/crates/bevy_openxr/src/render.rs @@ -9,28 +9,28 @@ use bevy::{ }, transform::TransformSystem, }; -use bevy_xr_api::camera::{XrCamera, XrCameraBundle, XrProjection}; +use bevy_xr::camera::{XrCamera, XrCameraBundle, XrProjection}; use openxr::{CompositionLayerFlags, ViewStateFlags}; -use crate::oxr::init::{session_started, OXrPreUpdateSet}; -use crate::oxr::layer_builder::*; -use crate::oxr::resources::*; +use crate::init::{session_started, XrPreUpdateSet}; +use crate::layer_builder::*; +use crate::resources::*; pub struct XrRenderPlugin; impl Plugin for XrRenderPlugin { fn build(&self, app: &mut App) { - app.add_plugins((ExtractResourcePlugin::::default(),)) + app.add_plugins((ExtractResourcePlugin::::default(),)) .add_systems( PreUpdate, ( - init_views.run_if(resource_added::), + init_views.run_if(resource_added::), wait_frame.run_if(session_started), locate_views.run_if(session_started), update_views.run_if(session_started), ) .chain() - .after(OXrPreUpdateSet::HandleEvents), + .after(XrPreUpdateSet::HandleEvents), ) .add_systems( PostUpdate, @@ -65,9 +65,9 @@ pub const XR_TEXTURE_INDEX: u32 = 3383858418; // TODO: have cameras initialized externally and then recieved by this function. /// This is needed to properly initialize the texture views so that bevy will set them to the correct resolution despite them being updated in the render world. pub fn init_views( - graphics_info: Res, + graphics_info: Res, mut manual_texture_views: ResMut, - swapchain_images: Res, + swapchain_images: Res, mut commands: Commands, ) { let _span = info_span!("xr_init_views"); @@ -93,22 +93,22 @@ pub fn init_views( )); views.push(default()); } - commands.insert_resource(OXrViews(views)); + commands.insert_resource(XrViews(views)); } -pub fn wait_frame(mut frame_waiter: ResMut, mut commands: Commands) { +pub fn wait_frame(mut frame_waiter: ResMut, mut commands: Commands) { let _span = info_span!("xr_wait_frame"); let state = frame_waiter.wait().expect("Failed to wait frame"); // Here we insert the predicted display time for when this frame will be displayed. // TODO: don't add predicted_display_period if pipelined rendering plugin not enabled - commands.insert_resource(OXrTime(state.predicted_display_time)); + commands.insert_resource(XrTime(state.predicted_display_time)); } pub fn locate_views( - session: Res, - stage: Res, - time: Res, - mut openxr_views: ResMut, + session: Res, + stage: Res, + time: Res, + mut openxr_views: ResMut, ) { let _span = info_span!("xr_locate_views"); let (flags, xr_views) = session @@ -125,7 +125,7 @@ pub fn locate_views( flags & ViewStateFlags::ORIENTATION_VALID == ViewStateFlags::ORIENTATION_VALID, flags & ViewStateFlags::POSITION_VALID == ViewStateFlags::POSITION_VALID, ) { - (true, true) => *openxr_views = OXrViews(xr_views), + (true, true) => *openxr_views = XrViews(xr_views), (true, false) => { for (i, view) in openxr_views.iter_mut().enumerate() { view.pose.orientation = xr_views[i].pose.orientation; @@ -142,7 +142,7 @@ pub fn locate_views( pub fn update_views( mut query: Query<(&mut Transform, &mut XrProjection, &XrCamera)>, - views: ResMut, + views: ResMut, ) { for (mut transform, mut projection, camera) in query.iter_mut() { let Some(view) = views.get(camera.0 as usize) else { @@ -162,8 +162,8 @@ pub fn update_views( } pub fn update_views_render_world( - views: Res, - root: Res, + views: Res, + root: Res, mut query: Query<(&mut ExtractedView, &XrCamera)>, ) { for (mut extracted_view, camera) in query.iter_mut() { @@ -280,10 +280,10 @@ fn calculate_projection(near_z: f32, fov: openxr::Fovf) -> Mat4 { /// # Safety /// Images inserted into texture views here should not be written to until [`wait_image`] is ran pub fn insert_texture_views( - swapchain_images: Res, - mut swapchain: ResMut, + swapchain_images: Res, + mut swapchain: ResMut, mut manual_texture_views: ResMut, - graphics_info: Res, + graphics_info: Res, ) { let _span = info_span!("xr_insert_texture_views"); let index = swapchain.acquire_image().expect("Failed to acquire image"); @@ -294,7 +294,7 @@ pub fn insert_texture_views( } } -pub fn wait_image(mut swapchain: ResMut) { +pub fn wait_image(mut swapchain: ResMut) { swapchain .wait_image(openxr::Duration::INFINITE) .expect("Failed to wait image"); @@ -303,7 +303,7 @@ pub fn wait_image(mut swapchain: ResMut) { pub fn add_texture_view( manual_texture_views: &mut ManualTextureViews, texture: &wgpu::Texture, - info: &OXrGraphicsInfo, + info: &XrGraphicsInfo, index: u32, ) -> ManualTextureViewHandle { let view = texture.create_view(&wgpu::TextureViewDescriptor { @@ -322,17 +322,17 @@ pub fn add_texture_view( handle } -pub fn begin_frame(mut frame_stream: ResMut) { +pub fn begin_frame(mut frame_stream: ResMut) { frame_stream.begin().expect("Failed to begin frame") } pub fn end_frame( - mut frame_stream: ResMut, - mut swapchain: ResMut, - stage: Res, - display_time: Res, - graphics_info: Res, - openxr_views: Res, + mut frame_stream: ResMut, + mut swapchain: ResMut, + stage: Res, + display_time: Res, + graphics_info: Res, + openxr_views: Res, ) { let _span = info_span!("xr_end_frame"); swapchain.release_image().unwrap(); diff --git a/src/oxr/resources.rs b/crates/bevy_openxr/src/resources.rs similarity index 61% rename from src/oxr/resources.rs rename to crates/bevy_openxr/src/resources.rs index 149234a..882a799 100644 --- a/src/oxr/resources.rs +++ b/crates/bevy_openxr/src/resources.rs @@ -1,36 +1,35 @@ +use std::any::TypeId; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; +use crate::error::XrError; +use crate::graphics::*; +use crate::layer_builder::CompositionLayer; +use crate::types::*; use bevy::prelude::*; use bevy::render::extract_resource::ExtractResource; +use bevy::utils::HashMap; use openxr::AnyGraphics; -use crate::oxr::error::OXrError; -use crate::oxr::graphics::*; -use crate::oxr::layer_builder::CompositionLayer; -use crate::oxr::types::*; - -/// Wrapper around the entry point to the OpenXR API #[derive(Deref, Clone)] -pub struct OXrEntry(pub openxr::Entry); +pub struct XrEntry(pub openxr::Entry); -impl OXrEntry { - /// Enumerate available extensions for this OpenXR runtime. - pub fn enumerate_extensions(&self) -> Result { +impl XrEntry { + pub fn enumerate_extensions(&self) -> Result { Ok(self.0.enumerate_extensions().map(Into::into)?) } pub fn create_instance( &self, app_info: AppInfo, - exts: OXrExtensions, + exts: XrExtensions, layers: &[&str], backend: GraphicsBackend, - ) -> Result { + ) -> Result { let available_exts = self.enumerate_extensions()?; if !backend.is_available(&available_exts) { - return Err(OXrError::UnavailableBackend(backend)); + return Err(XrError::UnavailableBackend(backend)); } let required_exts = exts | backend.required_exts(); @@ -46,7 +45,7 @@ impl OXrEntry { layers, )?; - Ok(OXrInstance(instance, backend, app_info)) + Ok(XrInstance(instance, backend, app_info)) } pub fn available_backends(&self) -> Result> { @@ -56,47 +55,39 @@ impl OXrEntry { } } -/// Wrapper around [openxr::Instance] with additional data for safety. #[derive(Resource, Deref, Clone)] -pub struct OXrInstance( +pub struct XrInstance( #[deref] pub openxr::Instance, pub(crate) GraphicsBackend, pub(crate) AppInfo, ); -impl OXrInstance { - pub fn into_inner(self) -> openxr::Instance { - self.0 - } - - /// Initialize graphics. This is used to create [WgpuGraphics] for the bevy app and to get the [SessionCreateInfo] to make an XR session. +impl XrInstance { pub fn init_graphics( &self, system_id: openxr::SystemId, - ) -> Result<(WgpuGraphics, SessionCreateInfo)> { + ) -> Result<(WgpuGraphics, XrSessionGraphicsInfo)> { graphics_match!( self.1; _ => { let (graphics, session_info) = Api::init_graphics(&self.2, &self, system_id)?; - Ok((graphics, SessionCreateInfo(Api::wrap(session_info)))) + Ok((graphics, XrSessionGraphicsInfo(Api::wrap(session_info)))) } ) } - /// Creates an [OXrSession] - /// /// # Safety /// /// `info` must contain valid handles for the graphics api pub unsafe fn create_session( &self, system_id: openxr::SystemId, - info: SessionCreateInfo, - ) -> Result<(OXrSession, OXrFrameWaiter, OXrFrameStream)> { + info: XrSessionGraphicsInfo, + ) -> Result<(XrSession, XrFrameWaiter, XrFrameStream)> { if !info.0.using_graphics_of_val(&self.1) { - return Err(OXrError::GraphicsBackendMismatch { - item: std::any::type_name::(), + return Err(XrError::GraphicsBackendMismatch { + item: std::any::type_name::(), backend: info.0.graphics_name(), expected_backend: self.1.graphics_name(), }); @@ -105,61 +96,59 @@ impl OXrInstance { info.0; info => { let (session, frame_waiter, frame_stream) = self.0.create_session::(system_id, &info)?; - Ok((session.into(), OXrFrameWaiter(frame_waiter), OXrFrameStream(Api::wrap(frame_stream)))) + Ok((session.into(), XrFrameWaiter(frame_waiter), XrFrameStream(Api::wrap(frame_stream)))) } ) } } -/// Graphics agnostic wrapper around [openxr::Session] +#[derive(Clone)] +pub struct XrSessionGraphicsInfo(pub(crate) GraphicsWrap); + +impl GraphicsType for XrSessionGraphicsInfo { + type Inner = G::SessionCreateInfo; +} + #[derive(Resource, Deref, Clone)] -pub struct OXrSession( - #[deref] pub openxr::Session, - pub GraphicsWrap, +pub struct XrSession( + #[deref] pub(crate) openxr::Session, + pub(crate) GraphicsWrap, ); -impl GraphicsType for OXrSession { +impl GraphicsType for XrSession { type Inner = openxr::Session; } -impl From> for OXrSession { - fn from(session: openxr::Session) -> Self { - Self::new(session) +impl From> for XrSession { + fn from(value: openxr::Session) -> Self { + Self(value.clone().into_any_graphics(), G::wrap(value)) } } -impl OXrSession { - pub fn new(session: openxr::Session) -> Self { - Self(session.clone().into_any_graphics(), G::wrap(session)) - } - - /// Enumerate all available swapchain formats. +impl XrSession { pub fn enumerate_swapchain_formats(&self) -> Result> { graphics_match!( &self.1; - session => Ok(session.enumerate_swapchain_formats()?.into_iter().filter_map(Api::into_wgpu_format).collect()) + session => Ok(session.enumerate_swapchain_formats()?.into_iter().filter_map(Api::to_wgpu_format).collect()) ) } - /// Creates an [OXrSwapchain]. - pub fn create_swapchain(&self, info: SwapchainCreateInfo) -> Result { - Ok(OXrSwapchain(graphics_match!( + pub fn create_swapchain(&self, info: SwapchainCreateInfo) -> Result { + Ok(XrSwapchain(graphics_match!( &self.1; - session => session.create_swapchain(&info.try_into()?)? => OXrSwapchain + session => session.create_swapchain(&info.try_into()?)? => XrSwapchain ))) } } -/// Graphics agnostic wrapper around [openxr::FrameStream] #[derive(Resource)] -pub struct OXrFrameStream(pub GraphicsWrap); +pub struct XrFrameStream(pub(crate) GraphicsWrap); -impl GraphicsType for OXrFrameStream { +impl GraphicsType for XrFrameStream { type Inner = openxr::FrameStream; } -impl OXrFrameStream { - /// Indicate that graphics device work is beginning. +impl XrFrameStream { pub fn begin(&mut self) -> openxr::Result<()> { graphics_match!( &mut self.0; @@ -167,10 +156,6 @@ impl OXrFrameStream { ) } - /// Indicate that all graphics work for the frame has been submitted - /// - /// `layers` is an array of references to any type of composition layer, - /// e.g. [`CompositionLayerProjection`](crate::oxr::layer_builder::CompositionLayerProjection) pub fn end( &mut self, display_time: openxr::Time, @@ -202,20 +187,17 @@ impl OXrFrameStream { } } -/// Handle for waiting to render a frame. Check [`FrameWaiter`](openxr::FrameWaiter) for available methods. #[derive(Resource, Deref, DerefMut)] -pub struct OXrFrameWaiter(pub openxr::FrameWaiter); +pub struct XrFrameWaiter(pub openxr::FrameWaiter); -/// Graphics agnostic wrapper around [openxr::Swapchain] #[derive(Resource)] -pub struct OXrSwapchain(pub GraphicsWrap); +pub struct XrSwapchain(pub(crate) GraphicsWrap); -impl GraphicsType for OXrSwapchain { +impl GraphicsType for XrSwapchain { type Inner = openxr::Swapchain; } -impl OXrSwapchain { - /// Determine the index of the next image to render to in the swapchain image array +impl XrSwapchain { pub fn acquire_image(&mut self) -> Result { graphics_match!( &mut self.0; @@ -223,7 +205,6 @@ impl OXrSwapchain { ) } - /// Wait for the compositor to finish reading from the oldest unwaited acquired image pub fn wait_image(&mut self, timeout: openxr::Duration) -> Result<()> { graphics_match!( &mut self.0; @@ -231,7 +212,6 @@ impl OXrSwapchain { ) } - /// Release the oldest acquired image pub fn release_image(&mut self) -> Result<()> { graphics_match!( &mut self.0; @@ -239,13 +219,12 @@ impl OXrSwapchain { ) } - /// Enumerates swapchain images and converts them to wgpu [`Texture`](wgpu::Texture)s. pub fn enumerate_images( &self, device: &wgpu::Device, format: wgpu::TextureFormat, resolution: UVec2, - ) -> Result { + ) -> Result { graphics_match!( &self.0; swap => { @@ -255,39 +234,43 @@ impl OXrSwapchain { images.push(Api::to_wgpu_img(image, device, format, resolution)?); } } - Ok(OXrSwapchainImages(images.into())) + Ok(XrSwapchainImages(images.into())) } ) } } -/// Stores the generated swapchain images. -#[derive(Debug, Deref, Resource, Clone)] -pub struct OXrSwapchainImages(pub Arc>); - -/// Thread safe wrapper around [openxr::Space] representing the stage. #[derive(Deref, Clone, Resource)] -pub struct OXrStage(pub Arc); +pub struct XrStage(pub Arc); -/// Stores the latest generated [OXrViews] -#[derive(Clone, Resource, ExtractResource, Deref, DerefMut)] -pub struct OXrViews(pub Vec); +#[derive(Debug, Deref, Resource, Clone)] +pub struct XrSwapchainImages(pub Arc>); + +#[derive(Copy, Clone, Eq, PartialEq, Deref, DerefMut, Resource, ExtractResource)] +pub struct XrTime(pub openxr::Time); + +#[derive(Copy, Clone, Eq, PartialEq, Resource)] +pub struct XrSwapchainInfo { + pub format: wgpu::TextureFormat, + pub resolution: UVec2, +} -/// Wrapper around [openxr::SystemId] to allow it to be stored as a resource. #[derive(Debug, Copy, Clone, Deref, Default, Eq, PartialEq, Ord, PartialOrd, Hash, Resource)] -pub struct OXrSystemId(pub openxr::SystemId); +pub struct XrSystemId(pub openxr::SystemId); -/// Resource storing graphics info for the currently running session. #[derive(Clone, Copy, Resource)] -pub struct OXrGraphicsInfo { +pub struct XrGraphicsInfo { pub blend_mode: EnvironmentBlendMode, pub resolution: UVec2, pub format: wgpu::TextureFormat, } +#[derive(Clone, Resource, ExtractResource, Deref, DerefMut)] +pub struct XrViews(pub Vec); + #[derive(Clone)] /// This is used to store information from startup that is needed to create the session after the instance has been created. -pub struct SessionConfigInfo { +pub struct XrSessionCreateInfo { /// List of blend modes the openxr session can use. If [None], pick the first available blend mode. pub blend_modes: Option>, /// List of formats the openxr session can use. If [None], pick the first available format @@ -295,13 +278,13 @@ pub struct SessionConfigInfo { /// List of resolutions that the openxr swapchain can use. If [None] pick the first available resolution. pub resolutions: Option>, /// Graphics info used to create a session. - pub graphics_info: SessionCreateInfo, + pub graphics_info: XrSessionGraphicsInfo, } #[derive(Resource, Clone, Default)] -pub struct OXrSessionStarted(Arc); +pub struct XrSessionStarted(Arc); -impl OXrSessionStarted { +impl XrSessionStarted { pub fn set(&self, val: bool) { self.0.store(val, Ordering::SeqCst); } @@ -311,14 +294,36 @@ impl OXrSessionStarted { } } -/// The calculated display time for the app. Passed through the pipeline. -#[derive(Copy, Clone, Eq, PartialEq, Deref, DerefMut, Resource, ExtractResource)] -pub struct OXrTime(pub openxr::Time); - -/// The root transform's global position for late latching in the render world. #[derive(ExtractResource, Resource, Clone, Copy, Default)] -pub struct OXrRootTransform(pub GlobalTransform); +pub struct XrRootTransform(pub GlobalTransform); #[derive(ExtractResource, Resource, Clone, Copy, Default, Deref, DerefMut, PartialEq)] /// This is inserted into the world to signify if the session should be cleaned up. -pub struct OXrCleanupSession(pub bool); +pub struct XrCleanupSession(pub bool); + +#[derive(Resource, Clone, Deref)] +pub struct XrActionSet(#[deref] pub openxr::ActionSet, bool); + +impl XrActionSet { + pub fn new(action_set: openxr::ActionSet) -> Self { + Self(action_set, false) + } + + pub fn attach(&mut self) { + self.1 = true; + } + + pub fn is_attached(&self) -> bool { + self.1 + } +} + +#[derive(Clone)] +pub enum TypedAction { + Bool(openxr::Action), + Float(openxr::Action), + Vector(openxr::Action), +} + +#[derive(Resource, Clone, Deref)] +pub struct XrActions(pub HashMap); \ No newline at end of file diff --git a/src/oxr/types.rs b/crates/bevy_openxr/src/types.rs similarity index 54% rename from src/oxr/types.rs rename to crates/bevy_openxr/src/types.rs index 31606c0..305e0eb 100644 --- a/src/oxr/types.rs +++ b/crates/bevy_openxr/src/types.rs @@ -1,15 +1,15 @@ use std::borrow::Cow; -use super::error::OXrError; -use super::graphics::{GraphicsExt, GraphicsType, GraphicsWrap}; +pub use crate::error::XrError; +pub use crate::extensions::XrExtensions; +use crate::graphics::GraphicsExt; -pub use crate::oxr::exts::OXrExtensions; +pub use openxr::{ + ApiLayerProperties, EnvironmentBlendMode, SwapchainCreateFlags, SwapchainUsageFlags, +}; -pub use openxr::{EnvironmentBlendMode, SwapchainCreateFlags, SwapchainUsageFlags}; +pub type Result = std::result::Result; -pub type Result = std::result::Result; - -/// A container for all required graphics objects needed for a bevy app. pub struct WgpuGraphics( pub wgpu::Device, pub wgpu::Queue, @@ -18,13 +18,11 @@ pub struct WgpuGraphics( pub wgpu::Instance, ); -/// A version number that can be stored inside of a u32 #[derive(Clone, Copy, Debug, Default, PartialEq)] pub struct Version(pub u8, pub u8, pub u16); impl Version { - /// Bevy's version number - pub const BEVY: Self = Self(0, 13, 0); + pub const BEVY: Self = Self(0, 12, 1); pub const fn to_u32(self) -> u32 { let major = (self.0 as u32) << 24; @@ -33,29 +31,21 @@ impl Version { } } -/// Info needed about an app for OpenXR #[derive(Clone, Debug, PartialEq)] pub struct AppInfo { pub name: Cow<'static, str>, pub version: Version, } -impl AppInfo { - /// The default app info for a generic bevy app - pub const BEVY: Self = Self { - name: Cow::Borrowed("Bevy"), - version: Version::BEVY, - }; -} - impl Default for AppInfo { fn default() -> Self { - Self::BEVY + Self { + name: "Bevy".into(), + version: Version::BEVY, + } } } -/// Info needed to create a swapchain. -/// This is an API agnostic version of [openxr::SwapchainCreateInfo] used for some of this library's functions #[derive(Debug, Copy, Clone)] pub struct SwapchainCreateInfo { pub create_flags: SwapchainCreateFlags, @@ -70,14 +60,14 @@ pub struct SwapchainCreateInfo { } impl TryFrom for openxr::SwapchainCreateInfo { - type Error = OXrError; + type Error = XrError; fn try_from(value: SwapchainCreateInfo) -> Result { Ok(openxr::SwapchainCreateInfo { create_flags: value.create_flags, usage_flags: value.usage_flags, format: G::from_wgpu_format(value.format) - .ok_or(OXrError::UnsupportedTextureFormat(value.format))?, + .ok_or(XrError::UnsupportedTextureFormat(value.format))?, sample_count: value.sample_count, width: value.width, height: value.height, @@ -87,12 +77,3 @@ impl TryFrom for openxr::SwapchainCreateInf }) } } - -/// Info needed to create a session. Mostly contains graphics info. -/// This is an API agnostic version of [openxr::Graphics::SessionCreateInfo] used for some of this library's functions -#[derive(Clone)] -pub struct SessionCreateInfo(pub GraphicsWrap); - -impl GraphicsType for SessionCreateInfo { - type Inner = G::SessionCreateInfo; -} diff --git a/bevy_xr_api/Cargo.toml b/crates/bevy_xr/Cargo.toml similarity index 90% rename from bevy_xr_api/Cargo.toml rename to crates/bevy_xr/Cargo.toml index ef390cd..d15550c 100644 --- a/bevy_xr_api/Cargo.toml +++ b/crates/bevy_xr/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bevy_xr_api" +name = "bevy_xr" version = "0.1.0" edition = "2021" diff --git a/bevy_xr_api/macros/Cargo.toml b/crates/bevy_xr/macros/Cargo.toml similarity index 100% rename from bevy_xr_api/macros/Cargo.toml rename to crates/bevy_xr/macros/Cargo.toml diff --git a/bevy_xr_api/macros/src/lib.rs b/crates/bevy_xr/macros/src/lib.rs similarity index 100% rename from bevy_xr_api/macros/src/lib.rs rename to crates/bevy_xr/macros/src/lib.rs diff --git a/bevy_xr_api/src/actions.rs b/crates/bevy_xr/src/actions.rs similarity index 100% rename from bevy_xr_api/src/actions.rs rename to crates/bevy_xr/src/actions.rs diff --git a/bevy_xr_api/src/camera.rs b/crates/bevy_xr/src/camera.rs similarity index 100% rename from bevy_xr_api/src/camera.rs rename to crates/bevy_xr/src/camera.rs diff --git a/bevy_xr_api/src/lib.rs b/crates/bevy_xr/src/lib.rs similarity index 100% rename from bevy_xr_api/src/lib.rs rename to crates/bevy_xr/src/lib.rs diff --git a/bevy_xr_api/src/session.rs b/crates/bevy_xr/src/session.rs similarity index 100% rename from bevy_xr_api/src/session.rs rename to crates/bevy_xr/src/session.rs diff --git a/bevy_xr_api/src/types.rs b/crates/bevy_xr/src/types.rs similarity index 100% rename from bevy_xr_api/src/types.rs rename to crates/bevy_xr/src/types.rs diff --git a/examples/3d_scene.rs b/examples/3d_scene.rs index 728f3de..560f7c2 100644 --- a/examples/3d_scene.rs +++ b/examples/3d_scene.rs @@ -1,11 +1,10 @@ //! A simple 3D scene with light shining over a cube sitting on a plane. use bevy::prelude::*; -use bevy_xr::add_xr_plugins; fn main() { App::new() - .add_plugins(add_xr_plugins(DefaultPlugins)) + .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .run(); } @@ -44,4 +43,4 @@ fn setup( transform: Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y), ..default() }); -} +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index ca2aafc..646e102 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,2 @@ -#[cfg(not(target_family = "wasm"))] -pub mod oxr; -#[cfg(target_family = "wasm")] -pub mod webxr; - -#[cfg(not(target_family = "wasm"))] -pub use oxr::add_xr_plugins; +pub use bevy_openxr; +pub use bevy_xr;