feat: update to bevy 0.17 and use individual bevy crates

Signed-off-by: Schmarni <marnistromer@gmail.com>
This commit is contained in:
Schmarni
2025-10-19 16:13:59 +02:00
parent 9fd0c79759
commit eb3ec03d91
45 changed files with 1581 additions and 986 deletions

1650
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -10,21 +10,30 @@ resolver = "2"
members = ["crates/*", "crates/bevy_openxr/examples/android"] members = ["crates/*", "crates/bevy_openxr/examples/android"]
[workspace.dependencies] [workspace.dependencies]
bevy = { version = "0.16.0", default-features = false, features = [ bevy = "0.17"
"bevy_render", bevy_ecs = { version = "0.17.0", default-features = false }
"bevy_core_pipeline", bevy_math = { version = "0.17.0", default-features = false }
"bevy_winit", bevy_render = { version = "0.17.0", default-features = false }
"bevy_pbr", bevy_core_pipeline = { version = "0.17.0", default-features = false }
"bevy_window", bevy_window = { version = "0.17.0", default-features = false }
"x11", bevy_winit = { version = "0.17.0", default-features = false }
] } bevy_pbr = { version = "0.17.0", default-features = false }
bevy_app = { version = "0.17.0", default-features = false }
bevy_reflect = { version = "0.17.0", default-features = false }
bevy_log = { version = "0.17.0", default-features = false }
bevy_gizmos = { version = "0.17.0", default-features = false }
bevy_camera = { version = "0.17.0", default-features = false }
bevy_color = { version = "0.17.0", default-features = false }
bevy_transform = { version = "0.17.0", default-features = false }
bevy_derive = { version = "0.17.0", default-features = false }
bevy_platform = { version = "0.17.0", default-features = false }
bevy_mod_xr = { path = "crates/bevy_xr", version = "0.3.0" } bevy_mod_xr = { path = "crates/bevy_xr", version = "0.3.0" }
bevy_mod_openxr = { path = "crates/bevy_openxr", version = "0.3.0" } bevy_mod_openxr = { path = "crates/bevy_openxr", version = "0.3.0" }
bevy_xr_utils = { path = "crates/bevy_xr_utils", version = "0.3.0" } bevy_xr_utils = { path = "crates/bevy_xr_utils", version = "0.3.0" }
openxr = "0.19.0" openxr = "0.19.0"
thiserror = "2.0.3" thiserror = "2.0.3"
wgpu = "24.0.1" wgpu = "26"
wgpu-hal = "24.0.2" wgpu-hal = "26"
# Enable a small amount of optimization in the dev profile. # Enable a small amount of optimization in the dev profile.
[profile.dev] [profile.dev]

View File

@@ -8,13 +8,15 @@ license.workspace = true
keywords = ["gamedev", "bevy", "Xr", "Vr", "OpenXR"] keywords = ["gamedev", "bevy", "Xr", "Vr", "OpenXR"]
[features] [features]
default = ["vulkan", "d3d12", "passthrough"] default = ["vulkan"]
vulkan = ["dep:ash", "dep:android_system_properties"] vulkan = ["dep:ash", "dep:android_system_properties"]
d3d12 = ["wgpu/dx12", "wgpu-hal/dx12", "dep:winapi"] d3d12 = ["wgpu/dx12", "wgpu-hal/dx12", "dep:winapi"]
passthrough = [] passthrough = []
reflect = ["dep:bevy_reflect"]
window_support = ["dep:bevy_winit"]
[dev-dependencies] [dev-dependencies]
bevy = { workspace = true, default-features = true } bevy.workspace = true
[target.'cfg(target_os = "android")'.dependencies] [target.'cfg(target_os = "android")'.dependencies]
ndk-context = "0.1" ndk-context = "0.1"
@@ -23,7 +25,18 @@ android_system_properties = { version = "0.1.5", optional = true }
# bevy can't be placed behind target or proc macros won't work properly # bevy can't be placed behind target or proc macros won't work properly
[dependencies] [dependencies]
bevy.workspace = true bevy_ecs.workspace = true
bevy_math.workspace = true
bevy_render.workspace = true
bevy_app.workspace = true
bevy_reflect = { workspace = true, optional = true }
bevy_log.workspace = true
bevy_transform.workspace = true
bevy_camera.workspace = true
bevy_derive.workspace = true
bevy_platform.workspace = true
bevy_winit = { workspace = true, optional = true }
bevy_window = { workspace = true, optional = true }
# all other dependencies are placed under this since on wasm, this crate is completely empty # all other dependencies are placed under this since on wasm, this crate is completely empty
[target.'cfg(not(target_family = "wasm"))'.dependencies] [target.'cfg(not(target_family = "wasm"))'.dependencies]

View File

@@ -10,14 +10,14 @@ publish = false
bevy_mod_openxr.workspace = true bevy_mod_openxr.workspace = true
bevy_xr_utils.workspace = true bevy_xr_utils.workspace = true
bevy_mod_xr.workspace = true bevy_mod_xr.workspace = true
bevy = { workspace = true, default-features = false, features = [ # bevy = { workspace = true, default-features = false, features = [
# Bevy 0.15 made GameActivity the default which breaks Quest builds # # Bevy 0.15 made GameActivity the default which breaks Quest builds
# To use NativeActivity instead of GameActivity all of the features have to be listed manually # # To use NativeActivity instead of GameActivity all of the features have to be listed manually
"android-native-activity", # "android-native-activity",
"bevy_window", # "bevy_window",
"multi_threaded", # "multi_threaded",
"tonemapping_luts", # "tonemapping_luts",
] } # ] }
[build-dependencies] [build-dependencies]
reqwest = { version = "0.12", features = ["blocking"] } reqwest = { version = "0.12", features = ["blocking"] }

View File

@@ -2,7 +2,7 @@
use bevy::prelude::*; use bevy::prelude::*;
use bevy_mod_openxr::{ use bevy_mod_openxr::{
add_xr_plugins, features::overlay::OxrOverlaySessionEvent, init::OxrInitPlugin, add_xr_plugins, features::overlay::OxrOverlaySessionMessage, init::OxrInitPlugin,
resources::OxrSessionConfig, types::OxrExtensions, resources::OxrSessionConfig, types::OxrExtensions,
}; };
use openxr::EnvironmentBlendMode; use openxr::EnvironmentBlendMode;
@@ -36,20 +36,20 @@ fn main() {
.run(); .run();
} }
fn print_main_session_changes(mut events: EventReader<OxrOverlaySessionEvent>) { fn print_main_session_changes(mut events: MessageReader<OxrOverlaySessionMessage>) {
for event in events.read() { for event in events.read() {
let OxrOverlaySessionEvent::MainSessionVisibilityChanged { visible, flags: _ } = event; let OxrOverlaySessionMessage::MainSessionVisibilityChanged { visible, flags: _ } = event;
info!("main session visible: {visible}"); info!("main session visible: {visible}");
} }
} }
fn handle_input( fn handle_input(
keys: Res<ButtonInput<KeyCode>>, keys: Res<ButtonInput<KeyCode>>,
mut end: EventWriter<bevy_mod_xr::session::XrEndSessionEvent>, mut end: MessageWriter<bevy_mod_xr::session::XrEndSessionMessage>,
mut destroy: EventWriter<bevy_mod_xr::session::XrDestroySessionEvent>, mut destroy: MessageWriter<bevy_mod_xr::session::XrDestroySessionMessage>,
mut begin: EventWriter<bevy_mod_xr::session::XrBeginSessionEvent>, mut begin: MessageWriter<bevy_mod_xr::session::XrBeginSessionMessage>,
mut create: EventWriter<bevy_mod_xr::session::XrCreateSessionEvent>, mut create: MessageWriter<bevy_mod_xr::session::XrCreateSessionMessage>,
mut request_exit: EventWriter<bevy_mod_xr::session::XrRequestExitEvent>, mut request_exit: MessageWriter<bevy_mod_xr::session::XrRequestExitMessage>,
) { ) {
if keys.just_pressed(KeyCode::KeyE) { if keys.just_pressed(KeyCode::KeyE) {
info!("sending end"); info!("sending end");

View File

@@ -35,7 +35,7 @@ fn main() -> AppExit {
app.run() app.run()
} }
fn attach_set(actions: Res<ControllerActions>, mut attach: EventWriter<OxrAttachActionSet>) { fn attach_set(actions: Res<ControllerActions>, mut attach: MessageWriter<OxrAttachActionSet>) {
attach.write(OxrAttachActionSet(actions.set.clone())); attach.write(OxrAttachActionSet(actions.set.clone()));
} }
@@ -45,7 +45,7 @@ struct ControllerActions {
left: openxr::Action<Posef>, left: openxr::Action<Posef>,
right: openxr::Action<Posef>, right: openxr::Action<Posef>,
} }
fn sync_actions(actions: Res<ControllerActions>, mut sync: EventWriter<OxrSyncActionSet>) { fn sync_actions(actions: Res<ControllerActions>, mut sync: MessageWriter<OxrSyncActionSet>) {
sync.write(OxrSyncActionSet(actions.set.clone())); sync.write(OxrSyncActionSet(actions.set.clone()));
} }
/// set up a simple 3D scene /// set up a simple 3D scene
@@ -81,7 +81,7 @@ fn setup(
} }
fn suggest_action_bindings( fn suggest_action_bindings(
actions: Res<ControllerActions>, actions: Res<ControllerActions>,
mut bindings: EventWriter<OxrSuggestActionBinding>, mut bindings: MessageWriter<OxrSuggestActionBinding>,
) { ) {
bindings.write(OxrSuggestActionBinding { bindings.write(OxrSuggestActionBinding {
action: actions.left.as_raw(), action: actions.left.as_raw(),

View File

@@ -16,11 +16,11 @@ fn main() -> AppExit {
fn handle_input( fn handle_input(
keys: Res<ButtonInput<KeyCode>>, keys: Res<ButtonInput<KeyCode>>,
mut end: EventWriter<bevy_mod_xr::session::XrEndSessionEvent>, mut end: MessageWriter<bevy_mod_xr::session::XrEndSessionMessage>,
mut destroy: EventWriter<bevy_mod_xr::session::XrDestroySessionEvent>, mut destroy: MessageWriter<bevy_mod_xr::session::XrDestroySessionMessage>,
mut begin: EventWriter<bevy_mod_xr::session::XrBeginSessionEvent>, mut begin: MessageWriter<bevy_mod_xr::session::XrBeginSessionMessage>,
mut create: EventWriter<bevy_mod_xr::session::XrCreateSessionEvent>, mut create: MessageWriter<bevy_mod_xr::session::XrCreateSessionMessage>,
mut request_exit: EventWriter<bevy_mod_xr::session::XrRequestExitEvent>, mut request_exit: MessageWriter<bevy_mod_xr::session::XrRequestExitMessage>,
state: Res<XrState>, state: Res<XrState>,
) { ) {
if keys.just_pressed(KeyCode::KeyE) { if keys.just_pressed(KeyCode::KeyE) {

View File

@@ -1,11 +1,15 @@
use std::borrow::Cow; use std::borrow::Cow;
use std::ptr; use std::ptr;
use bevy::ecs::schedule::ScheduleLabel; use bevy_app::{App, Plugin, Update};
use bevy::ecs::system::RunSystemOnce; use bevy_ecs::message::{Message, MessageReader};
use bevy::platform::collections::HashMap; use bevy_ecs::schedule::common_conditions::on_message;
use bevy::prelude::*; use bevy_ecs::schedule::{IntoScheduleConfigs as _, Schedule, ScheduleLabel};
use bevy_mod_xr::session::XrSessionCreatedEvent; use bevy_ecs::system::{Res, RunSystemOnce};
use bevy_ecs::world::World;
use bevy_log::error;
use bevy_mod_xr::session::XrSessionCreatedMessage;
use bevy_platform::collections::HashMap;
use openxr::sys::ActionSuggestedBinding; use openxr::sys::ActionSuggestedBinding;
use crate::resources::OxrInstance; use crate::resources::OxrInstance;
@@ -13,10 +17,10 @@ use crate::resources::OxrInstance;
impl Plugin for OxrActionBindingPlugin { impl Plugin for OxrActionBindingPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_schedule(Schedule::new(OxrSendActionBindings)); app.add_schedule(Schedule::new(OxrSendActionBindings));
app.add_event::<OxrSuggestActionBinding>(); app.add_message::<OxrSuggestActionBinding>();
app.add_systems( app.add_systems(
Update, Update,
run_action_binding_sugestion.run_if(on_event::<XrSessionCreatedEvent>), run_action_binding_sugestion.run_if(on_message::<XrSessionCreatedMessage>),
); );
} }
} }
@@ -28,7 +32,7 @@ pub(crate) fn run_action_binding_sugestion(world: &mut World) {
_ = world.run_system_once(bind_actions); _ = world.run_system_once(bind_actions);
} }
fn bind_actions(instance: Res<OxrInstance>, mut actions: EventReader<OxrSuggestActionBinding>) { fn bind_actions(instance: Res<OxrInstance>, mut actions: MessageReader<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(
@@ -88,7 +92,7 @@ fn bind_actions(instance: Res<OxrInstance>, mut actions: EventReader<OxrSuggestA
} }
} }
#[derive(Event, Clone)] #[derive(Message, Clone)]
/// Only Send this for Actions that were not attached yet! /// Only Send this for Actions that were not attached yet!
pub struct OxrSuggestActionBinding { pub struct OxrSuggestActionBinding {
pub action: openxr::sys::Action, pub action: openxr::sys::Action,
@@ -97,6 +101,5 @@ pub struct OxrSuggestActionBinding {
} }
pub struct OxrActionBindingPlugin; pub struct OxrActionBindingPlugin;
// Maybe use a SystemSet in an XrStartup Schedule?
#[derive(ScheduleLabel, Hash, Debug, Clone, Copy, PartialEq, Eq)] #[derive(ScheduleLabel, Hash, Debug, Clone, Copy, PartialEq, Eq)]
pub struct OxrSendActionBindings; pub struct OxrSendActionBindings;

View File

@@ -1,20 +1,22 @@
use crate::{action_binding::run_action_binding_sugestion, session::OxrSession}; use crate::{action_binding::run_action_binding_sugestion, session::OxrSession};
use bevy::prelude::*; use bevy_app::{App, Plugin, PostUpdate};
use bevy_mod_xr::session::XrSessionCreatedEvent; use bevy_ecs::{message::{Message, MessageReader}, schedule::{IntoScheduleConfigs as _, common_conditions::on_message}, system::Res};
use bevy_log::{error, info};
use bevy_mod_xr::session::XrSessionCreatedMessage;
impl Plugin for OxrActionAttachingPlugin { impl Plugin for OxrActionAttachingPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<OxrAttachActionSet>(); app.add_message::<OxrAttachActionSet>();
app.add_systems( app.add_systems(
PostUpdate, PostUpdate,
attach_sets attach_sets
.run_if(on_event::<XrSessionCreatedEvent>) .run_if(on_message::<XrSessionCreatedMessage>)
.after(run_action_binding_sugestion), .after(run_action_binding_sugestion),
); );
} }
} }
fn attach_sets(session: Res<OxrSession>, mut events: EventReader<OxrAttachActionSet>) { fn attach_sets(session: Res<OxrSession>, mut events: MessageReader<OxrAttachActionSet>) {
let sets = events.read().map(|v| &v.0).collect::<Vec<_>>(); let sets = events.read().map(|v| &v.0).collect::<Vec<_>>();
if sets.is_empty() { if sets.is_empty() {
return; return;
@@ -36,7 +38,7 @@ fn attach_sets(session: Res<OxrSession>, mut events: EventReader<OxrAttachAction
}; };
} }
#[derive(Event, Clone)] #[derive(Message, Clone)]
/// Send this event for every ActionSet you want to attach to the [`OxrSession`] once the Session Status changed to Ready. all requests will /// Send this event for every ActionSet you want to attach to the [`OxrSession`] once the Session Status changed to Ready. all requests will
/// be applied in [`PostUpdate`] /// be applied in [`PostUpdate`]
pub struct OxrAttachActionSet(pub openxr::ActionSet); pub struct OxrAttachActionSet(pub openxr::ActionSet);

View File

@@ -1,12 +1,15 @@
use bevy_app::{App, Plugin, PreUpdate};
use bevy_ecs::{message::{Message, MessageReader}, schedule::{IntoScheduleConfigs as _, SystemSet}, system::Res};
use bevy_log::warn;
use crate::{openxr_session_running, session::OxrSession}; use crate::{openxr_session_running, session::OxrSession};
use bevy::prelude::*;
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone, Copy)] #[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub struct OxrActionSetSyncSet; pub struct OxrActionSetSyncSet;
impl Plugin for OxrActionSyncingPlugin { impl Plugin for OxrActionSyncingPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<OxrSyncActionSet>(); app.add_message::<OxrSyncActionSet>();
app.add_systems( app.add_systems(
PreUpdate, PreUpdate,
sync_sets sync_sets
@@ -16,8 +19,8 @@ impl Plugin for OxrActionSyncingPlugin {
} }
} }
fn sync_sets(session: Res<OxrSession>, mut events: EventReader<OxrSyncActionSet>) { fn sync_sets(session: Res<OxrSession>, mut messages: MessageReader<OxrSyncActionSet>) {
let sets = events let sets = messages
.read() .read()
.map(|v| &v.0) .map(|v| &v.0)
.map(openxr::ActiveActionSet::new) .map(openxr::ActiveActionSet::new)
@@ -31,7 +34,7 @@ fn sync_sets(session: Res<OxrSession>, mut events: EventReader<OxrSyncActionSet>
} }
} }
#[derive(Event, Clone)] #[derive(Message, Clone)]
/// Send this event for every ActionSet you want to attach to the [`OxrSession`] once the Session Status changed to Ready. all requests will /// Send this event for every ActionSet you want to attach to the [`OxrSession`] once the Session Status changed to Ready. all requests will
pub struct OxrSyncActionSet(pub openxr::ActionSet); pub struct OxrSyncActionSet(pub openxr::ActionSet);

View File

@@ -1,4 +1,5 @@
use bevy::{ecs::resource::Resource, render::extract_resource::ExtractResource}; use bevy_ecs::resource::Resource;
use bevy_render::extract_resource::ExtractResource;
use openxr::EnvironmentBlendMode; use openxr::EnvironmentBlendMode;
#[derive(Resource, ExtractResource, Clone)] #[derive(Resource, ExtractResource, Clone)]

View File

@@ -1,4 +1,5 @@
use bevy::prelude::{Deref, DerefMut, Resource}; use bevy_derive::{Deref, DerefMut};
use bevy_ecs::resource::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

@@ -1,7 +1,8 @@
use bevy::prelude::*; use bevy_log::error;
use bevy::render::Render; use bevy_log::info;
use bevy::render::RenderApp; use bevy_render::Render;
use bevy::render::RenderSet; use bevy_render::RenderApp;
use bevy_render::RenderSystems;
use openxr::sys::SystemPassthroughProperties2FB; use openxr::sys::SystemPassthroughProperties2FB;
use openxr::PassthroughCapabilityFlagsFB; use openxr::PassthroughCapabilityFlagsFB;
@@ -105,7 +106,7 @@ pub fn supports_passthrough(instance: &OxrInstance, system: OxrSystemId) -> OxrR
system.0, system.0,
p.as_mut_ptr(), p.as_mut_ptr(),
))?; ))?;
bevy::log::info!( info!(
"From supports_passthrough: Passthrough capabilities: {:?}", "From supports_passthrough: Passthrough capabilities: {:?}",
properties.capabilities properties.capabilities
); );

View File

@@ -1,4 +1,12 @@
use bevy::prelude::*; use bevy_app::{App, Plugin, PreUpdate, Startup};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::component::Component;
use bevy_ecs::entity::Entity;
use bevy_ecs::query::{Or, With};
use bevy_ecs::schedule::IntoScheduleConfigs as _;
use bevy_ecs::system::{Commands, Query, Res};
use bevy_ecs::world::World;
use bevy_log::{debug, error, warn};
use bevy_mod_xr::hands::{ use bevy_mod_xr::hands::{
spawn_hand_bones, HandBone, HandSide, SpawnHandTracker, SpawnHandTrackerCommandExecutor, spawn_hand_bones, HandBone, HandSide, SpawnHandTracker, SpawnHandTrackerCommandExecutor,
XrHandBoneRadius, XrHandBoneRadius,
@@ -9,6 +17,7 @@ use bevy_mod_xr::spaces::{
XrPrimaryReferenceSpace, XrReferenceSpace, XrSpaceLocationFlags, XrSpaceSyncSet, XrPrimaryReferenceSpace, XrReferenceSpace, XrSpaceLocationFlags, XrSpaceSyncSet,
XrSpaceVelocityFlags, XrVelocity, XrSpaceVelocityFlags, XrVelocity,
}; };
use bevy_transform::components::Transform;
use openxr::{SpaceLocationFlags, SpaceVelocityFlags}; use openxr::{SpaceLocationFlags, SpaceVelocityFlags};
use crate::helper_traits::ToVec3; use crate::helper_traits::ToVec3;

View File

@@ -1,6 +1,7 @@
use std::{mem, ptr}; use std::{mem, ptr};
use bevy::prelude::*; use bevy_app::{App, First, Plugin};
use bevy_ecs::{message::{Message, MessageWriter}, resource::Resource, schedule::IntoScheduleConfigs as _, system::{NonSendMut, Res}};
use openxr::{sys, Event}; use openxr::{sys, Event};
use crate::{ use crate::{
@@ -14,8 +15,8 @@ use crate::{
pub struct OxrOverlayPlugin; pub struct OxrOverlayPlugin;
impl Plugin for OxrOverlayPlugin { impl Plugin for OxrOverlayPlugin {
fn build(&self, app: &mut bevy::prelude::App) { fn build(&self, app: &mut App) {
app.add_event::<OxrOverlaySessionEvent>(); app.add_message::<OxrOverlaySessionMessage>();
app.init_resource::<OxrOverlaySettings>(); app.init_resource::<OxrOverlaySettings>();
app.add_systems( app.add_systems(
First, First,
@@ -25,9 +26,9 @@ impl Plugin for OxrOverlayPlugin {
} }
} }
fn handle_overlay_event(event: OxrEventIn, mut writer: EventWriter<OxrOverlaySessionEvent>) { fn handle_overlay_event(event: OxrEventIn, mut writer: MessageWriter<OxrOverlaySessionMessage>) {
if let Event::MainSessionVisibilityChangedEXTX(event) = *event { if let Event::MainSessionVisibilityChangedEXTX(event) = *event {
writer.write(OxrOverlaySessionEvent::MainSessionVisibilityChanged { writer.write(OxrOverlaySessionMessage::MainSessionVisibilityChanged {
visible: event.visible(), visible: event.visible(),
flags: event.flags(), flags: event.flags(),
}); });
@@ -62,8 +63,8 @@ fn add_overlay_info_to_chain(
} }
} }
#[derive(Event, Clone, Copy, Debug)] #[derive(Message, Clone, Copy, Debug)]
pub enum OxrOverlaySessionEvent { pub enum OxrOverlaySessionMessage {
MainSessionVisibilityChanged { MainSessionVisibilityChanged {
visible: bool, visible: bool,
flags: openxr::OverlayMainSessionFlagsEXTX, flags: openxr::OverlayMainSessionFlagsEXTX,

View File

@@ -5,7 +5,8 @@ pub mod vulkan;
use std::{any::TypeId, ffi::CStr}; use std::{any::TypeId, ffi::CStr};
use bevy::{ecs::resource::Resource, math::UVec2}; use bevy_ecs::resource::Resource;
use bevy_math::UVec2;
use openxr::{FrameStream, FrameWaiter, Session}; use openxr::{FrameStream, FrameWaiter, Session};
use crate::{ use crate::{

View File

@@ -2,10 +2,11 @@ use std::ffi::{c_void, CStr, CString};
use std::str::FromStr; use std::str::FromStr;
use ash::vk::{self, Handle}; use ash::vk::{self, Handle};
use bevy::log::{debug, error}; use bevy_log::{debug, error};
use bevy::math::UVec2; use bevy_math::UVec2;
use openxr::{sys, Version}; use openxr::{sys, Version};
use wgpu::InstanceFlags; use wgpu::{InstanceFlags, MemoryBudgetThresholds};
use wgpu::TextureUses;
use wgpu_hal::api::Vulkan; use wgpu_hal::api::Vulkan;
use wgpu_hal::Api; use wgpu_hal::Api;
@@ -53,7 +54,15 @@ unsafe impl GraphicsExt for openxr::Vulkan {
) -> Result<wgpu::Texture> { ) -> Result<wgpu::Texture> {
let color_image = vk::Image::from_raw(color_image); let color_image = vk::Image::from_raw(color_image);
let wgpu_hal_texture = unsafe { let wgpu_hal_texture = unsafe {
<wgpu_hal::vulkan::Api as wgpu_hal::Api>::Device::texture_from_raw( let hal_dev =
device
.as_hal::<wgpu_hal::vulkan::Api>()
.ok_or(OxrError::GraphicsBackendMismatch {
item: "Wgpu Device",
backend: "unknown",
expected_backend: "vulkan",
})?;
hal_dev.texture_from_raw(
color_image, color_image,
&wgpu_hal::TextureDescriptor { &wgpu_hal::TextureDescriptor {
label: Some("VR Swapchain"), label: Some("VR Swapchain"),
@@ -66,7 +75,7 @@ unsafe impl GraphicsExt for openxr::Vulkan {
sample_count: 1, sample_count: 1,
dimension: wgpu::TextureDimension::D2, dimension: wgpu::TextureDimension::D2,
format, format,
usage: wgpu_hal::TextureUses::COLOR_TARGET | wgpu_hal::TextureUses::COPY_DST, usage: TextureUses::COLOR_TARGET | TextureUses::COPY_DST,
memory_flags: wgpu_hal::MemoryFlags::empty(), memory_flags: wgpu_hal::MemoryFlags::empty(),
view_formats: vec![], view_formats: vec![],
}, },
@@ -151,7 +160,7 @@ unsafe impl GraphicsExt for openxr::Vulkan {
vk_physical_device, vk_physical_device,
instance_exts, instance_exts,
flags, flags,
device_exts.into(), device_exts,
|info| unsafe { |info| unsafe {
let vk_device = instance let vk_device = instance
.create_vulkan_device( .create_vulkan_device(
@@ -262,8 +271,8 @@ unsafe impl GraphicsExt for openxr::Vulkan {
vk_physical_device, vk_physical_device,
instance_exts, instance_exts,
instance_flags, instance_flags,
device_exts.into(), device_exts,
|info| unsafe { Ok(vk_instance.create_device(vk_physical_device, &info, None)?) }, |info| unsafe { Ok(vk_instance.create_device(vk_physical_device, info, None)?) },
) )
.map(|v| v.0) .map(|v| v.0)
} }
@@ -275,7 +284,7 @@ fn get_extensions(
) -> Result<(wgpu::InstanceFlags, Vec<&'static CStr>, Vec<&'static CStr>)> { ) -> Result<(wgpu::InstanceFlags, Vec<&'static CStr>, Vec<&'static CStr>)> {
let flags = wgpu::InstanceFlags::default().with_env(); let flags = wgpu::InstanceFlags::default().with_env();
let mut instance_exts = let mut instance_exts =
<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 mut device_exts = vec![ let mut device_exts = vec![
ash::khr::swapchain::NAME, ash::khr::swapchain::NAME,
ash::khr::draw_indirect_count::NAME, ash::khr::draw_indirect_count::NAME,
@@ -370,6 +379,7 @@ fn init_from_instance_and_dev(
None, None,
instance_exts, instance_exts,
instance_flags, instance_flags,
MemoryBudgetThresholds::default(),
has_nv_optimus, has_nv_optimus,
None, None,
)? )?
@@ -442,8 +452,8 @@ fn init_from_instance_and_dev(
required_features: wgpu_features, required_features: wgpu_features,
required_limits: limits, required_limits: limits,
memory_hints: wgpu::MemoryHints::Performance, memory_hints: wgpu::MemoryHints::Performance,
trace: wgpu::Trace::Off,
}, },
None,
) )
}?; }?;
Ok(( Ok((

View File

@@ -1,4 +1,5 @@
use bevy::{math::Vec3A, prelude::*}; use bevy_math::{Isometry3d, Quat, Vec2, Vec3, Vec3A};
use bevy_transform::components::Transform;
pub trait ToPosef { pub trait ToPosef {
fn to_posef(&self) -> openxr::Posef; fn to_posef(&self) -> openxr::Posef;

View File

@@ -1,23 +1,45 @@
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::Arc; use std::sync::Arc;
use bevy::prelude::*; use bevy_app::App;
use bevy::render::extract_resource::ExtractResourcePlugin; use bevy_app::Plugin;
use bevy::render::renderer::RenderAdapter; use bevy_ecs::message::MessageWriter;
use bevy::render::renderer::RenderAdapterInfo; use bevy_ecs::message::Messages;
use bevy::render::renderer::RenderDevice; use bevy_ecs::resource::Resource;
use bevy::render::renderer::RenderInstance; use bevy_ecs::schedule::SystemCondition as _;
use bevy::render::renderer::RenderQueue; use bevy_ecs::schedule::common_conditions::on_message;
use bevy::render::renderer::WgpuWrapper; use bevy_ecs::schedule::common_conditions::resource_exists;
use bevy::render::settings::RenderCreation; use bevy_ecs::schedule::IntoScheduleConfigs as _;
use bevy::render::MainWorld; use bevy_ecs::system::Commands;
use bevy::render::Render; use bevy_ecs::system::Local;
use bevy::render::RenderApp; use bevy_ecs::system::Res;
use bevy::render::RenderDebugFlags; use bevy_ecs::system::ResMut;
use bevy::render::RenderPlugin; use bevy_ecs::world::World;
use bevy::winit::UpdateMode; use bevy_log::debug;
use bevy::winit::WinitSettings; use bevy_log::debug_span;
use bevy_log::error;
use bevy_log::info;
use bevy_log::warn;
use bevy_math::UVec2;
use bevy_mod_xr::session::*; use bevy_mod_xr::session::*;
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::WgpuWrapper;
use bevy_render::settings::RenderCreation;
use bevy_render::ExtractSchedule;
use bevy_render::MainWorld;
use bevy_render::Render;
use bevy_render::RenderApp;
use bevy_render::RenderDebugFlags;
use bevy_render::RenderPlugin;
#[cfg(feature = "window_support")]
use bevy_winit::UpdateMode;
#[cfg(feature = "window_support")]
use bevy_winit::WinitSettings;
use crate::error::OxrError; use crate::error::OxrError;
use crate::graphics::*; use crate::graphics::*;
@@ -63,15 +85,15 @@ pub struct OxrInitPlugin {
impl Default for OxrInitPlugin { impl Default for OxrInitPlugin {
fn default() -> Self { fn default() -> Self {
Self { Self {
app_info: default(), app_info: Default::default(),
exts: { exts: {
let mut exts = OxrExtensions::default(); let mut exts = OxrExtensions::default();
exts.enable_hand_tracking(); exts.enable_hand_tracking();
exts exts
}, },
backends: default(), backends: Default::default(),
synchronous_pipeline_compilation: false, synchronous_pipeline_compilation: false,
render_debug_flags: default(), render_debug_flags: Default::default(),
} }
} }
} }
@@ -110,7 +132,7 @@ impl Plugin for OxrInitPlugin {
( (
create_xr_session create_xr_session
.run_if(state_equals(XrState::Available)) .run_if(state_equals(XrState::Available))
.run_if(on_event::<XrCreateSessionEvent>), .run_if(on_message::<XrCreateSessionMessage>),
( (
destroy_xr_session, destroy_xr_session,
(|v: Res<XrDestroySessionRender>| { (|v: Res<XrDestroySessionRender>| {
@@ -120,16 +142,16 @@ impl Plugin for OxrInitPlugin {
) )
.chain() .chain()
.run_if(state_matches!(XrState::Exiting { .. })) .run_if(state_matches!(XrState::Exiting { .. }))
.run_if(on_event::<XrDestroySessionEvent>), .run_if(on_message::<XrDestroySessionMessage>),
begin_xr_session begin_xr_session
.run_if(state_equals(XrState::Ready)) .run_if(state_equals(XrState::Ready))
.run_if(on_event::<XrBeginSessionEvent>), .run_if(on_message::<XrBeginSessionMessage>),
end_xr_session end_xr_session
.run_if(state_equals(XrState::Stopping)) .run_if(state_equals(XrState::Stopping))
.run_if(on_event::<XrEndSessionEvent>), .run_if(on_message::<XrEndSessionMessage>),
request_exit_xr_session request_exit_xr_session
.run_if(session_created) .run_if(session_created)
.run_if(on_event::<XrRequestExitEvent>), .run_if(on_message::<XrRequestExitMessage>),
detect_session_destroyed, detect_session_destroyed,
) )
.in_set(XrHandleEvents::SessionStateUpdateEvents), .in_set(XrHandleEvents::SessionStateUpdateEvents),
@@ -137,17 +159,20 @@ impl Plugin for OxrInitPlugin {
.insert_resource(instance.clone()) .insert_resource(instance.clone())
.insert_resource(system_id) .insert_resource(system_id)
.insert_resource(XrState::Available) .insert_resource(XrState::Available)
.insert_resource(WinitSettings {
focused_mode: UpdateMode::Continuous,
unfocused_mode: UpdateMode::Continuous,
})
.insert_resource(OxrSessionStarted(false)) .insert_resource(OxrSessionStarted(false))
.insert_non_send_resource(graphics_info) .insert_non_send_resource(graphics_info)
.init_non_send_resource::<OxrSessionCreateNextChain>(); .init_non_send_resource::<OxrSessionCreateNextChain>();
#[cfg(feature = "window_support")]
{
app.insert_resource(WinitSettings {
focused_mode: UpdateMode::Continuous,
unfocused_mode: UpdateMode::Continuous,
});
};
app.world_mut() app.world_mut()
.resource_mut::<Events<XrStateChanged>>() .resource_mut::<Messages<XrStateChanged>>()
.send(XrStateChanged(XrState::Available)); .write(XrStateChanged(XrState::Available));
let render_app = app.sub_app_mut(RenderApp); let render_app = app.sub_app_mut(RenderApp);
@@ -213,7 +238,7 @@ impl Plugin for OxrInitPlugin {
fn detect_session_destroyed( fn detect_session_destroyed(
mut last_state: Local<bool>, mut last_state: Local<bool>,
state: Res<XrDestroySessionRender>, state: Res<XrDestroySessionRender>,
mut sender: EventWriter<XrSessionDestroyedEvent>, mut sender: MessageWriter<XrSessionDestroyedMessage>,
mut cmds: Commands, mut cmds: Commands,
) { ) {
let state = state.0.load(Ordering::Relaxed); let state = state.0.load(Ordering::Relaxed);
@@ -307,7 +332,7 @@ impl OxrInitPlugin {
pub fn handle_events( pub fn handle_events(
event: OxrEventIn, event: OxrEventIn,
mut status: ResMut<XrState>, mut status: ResMut<XrState>,
mut changed_event: EventWriter<XrStateChanged>, mut changed_event: MessageWriter<XrStateChanged>,
) { ) {
use openxr::Event::*; use openxr::Event::*;
match *event { match *event {
@@ -511,7 +536,7 @@ pub fn create_xr_session(world: &mut World) {
} }
world.insert_non_send_resource(chain); world.insert_non_send_resource(chain);
world.run_schedule(XrSessionCreated); world.run_schedule(XrSessionCreated);
world.send_event(XrSessionCreatedEvent); world.write_message(XrSessionCreatedMessage);
} }
pub fn destroy_xr_session(world: &mut World) { pub fn destroy_xr_session(world: &mut World) {
@@ -525,9 +550,7 @@ pub fn destroy_xr_session(world: &mut World) {
world.insert_resource(XrState::Available); world.insert_resource(XrState::Available);
} }
pub fn begin_xr_session( pub fn begin_xr_session(world: &mut World) {
world: &mut World,
) {
let _span = debug_span!("xr_begin_session").entered(); let _span = debug_span!("xr_begin_session").entered();
world world
.get_resource::<OxrSession>() .get_resource::<OxrSession>()
@@ -539,9 +562,7 @@ pub fn begin_xr_session(
world.run_schedule(XrPostSessionBegin); world.run_schedule(XrPostSessionBegin);
} }
pub fn end_xr_session( pub fn end_xr_session(world: &mut World) {
world: &mut World,
) {
world.run_schedule(XrPreSessionEnd); world.run_schedule(XrPreSessionEnd);
let _span = debug_span!("xr_end_session").entered(); let _span = debug_span!("xr_end_session").entered();
world world

View File

@@ -1,6 +1,6 @@
use std::mem; use std::mem;
use bevy::ecs::world::World; use bevy_ecs::world::World;
use bevy_mod_xr::spaces::{XrPrimaryReferenceSpace, XrSpace}; use bevy_mod_xr::spaces::{XrPrimaryReferenceSpace, XrSpace};
use openxr::{sys, CompositionLayerFlags, Fovf, Posef, Rect2Di}; use openxr::{sys, CompositionLayerFlags, Fovf, Posef, Rect2Di};
@@ -63,7 +63,7 @@ impl LayerProvider for ProjectionLayer {
} }
impl LayerProvider for PassthroughLayer { impl LayerProvider for PassthroughLayer {
fn get(&self, world: &World) -> Option<Box<dyn CompositionLayer>> { fn get(&self, world: &World) -> Option<Box<dyn CompositionLayer<'_>>> {
Some(Box::new( Some(Box::new(
CompositionLayerPassthrough::new() CompositionLayerPassthrough::new()
.layer_handle(world.get_resource::<OxrPassthroughLayer>()?) .layer_handle(world.get_resource::<OxrPassthroughLayer>()?)

View File

@@ -1,13 +1,11 @@
// use actions::XrActionPlugin; // use actions::XrActionPlugin;
use bevy::{ use bevy_app::{PluginGroup, PluginGroupBuilder};
app::{PluginGroup, PluginGroupBuilder}, use bevy_ecs::system::Res;
prelude::Res,
render::RenderPlugin,
utils::default,
window::{PresentMode, Window, WindowPlugin},
};
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 bevy_render::RenderPlugin;
#[cfg(feature = "window_support")]
use bevy_window::{PresentMode, Window, WindowPlugin};
use init::OxrInitPlugin; use init::OxrInitPlugin;
use poll_events::OxrEventsPlugin; use poll_events::OxrEventsPlugin;
use render::OxrRenderPlugin; use render::OxrRenderPlugin;
@@ -54,7 +52,7 @@ pub fn openxr_session_running(
} }
pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder { pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
plugins let plugins = plugins
.build() .build()
.disable::<RenderPlugin>() .disable::<RenderPlugin>()
.add_before::<RenderPlugin>(XrSessionPlugin { auto_handle: true }) .add_before::<RenderPlugin>(XrSessionPlugin { auto_handle: true })
@@ -69,15 +67,17 @@ pub fn add_xr_plugins<G: PluginGroup>(plugins: G) -> PluginGroupBuilder {
.add(action_set_syncing::OxrActionSyncingPlugin) .add(action_set_syncing::OxrActionSyncingPlugin)
.add(features::overlay::OxrOverlayPlugin) .add(features::overlay::OxrOverlayPlugin)
.add(spaces::OxrSpatialPlugin) .add(spaces::OxrSpatialPlugin)
.add(spaces::OxrSpacePatchingPlugin) .add(spaces::OxrSpacePatchingPlugin);
// we should probably handle the exiting ourselfs so that we can correctly end the // we should probably handle the exiting ourselfs so that we can correctly end the
// session and instance // session and instance
.set(WindowPlugin { #[cfg(feature = "window_support")]
let plugins = plugins.set(WindowPlugin {
primary_window: Some(Window { primary_window: Some(Window {
transparent: true, transparent: true,
present_mode: PresentMode::AutoNoVsync, present_mode: PresentMode::AutoNoVsync,
..default() ..default()
}), }),
..default() ..default()
}) });
plugins
} }

View File

@@ -1,5 +1,8 @@
use super::{openxr_session_available, resources::OxrInstance}; use super::{openxr_session_available, resources::OxrInstance};
use bevy::{ecs::system::SystemId, prelude::*}; use bevy_app::{App, Plugin};
use bevy_derive::Deref;
use bevy_ecs::{entity::Entity, resource::Resource, schedule::IntoScheduleConfigs as _, system::{IntoSystem, SystemId, SystemInput}, world::World};
use bevy_log::{debug_span, error};
use bevy_mod_xr::session::{XrFirst, XrHandleEvents}; use bevy_mod_xr::session::{XrFirst, XrHandleEvents};
use openxr::{Event, EventDataBuffer}; use openxr::{Event, EventDataBuffer};

View File

@@ -1,11 +1,17 @@
use bevy::{ use bevy_app::{App, Plugin};
prelude::*, use bevy_ecs::{
render::{extract_resource::ExtractResourcePlugin, RenderApp}, entity::Entity,
query::With,
resource::Resource,
system::{Commands, Query, Res},
}; };
use bevy_log::error;
use bevy_math::Isometry3d;
use bevy_mod_xr::{ use bevy_mod_xr::{
session::{XrPreDestroySession, XrSessionCreated}, session::{XrPreDestroySession, XrSessionCreated},
spaces::{XrPrimaryReferenceSpace, XrReferenceSpace}, spaces::{XrPrimaryReferenceSpace, XrReferenceSpace},
}; };
use bevy_render::{RenderApp, extract_resource::ExtractResourcePlugin};
use crate::session::OxrSession; use crate::session::OxrSession;
@@ -51,7 +57,7 @@ fn set_primary_ref_space(
space_type: Res<OxrDefaultPrimaryReferenceSpaceType>, space_type: Res<OxrDefaultPrimaryReferenceSpaceType>,
mut cmds: Commands, mut cmds: Commands,
) { ) {
match session.create_reference_space(space_type.0, Transform::IDENTITY) { match session.create_reference_space(space_type.0, Isometry3d::IDENTITY) {
Ok(space) => { Ok(space) => {
cmds.insert_resource(XrPrimaryReferenceSpace(space)); cmds.insert_resource(XrPrimaryReferenceSpace(space));
} }

View File

@@ -1,25 +1,33 @@
use bevy::{ use bevy_app::{App, Plugin, PostUpdate};
prelude::*, use bevy_camera::{Camera, ManualTextureViewHandle, Projection, RenderTarget};
render::{ use bevy_ecs::{
camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews, RenderTarget}, change_detection::DetectChanges as _,
entity::Entity,
schedule::{IntoScheduleConfigs as _, SystemSet},
system::{Commands, Query, Res, ResMut},
world::World,
};
use bevy_log::{debug_span, error, info};
use bevy_render::{
extract_resource::ExtractResourcePlugin, extract_resource::ExtractResourcePlugin,
pipelined_rendering::PipelinedRenderingPlugin, pipelined_rendering::PipelinedRenderingPlugin,
view::{ExtractedView, NoFrustumCulling}, texture::{ManualTextureView, ManualTextureViews},
view::ExtractedView,
Render, RenderApp, Render, RenderApp,
},
transform::TransformSystem,
}; };
use bevy_mod_xr::{ use bevy_mod_xr::{
camera::{calculate_projection, Fov, XrCamera, XrProjection, XrViewInit}, camera::{calculate_projection, Fov, XrCamera, XrProjection, XrViewInit},
session::{ session::{
XrFirst, XrHandleEvents, XrPreDestroySession, XrRenderSet, XrRootTransform, XrFirst, XrHandleEvents, XrPreDestroySession, XrRenderSystems, XrRootTransform,
XrSessionCreated, XrSessionCreated,
}, },
spaces::XrPrimaryReferenceSpace, spaces::XrPrimaryReferenceSpace,
}; };
use bevy_transform::{components::Transform, TransformSystems};
use openxr::ViewStateFlags; use openxr::ViewStateFlags;
use crate::{init::should_run_frame_loop, resources::*}; use crate::{helper_traits::ToTransform as _, init::should_run_frame_loop, resources::*};
use crate::{layer_builder::ProjectionLayer, session::OxrSession}; use crate::{layer_builder::ProjectionLayer, session::OxrSession};
use super::environment_blend_mode::OxrEnvironmentBlendModes; use super::environment_blend_mode::OxrEnvironmentBlendModes;
@@ -88,9 +96,8 @@ impl Plugin for OxrRenderPlugin {
.add_systems( .add_systems(
PostUpdate, PostUpdate,
(locate_views, update_views) (locate_views, update_views)
.before(TransformSystem::TransformPropagate) .before(TransformSystems::Propagate)
.chain() .chain()
// .run_if(should_render)
.run_if(should_run_frame_loop), .run_if(should_run_frame_loop),
) )
.init_resource::<OxrViews>(); .init_resource::<OxrViews>();
@@ -109,7 +116,7 @@ impl Plugin for OxrRenderPlugin {
wait_image, wait_image,
) )
.chain() .chain()
.in_set(XrRenderSet::PreRender) .in_set(XrRenderSystems::PreRender)
.run_if(should_run_frame_loop), .run_if(should_run_frame_loop),
) )
.add_systems( .add_systems(
@@ -117,40 +124,12 @@ impl Plugin for OxrRenderPlugin {
(release_image, end_frame) (release_image, end_frame)
.chain() .chain()
.run_if(should_run_frame_loop) .run_if(should_run_frame_loop)
.in_set(XrRenderSet::PostRender), .in_set(XrRenderSystems::PostRender),
) )
.insert_resource(OxrRenderLayers(vec![Box::new(ProjectionLayer)])); .insert_resource(OxrRenderLayers(vec![Box::new(ProjectionLayer)]));
} }
} }
// fn update_rendering(app_world: &mut World, _sub_app: &mut App) {
// app_world.resource_scope(|world, main_thread_executor: Mut<MainThreadExecutor>| {
// world.resource_scope(|world, mut render_channels: Mut<RenderAppChannels>| {
// // we use a scope here to run any main thread tasks that the render world still needs to run
// // while we wait for the render world to be received.
// let mut render_app = ComputeTaskPool::get()
// .scope_with_executor(true, Some(&*main_thread_executor.0), |s| {
// s.spawn(async { render_channels.recv().await });
// })
// .pop()
// .unwrap();
// if matches!(world.resource::<XrState>(), XrState::Stopping) {
// world.run_schedule(XrEndSession);
// }
// if matches!(world.resource::<XrState>(), XrState::Exiting { .. }) {
// world.run_schedule(XrDestroySession);
// render_app.app.world.run_schedule(XrDestroySession);
// }
// render_app.extract(world);
// render_channels.send_blocking(render_app);
// });
// });
// }
pub const XR_TEXTURE_INDEX: u32 = 3383858418; pub const XR_TEXTURE_INDEX: u32 = 3383858418;
pub fn clean_views( pub fn clean_views(
@@ -185,7 +164,7 @@ pub fn init_views<const SPAWN_CAMERAS: bool>(
}, },
XrCamera(index), XrCamera(index),
Projection::custom(XrProjection::default()), Projection::custom(XrProjection::default()),
NoFrustumCulling, // NoFrustumCulling,
)); ));
} }
} }
@@ -283,12 +262,7 @@ pub fn update_views(
); );
projection.projection_matrix = projection_matrix; projection.projection_matrix = projection_matrix;
let openxr::Quaternionf { x, y, z, w } = view.pose.orientation; *transform = view.pose.to_transform();
let rotation = Quat::from_xyzw(x, y, z, w);
transform.rotation = rotation;
let openxr::Vector3f { x, y, z } = view.pose.position;
let translation = Vec3::new(x, y, z);
transform.translation = translation;
} }
} }
@@ -301,14 +275,7 @@ pub fn update_views_render_world(
let Some(view) = views.get(camera.0 as usize) else { let Some(view) = views.get(camera.0 as usize) else {
continue; continue;
}; };
let mut transform = Transform::IDENTITY; extracted_view.world_from_view = root.0.mul_transform(view.pose.to_transform());
let openxr::Quaternionf { x, y, z, w } = view.pose.orientation;
let rotation = Quat::from_xyzw(x, y, z, w);
transform.rotation = rotation;
let openxr::Vector3f { x, y, z } = view.pose.position;
let translation = Vec3::new(x, y, z);
transform.translation = translation;
extracted_view.world_from_view = root.0.mul_transform(transform);
} }
} }
@@ -345,7 +312,7 @@ pub fn add_texture_view(
dimension: Some(wgpu::TextureViewDimension::D2), dimension: Some(wgpu::TextureViewDimension::D2),
array_layer_count: Some(1), array_layer_count: Some(1),
base_array_layer: index, base_array_layer: index,
..default() ..Default::default()
}); });
let view = ManualTextureView { let view = ManualTextureView {
texture_view: view.into(), texture_view: view.into(),

View File

@@ -1,5 +1,8 @@
use bevy::prelude::*; use bevy_derive::{Deref, DerefMut};
use bevy::render::extract_resource::ExtractResource; use bevy_ecs::resource::Resource;
use bevy_math::UVec2;
use bevy_render::extract_resource::ExtractResource;
use bevy_log::error;
use crate::error::OxrError; use crate::error::OxrError;
use crate::graphics::*; use crate::graphics::*;
@@ -351,7 +354,7 @@ impl Default for OxrSessionConfig {
Self { Self {
blend_mode_preference: vec![openxr::EnvironmentBlendMode::OPAQUE], blend_mode_preference: vec![openxr::EnvironmentBlendMode::OPAQUE],
formats: Some(vec![wgpu::TextureFormat::Rgba8UnormSrgb]), formats: Some(vec![wgpu::TextureFormat::Rgba8UnormSrgb]),
resolutions: default(), resolutions: None,
} }
} }
} }

View File

@@ -3,7 +3,8 @@ use std::ffi::c_void;
use crate::next_chain::{OxrNextChain, OxrNextChainStructBase, OxrNextChainStructProvider}; use crate::next_chain::{OxrNextChain, OxrNextChainStructBase, OxrNextChainStructProvider};
use crate::resources::{OxrPassthrough, OxrPassthroughLayer, OxrSwapchain}; use crate::resources::{OxrPassthrough, OxrPassthroughLayer, OxrSwapchain};
use crate::types::{Result, SwapchainCreateInfo}; use crate::types::{Result, SwapchainCreateInfo};
use bevy::prelude::*; use bevy_derive::Deref;
use bevy_ecs::resource::Resource;
use openxr::AnyGraphics; use openxr::AnyGraphics;
use crate::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap}; use crate::graphics::{graphics_match, GraphicsExt, GraphicsType, GraphicsWrap};

View File

@@ -1,16 +1,24 @@
use std::{mem::MaybeUninit, ptr, sync::Mutex}; use bevy_app::{App, Plugin, PreUpdate, Startup};
use bevy_ecs::{
use bevy::{platform::collections::hash_set::HashSet, prelude::*}; component::Component, message::MessageReader, schedule::IntoScheduleConfigs as _, system::{Query, Res, ResMut}
};
use bevy_log::{error, info};
use bevy_log::warn;
use bevy_math::Isometry3d;
use bevy_mod_xr::{ use bevy_mod_xr::{
session::{XrFirst, XrHandleEvents}, session::{XrFirst, XrHandleEvents},
spaces::{ spaces::{
XrDestroySpace, XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace, XrSpaceLocationFlags, XrSpaceSyncSet, XrSpaceVelocityFlags, XrVelocity XrDestroySpace, XrPrimaryReferenceSpace, XrReferenceSpace, XrSpace, XrSpaceLocationFlags,
XrSpaceSyncSet, XrSpaceVelocityFlags, XrVelocity,
}, },
}; };
use bevy_platform::collections::hash_set::HashSet;
use bevy_transform::components::Transform;
use openxr::{ use openxr::{
sys, HandJointLocation, HandJointLocations, HandJointVelocities, HandJointVelocity, sys, HandJointLocation, HandJointLocations, HandJointVelocities, HandJointVelocity,
ReferenceSpaceType, SpaceLocationFlags, SpaceVelocityFlags, HAND_JOINT_COUNT, ReferenceSpaceType, SpaceLocationFlags, SpaceVelocityFlags, HAND_JOINT_COUNT,
}; };
use std::{mem::MaybeUninit, ptr, sync::Mutex};
use crate::{ use crate::{
helper_traits::{ToPosef, ToQuat, ToVec3}, helper_traits::{ToPosef, ToQuat, ToVec3},
@@ -33,7 +41,7 @@ impl Plugin for OxrSpacePatchingPlugin {
pub struct OxrSpatialPlugin; pub struct OxrSpatialPlugin;
impl Plugin for OxrSpatialPlugin { impl Plugin for OxrSpatialPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<XrDestroySpace>() app.add_message::<XrDestroySpace>()
.add_systems( .add_systems(
XrFirst, XrFirst,
destroy_space_event destroy_space_event
@@ -51,7 +59,7 @@ impl Plugin for OxrSpatialPlugin {
} }
} }
fn destroy_space_event(instance: Res<OxrInstance>, mut events: EventReader<XrDestroySpace>) { fn destroy_space_event(instance: Res<OxrInstance>, mut events: MessageReader<XrDestroySpace>) {
for space in events.read() { for space in events.read() {
match instance.destroy_space(space.0) { match instance.destroy_space(space.0) {
Ok(_) => (), Ok(_) => (),
@@ -231,7 +239,7 @@ impl OxrSession {
pub fn create_reference_space( pub fn create_reference_space(
&self, &self,
ref_space_type: ReferenceSpaceType, ref_space_type: ReferenceSpaceType,
pose_in_ref_space: Transform, pose_in_ref_space: Isometry3d,
) -> openxr::Result<XrReferenceSpace> { ) -> openxr::Result<XrReferenceSpace> {
let info = sys::ReferenceSpaceCreateInfo { let info = sys::ReferenceSpaceCreateInfo {
ty: sys::ReferenceSpaceCreateInfo::TYPE, ty: sys::ReferenceSpaceCreateInfo::TYPE,
@@ -579,6 +587,7 @@ fn cvt(x: sys::Result) -> openxr::Result<sys::Result> {
Err(x) Err(x)
} }
} }
#[allow(clippy::obfuscated_if_else)]
unsafe fn create_view(flags: openxr::ViewStateFlags, raw: &MaybeUninit<sys::View>) -> openxr::View { unsafe fn create_view(flags: openxr::ViewStateFlags, raw: &MaybeUninit<sys::View>) -> openxr::View {
// Applications *must* not read invalid parts of a poses, i.e. they may be uninitialized // Applications *must* not read invalid parts of a poses, i.e. they may be uninitialized
let ptr = raw.as_ptr(); let ptr = raw.as_ptr();
@@ -596,6 +605,7 @@ unsafe fn create_view(flags: openxr::ViewStateFlags, raw: &MaybeUninit<sys::View
fov: *ptr::addr_of!((*ptr).fov), fov: *ptr::addr_of!((*ptr).fov),
} }
} }
#[allow(clippy::obfuscated_if_else)]
unsafe fn create_space_location(raw: &MaybeUninit<sys::SpaceLocation>) -> openxr::SpaceLocation { unsafe fn create_space_location(raw: &MaybeUninit<sys::SpaceLocation>) -> openxr::SpaceLocation {
// Applications *must* not read invalid parts of a pose, i.e. they may be uninitialized // Applications *must* not read invalid parts of a pose, i.e. they may be uninitialized
let ptr = raw.as_ptr(); let ptr = raw.as_ptr();
@@ -614,6 +624,7 @@ unsafe fn create_space_location(raw: &MaybeUninit<sys::SpaceLocation>) -> openxr
}, },
} }
} }
#[allow(clippy::obfuscated_if_else)]
unsafe fn create_space_velocity(raw: &MaybeUninit<sys::SpaceVelocity>) -> openxr::SpaceVelocity { unsafe fn create_space_velocity(raw: &MaybeUninit<sys::SpaceVelocity>) -> openxr::SpaceVelocity {
// Applications *must* not read invalid velocities, i.e. they may be uninitialized // Applications *must* not read invalid velocities, i.e. they may be uninitialized
let ptr = raw.as_ptr(); let ptr = raw.as_ptr();

View File

@@ -8,7 +8,7 @@ license.workspace = true
# bevy can't be placed behind target or proc macros won't work properly # bevy can't be placed behind target or proc macros won't work properly
[dependencies] [dependencies]
bevy.workspace = true # bevy.workspace = true
# all dependencies are placed under this since on anything but wasm, this crate is completely empty # all dependencies are placed under this since on anything but wasm, this crate is completely empty
[target.'cfg(target_family = "wasm")'.dependencies] [target.'cfg(target_family = "wasm")'.dependencies]

View File

@@ -10,10 +10,21 @@ keywords = ["gamedev", "bevy", "Xr", "Vr"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features] [features]
default = ["gizmos"] default = ["gizmos"]
gizmos = ["bevy/bevy_gizmos"] gizmos = ["dep:bevy_gizmos", "dep:bevy_color"]
reflect = ["dep:bevy_reflect"]
[dependencies] [dependencies]
bevy = { workspace = true, features = ["bevy_log"] } bevy_ecs.workspace = true
bevy_math.workspace = true
bevy_render.workspace = true
bevy_app.workspace = true
bevy_reflect = { workspace = true, optional = true }
bevy_log.workspace = true
bevy_gizmos = { workspace = true, optional = true }
bevy_color = { workspace = true, optional = true }
bevy_transform.workspace = true
bevy_camera.workspace = true
bevy_derive.workspace = true
[lints.clippy] [lints.clippy]
too_many_arguments = "allow" too_many_arguments = "allow"

View File

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

View File

@@ -1,14 +1,15 @@
use core::panic; use core::panic;
use bevy::app::{App, Plugin}; use bevy_app::{App, Plugin};
use bevy::core_pipeline::core_3d::Camera3d; use bevy_camera::{Camera3d, CameraProjection};
use bevy::ecs::component::Component; use bevy_ecs::{component::Component, schedule::SystemSet};
use bevy::math::{Mat4, Vec3A, Vec4}; use bevy_math::{Mat4, Vec3A, Vec4};
use bevy::prelude::SystemSet; // use bevy::prelude::SystemSet;
use bevy::reflect::std_traits::ReflectDefault; #[cfg(feature = "reflect")]
use bevy::reflect::Reflect; use bevy_reflect::std_traits::ReflectDefault;
use bevy::render::camera::CameraProjection; #[cfg(feature = "reflect")]
use bevy::render::extract_component::{ExtractComponent, ExtractComponentPlugin}; use bevy_reflect::Reflect;
use bevy_render::extract_component::{ExtractComponent, ExtractComponentPlugin};
use crate::session::XrTracker; use crate::session::XrTracker;
@@ -23,8 +24,9 @@ impl Plugin for XrCameraPlugin {
#[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)] #[derive(Debug, Clone)]
#[reflect(Default)] #[cfg_attr(feature = "reflect", derive(Reflect))]
#[cfg_attr(feature = "reflect", reflect(Default))]
pub struct XrProjection { pub struct XrProjection {
pub projection_matrix: Mat4, pub projection_matrix: Mat4,
pub near: f32, pub near: f32,
@@ -83,7 +85,7 @@ impl CameraProjection for XrProjection {
self.projection_matrix self.projection_matrix
} }
fn get_clip_from_view_for_sub(&self, _sub_view: &bevy::render::camera::SubCameraView) -> Mat4 { fn get_clip_from_view_for_sub(&self, _sub_view: &bevy_camera::SubCameraView) -> Mat4 {
panic!("sub view not supported for xr camera"); panic!("sub view not supported for xr camera");
} }
} }
@@ -194,11 +196,8 @@ pub fn calculate_projection(near_z: f32, fov: Fov) -> Mat4 {
mod tests { mod tests {
use std::f32::{self, consts::PI}; use std::f32::{self, consts::PI};
use bevy::{ use bevy_math::{Mat4,Vec3A};
math::{Mat4, Vec3A}, use bevy_camera::{CameraProjection, PerspectiveProjection};
render::camera::{CameraProjection, PerspectiveProjection},
utils::default,
};
const TEST_VALUES: &[(f32, f32)] = &[(0.5, 100.0), (50.0, 200.0)]; const TEST_VALUES: &[(f32, f32)] = &[(0.5, 100.0), (50.0, 200.0)];
@@ -230,7 +229,7 @@ mod tests {
fn test_get_frustum_corners_symmetrical() { fn test_get_frustum_corners_symmetrical() {
let control_proj = PerspectiveProjection { let control_proj = PerspectiveProjection {
near: 0.1, near: 0.1,
..default() ..Default::default()
}; };
let projection = XrProjection { let projection = XrProjection {
@@ -252,7 +251,7 @@ mod tests {
fn test_get_frustum_corners_symmetrical_far_plane() { fn test_get_frustum_corners_symmetrical_far_plane() {
let control_proj = PerspectiveProjection { let control_proj = PerspectiveProjection {
near: 0.1, near: 0.1,
..default() ..Default::default()
}; };
let projection = XrProjection { let projection = XrProjection {

View File

@@ -1,13 +1,21 @@
use crate::hands::{HandBone, XrHandBoneRadius}; use crate::hands::{HandBone, XrHandBoneRadius};
use crate::spaces::XrSpaceLocationFlags; use crate::spaces::XrSpaceLocationFlags;
use bevy::color::palettes::css; use bevy_app::{App, Plugin, PostUpdate};
use bevy::{prelude::*, transform::TransformSystem}; use bevy_color::palettes::css;
use bevy_color::Srgba;
use bevy_ecs::schedule::IntoScheduleConfigs as _;
use bevy_ecs::system::Query;
use bevy_gizmos::gizmos::Gizmos;
use bevy_math::Isometry3d;
use bevy_transform::TransformSystems;
use bevy_transform::components::GlobalTransform;
pub struct HandGizmosPlugin; pub struct HandGizmosPlugin;
impl Plugin for HandGizmosPlugin { impl Plugin for HandGizmosPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems( app.add_systems(
PostUpdate, PostUpdate,
draw_hand_gizmos.after(TransformSystem::TransformPropagate), draw_hand_gizmos.after(TransformSystems::Propagate),
); );
} }
} }

View File

@@ -1,10 +1,11 @@
use bevy::{
ecs::{component::Component, entity::Entity},
log::warn,
math::bool,
prelude::{Bundle, Command, Commands, Deref, DerefMut, Resource, Transform, Visibility, World},
};
use crate::{session::XrTracker, spaces::XrSpaceLocationFlags}; use crate::{session::XrTracker, spaces::XrSpaceLocationFlags};
use bevy_camera::visibility::Visibility;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{bundle::Bundle, component::Component, entity::Entity, resource::Resource, system::{Command, Commands}, world::World};
use bevy_log::warn;
use bevy_math::bool;
use bevy_transform::components::Transform;
pub const HAND_JOINT_COUNT: usize = 26; pub const HAND_JOINT_COUNT: usize = 26;
pub fn spawn_hand_bones<T: Bundle>( pub fn spawn_hand_bones<T: Bundle>(

View File

@@ -5,4 +5,3 @@ pub mod hand_debug_gizmos;
pub mod hands; pub mod hands;
pub mod session; pub mod session;
pub mod spaces; pub mod spaces;
pub mod types;

View File

@@ -2,30 +2,45 @@ use std::convert::identity;
use std::sync::atomic::AtomicBool; use std::sync::atomic::AtomicBool;
use std::sync::Arc; use std::sync::Arc;
use bevy::app::{AppExit, MainScheduleOrder}; use bevy_app::{App, AppExit, MainScheduleOrder, Plugin, PostUpdate, PreUpdate};
use bevy::ecs::component::HookContext; use bevy_camera::visibility::Visibility;
use bevy::ecs::schedule::ScheduleLabel; use bevy_derive::Deref;
use bevy::ecs::world::DeferredWorld; use bevy_ecs::component::Component;
use bevy::prelude::*; use bevy_ecs::entity::Entity;
use bevy::render::extract_resource::{ExtractResource, ExtractResourcePlugin}; use bevy_ecs::hierarchy::Children;
use bevy::render::{Render, RenderApp, RenderSet}; use bevy_ecs::lifecycle::HookContext;
use bevy_ecs::message::{Message, MessageReader, MessageWriter};
use bevy_ecs::query::{Has, With};
use bevy_ecs::resource::Resource;
use bevy_ecs::schedule::common_conditions::on_message;
use bevy_ecs::schedule::{
ExecutorKind, IntoScheduleConfigs as _, Schedule, ScheduleLabel, SystemCondition as _, SystemSet
};
use bevy_ecs::system::{Local, Query, Res, ResMut};
use bevy_ecs::world::DeferredWorld;
use bevy_render::extract_resource::{ExtractResource, ExtractResourcePlugin};
use bevy_render::{Render, RenderApp, RenderSystems};
use bevy_transform::components::{GlobalTransform, Transform};
use bevy_transform::TransformSystems;
#[cfg(feature="reflect")]
use bevy_reflect::Reflect;
/// Event sent to instruct backends to create an XR session. Only works when the [`XrState`] is [`Available`](XrState::Available). /// Message sent to instruct backends to create an XR session. Only works when the [`XrState`] is [`Available`](XrState::Available).
#[derive(Event, Clone, Copy, Default)] #[derive(Message, Clone, Copy, Default)]
pub struct XrCreateSessionEvent; pub struct XrCreateSessionMessage;
/// A schedule thats ran whenever an [`XrCreateSessionEvent`] is recieved while the [`XrState`] is [`Available`](XrState::Available) /// A schedule thats ran whenever an [`XrCreateSessionMessage`] is recieved while the [`XrState`] is [`Available`](XrState::Available)
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)] #[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
pub struct XrSessionCreated; pub struct XrSessionCreated;
/// Event sent after the XrSession was created. /// Message sent after the XrSession was created.
#[derive(Event, Clone, Copy, Default)] #[derive(Message, Clone, Copy, Default)]
pub struct XrSessionCreatedEvent; pub struct XrSessionCreatedMessage;
/// Event sent to instruct backends to destroy an XR session. Only works when the [`XrState`] is [`Exiting`](XrState::Exiting). /// Message sent to instruct backends to destroy an XR session. Only works when the [`XrState`] is [`Exiting`](XrState::Exiting).
/// If you would like to request that a running session be destroyed, send the [`XrRequestExitEvent`] instead. /// If you would like to request that a running session be destroyed, send the [`XrRequestExitMessage`] instead.
#[derive(Event, Clone, Copy, Default)] #[derive(Message, Clone, Copy, Default)]
pub struct XrDestroySessionEvent; pub struct XrDestroySessionMessage;
/// Resource flag thats inserted into the world and extracted to the render world to inform any session resources in the render world to drop. /// Resource flag thats inserted into the world and extracted to the render world to inform any session resources in the render world to drop.
#[derive(Resource, Clone, Default)] #[derive(Resource, Clone, Default)]
@@ -35,29 +50,29 @@ pub struct XrDestroySessionRender(pub Arc<AtomicBool>);
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)] #[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
pub struct XrPreDestroySession; pub struct XrPreDestroySession;
/// Event sent to instruct backends to begin an XR session. Only works when the [`XrState`] is [`Ready`](XrState::Ready). /// Message sent to instruct backends to begin an XR session. Only works when the [`XrState`] is [`Ready`](XrState::Ready).
#[derive(Event, Clone, Copy, Default)] #[derive(Message, Clone, Copy, Default)]
pub struct XrBeginSessionEvent; pub struct XrBeginSessionMessage;
/// Schedule thats ran when the XrSession has begun. /// Schedule thats ran when the XrSession has begun.
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)] #[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
pub struct XrPostSessionBegin; pub struct XrPostSessionBegin;
/// Event sent to backends to end an XR session. Only works when the [`XrState`] is [`Stopping`](XrState::Stopping). /// Message sent to backends to end an XR session. Only works when the [`XrState`] is [`Stopping`](XrState::Stopping).
#[derive(Event, Clone, Copy, Default)] #[derive(Message, Clone, Copy, Default)]
pub struct XrEndSessionEvent; pub struct XrEndSessionMessage;
/// Schedule thats ran whenever the XrSession is about to end /// Schedule thats ran whenever the XrSession is about to end
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)] #[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
pub struct XrPreSessionEnd; pub struct XrPreSessionEnd;
/// Event that is emitted when the XrSession is fully destroyed /// Message that is emitted when the XrSession is fully destroyed
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, Event)] #[derive(Message, Clone, Copy, Default, PartialEq, Eq, Debug, Hash)]
pub struct XrSessionDestroyedEvent; pub struct XrSessionDestroyedMessage;
/// Event sent to backends to request the [`XrState`] proceed to [`Exiting`](XrState::Exiting) and for the session to be exited. Can be called at any time a session exists. /// Message sent to backends to request the [`XrState`] proceed to [`Exiting`](XrState::Exiting) and for the session to be exited. Can be called at any time a session exists.
#[derive(Event, Clone, Copy, Default)] #[derive(Message, Clone, Copy, Default)]
pub struct XrRequestExitEvent; pub struct XrRequestExitMessage;
/// Schedule ran before [`First`] to handle XR events. /// Schedule ran before [`First`] to handle XR events.
#[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)] #[derive(Clone, Copy, Default, PartialEq, Eq, Debug, Hash, ScheduleLabel)]
@@ -75,13 +90,13 @@ pub enum XrHandleEvents {
/// System sets ran in the render world for XR. /// System sets ran in the render world for XR.
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)] #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
pub enum XrRenderSet { pub enum XrRenderSystems {
/// Ran before [`XrRenderSet::PreRender`] but after [`RenderSet::ExtractCommands`]. /// Ran before [`XrRenderSet::PreRender`] but after [`RenderSystems::ExtractCommands`].
HandleEvents, HandleEvents,
/// For any XR systems needing to be ran before rendering begins. /// For any XR systems needing to be ran before rendering begins.
/// Ran after [`XrRenderSet::HandleEvents`] but before every render set except [`RenderSet::ExtractCommands`]. /// Ran after [`XrRenderSet::HandleEvents`] but before every render set except [`RenderSystems::ExtractCommands`].
PreRender, PreRender,
/// For any XR systems needing to be ran after [`RenderSet::Render`] but before [`RenderSet::Cleanup`]. /// For any XR systems needing to be ran after [`RenderSystems::Render`] but before [`RenderSystems::Cleanup`].
PostRender, PostRender,
} }
@@ -97,7 +112,8 @@ 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, Component)] #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, Default, Component)]
#[cfg_attr(feature = "reflect", derive(Reflect))]
#[component(on_add = on_tracker_add)] #[component(on_add = on_tracker_add)]
pub struct XrTracker; pub struct XrTracker;
fn on_tracker_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) { fn on_tracker_add(mut world: DeferredWorld, HookContext { entity, .. }: HookContext) {
@@ -122,15 +138,15 @@ impl Plugin for XrSessionPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.init_resource::<XrDestroySessionRender>(); app.init_resource::<XrDestroySessionRender>();
let mut xr_first = Schedule::new(XrFirst); let mut xr_first = Schedule::new(XrFirst);
xr_first.set_executor_kind(bevy::ecs::schedule::ExecutorKind::Simple); xr_first.set_executor_kind(ExecutorKind::SingleThreaded);
app.add_event::<XrCreateSessionEvent>() app.add_message::<XrCreateSessionMessage>()
.add_event::<XrDestroySessionEvent>() .add_message::<XrDestroySessionMessage>()
.add_event::<XrBeginSessionEvent>() .add_message::<XrBeginSessionMessage>()
.add_event::<XrEndSessionEvent>() .add_message::<XrEndSessionMessage>()
.add_event::<XrRequestExitEvent>() .add_message::<XrRequestExitMessage>()
.add_event::<XrStateChanged>() .add_message::<XrStateChanged>()
.add_event::<XrSessionCreatedEvent>() .add_message::<XrSessionCreatedMessage>()
.add_event::<XrSessionDestroyedEvent>() .add_message::<XrSessionDestroyedMessage>()
.init_schedule(XrSessionCreated) .init_schedule(XrSessionCreated)
.init_schedule(XrPreDestroySession) .init_schedule(XrPreDestroySession)
.init_schedule(XrPostSessionBegin) .init_schedule(XrPostSessionBegin)
@@ -150,7 +166,7 @@ impl Plugin for XrSessionPlugin {
.add_systems( .add_systems(
XrFirst, XrFirst,
exits_session_on_app_exit exits_session_on_app_exit
.run_if(on_event::<AppExit>) .run_if(on_message::<AppExit>)
.run_if(session_created) .run_if(session_created)
.in_set(XrHandleEvents::ExitEvents), .in_set(XrHandleEvents::ExitEvents),
); );
@@ -178,13 +194,13 @@ impl Plugin for XrSessionPlugin {
.init_resource::<XrRootTransform>() .init_resource::<XrRootTransform>()
.add_systems( .add_systems(
PostUpdate, PostUpdate,
update_root_transform.after(TransformSystem::TransformPropagate), update_root_transform.after(TransformSystems::Propagate),
) )
.add_systems( .add_systems(
XrFirst, XrFirst,
exits_session_on_app_exit exits_session_on_app_exit
.before(XrHandleEvents::ExitEvents) .before(XrHandleEvents::ExitEvents)
.run_if(on_event::<AppExit>.and(session_running)), .run_if(on_message::<AppExit>.and(session_running)),
); );
let render_app = app.sub_app_mut(RenderApp); let render_app = app.sub_app_mut(RenderApp);
@@ -194,33 +210,33 @@ impl Plugin for XrSessionPlugin {
// .init_resource::<XrRootTransform>() // .init_resource::<XrRootTransform>()
.configure_sets( .configure_sets(
Render, Render,
(XrRenderSet::HandleEvents, XrRenderSet::PreRender).chain(), (XrRenderSystems::HandleEvents, XrRenderSystems::PreRender).chain(),
) )
.configure_sets( .configure_sets(
Render, Render,
XrRenderSet::HandleEvents.after(RenderSet::ExtractCommands), XrRenderSystems::HandleEvents.after(RenderSystems::ExtractCommands),
) )
.configure_sets( .configure_sets(
Render, Render,
XrRenderSet::PreRender XrRenderSystems::PreRender
.before(RenderSet::ManageViews) .before(RenderSystems::ManageViews)
.before(RenderSet::PrepareAssets), .before(RenderSystems::PrepareAssets),
) )
.configure_sets( .configure_sets(
Render, Render,
XrRenderSet::PostRender XrRenderSystems::PostRender
.after(RenderSet::Render) .after(RenderSystems::Render)
.before(RenderSet::Cleanup), .before(RenderSystems::Cleanup),
); );
} }
} }
fn exits_session_on_app_exit(mut request_exit: EventWriter<XrRequestExitEvent>) { fn exits_session_on_app_exit(mut request_exit: MessageWriter<XrRequestExitMessage>) {
request_exit.write_default(); request_exit.write_default();
} }
/// Event sent by backends whenever [`XrState`] is changed. /// Message sent by backends whenever [`XrState`] is changed.
#[derive(Event, Clone, Copy, Deref)] #[derive(Message, Clone, Copy, Deref)]
pub struct XrStateChanged(pub XrState); pub struct XrStateChanged(pub XrState);
/// A resource in the main world and render world representing the current session state. /// A resource in the main world and render world representing the current session state.
@@ -229,17 +245,17 @@ pub struct XrStateChanged(pub XrState);
pub enum XrState { pub enum XrState {
/// An XR session is not available here /// An XR session is not available here
Unavailable, Unavailable,
/// An XR session is available and ready to be created with an [`XrCreateSessionEvent`]. /// An XR session is available and ready to be created with an [`XrCreateSessionMessage`].
Available, Available,
/// An XR session is created but not ready to begin. Backends are not required to use this state. /// An XR session is created but not ready to begin. Backends are not required to use this state.
Idle, Idle,
/// An XR session has been created and is ready to start rendering with an [`XrBeginSessionEvent`]. /// An XR session has been created and is ready to start rendering with an [`XrBeginSessionMessage`].
Ready, Ready,
/// The XR session is running and can be stopped with an [`XrEndSessionEvent`]. /// The XR session is running and can be stopped with an [`XrEndSessionMessage`].
Running, Running,
/// The runtime has requested that the session should be ended with an [`XrEndSessionEvent`]. /// The runtime has requested that the session should be ended with an [`XrEndSessionMessage`].
Stopping, Stopping,
/// The XR session should be destroyed with an [`XrDestroySessionEvent`]. /// The XR session should be destroyed with an [`XrDestroySessionMessage`].
Exiting { Exiting {
/// Whether we should automatically restart the session /// Whether we should automatically restart the session
should_restart: bool, should_restart: bool,
@@ -247,11 +263,11 @@ pub enum XrState {
} }
pub fn auto_handle_session( pub fn auto_handle_session(
mut state_changed: EventReader<XrStateChanged>, mut state_changed: MessageReader<XrStateChanged>,
mut create_session: EventWriter<XrCreateSessionEvent>, mut create_session: MessageWriter<XrCreateSessionMessage>,
mut begin_session: EventWriter<XrBeginSessionEvent>, mut begin_session: MessageWriter<XrBeginSessionMessage>,
mut end_session: EventWriter<XrEndSessionEvent>, mut end_session: MessageWriter<XrEndSessionMessage>,
mut destroy_session: EventWriter<XrDestroySessionEvent>, mut destroy_session: MessageWriter<XrDestroySessionMessage>,
mut no_auto_restart: Local<bool>, mut no_auto_restart: Local<bool>,
) { ) {
for XrStateChanged(state) in state_changed.read() { for XrStateChanged(state) in state_changed.read() {
@@ -290,8 +306,8 @@ pub fn update_root_transform(
/// A [`Condition`](bevy::ecs::schedule::Condition) that allows the system to run when the xr status changed to a specific [`XrStatus`]. /// A [`Condition`](bevy::ecs::schedule::Condition) that allows the system to run when the xr status changed to a specific [`XrStatus`].
pub fn status_changed_to( pub fn status_changed_to(
status: XrState, status: XrState,
) -> impl FnMut(EventReader<XrStateChanged>) -> bool + Clone { ) -> impl FnMut(MessageReader<XrStateChanged>) -> bool + Clone {
move |mut reader: EventReader<XrStateChanged>| { move |mut reader: MessageReader<XrStateChanged>| {
reader.read().any(|new_status| new_status.0 == status) reader.read().any(|new_status| new_status.0 == status)
} }
} }
@@ -332,5 +348,4 @@ macro_rules! state_matches {
}; };
} }
use bevy::transform::TransformSystem;
pub use state_matches; pub use state_matches;

View File

@@ -1,7 +1,11 @@
use bevy::{ use bevy_camera::visibility::Visibility;
prelude::*, use bevy_derive::{Deref, DerefMut};
render::{extract_component::ExtractComponent, extract_resource::ExtractResource}, use bevy_ecs::{component::Component, message::Message, resource::Resource, schedule::SystemSet};
}; use bevy_math::Vec3;
use bevy_render::{extract_component::ExtractComponent, extract_resource::ExtractResource};
use bevy_transform::components::Transform;
#[cfg(feature="reflect")]
use bevy_reflect::Reflect;
use crate::session::XrTracker; use crate::session::XrTracker;
@@ -10,11 +14,13 @@ pub struct XrSpaceSyncSet;
/// Any Spaces will be invalid after the owning session exits /// Any Spaces will be invalid after the owning session exits
#[repr(transparent)] #[repr(transparent)]
#[derive(Component, Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, ExtractComponent)] #[derive(Component, Clone, Copy, Hash, PartialEq, Eq, Debug, ExtractComponent)]
#[cfg_attr(feature = "reflect", derive(Reflect))]
#[require(XrSpaceLocationFlags, Transform, Visibility, XrTracker)] #[require(XrSpaceLocationFlags, Transform, Visibility, XrTracker)]
pub struct XrSpace(u64); pub struct XrSpace(u64);
#[derive(Component, Clone, Copy, Reflect, Debug, ExtractComponent, Default)] #[derive(Component, Clone, Copy, Debug, ExtractComponent, Default)]
#[cfg_attr(feature = "reflect", derive(Reflect))]
#[require(XrSpaceVelocityFlags)] #[require(XrSpaceVelocityFlags)]
pub struct XrVelocity { pub struct XrVelocity {
/// Velocity of a space relative to it's reference space /// Velocity of a space relative to it's reference space
@@ -34,32 +40,30 @@ impl XrVelocity {
} }
} }
#[derive(Event, Clone, Copy, Deref, DerefMut)] #[derive(Message, Clone, Copy, Deref, DerefMut)]
pub struct XrDestroySpace(pub XrSpace); pub struct XrDestroySpace(pub XrSpace);
#[repr(transparent)] #[repr(transparent)]
#[derive( #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, Component, Deref, DerefMut, ExtractComponent)]
Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, Component, Deref, DerefMut, ExtractComponent, #[cfg_attr(feature = "reflect", derive(Reflect))]
)]
pub struct XrReferenceSpace(pub XrSpace); pub struct XrReferenceSpace(pub XrSpace);
#[repr(transparent)] #[repr(transparent)]
#[derive( #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, Resource, Deref, DerefMut, ExtractResource)]
Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, Resource, Deref, DerefMut, ExtractResource, #[cfg_attr(feature = "reflect", derive(Reflect))]
)]
pub struct XrPrimaryReferenceSpace(pub XrReferenceSpace); pub struct XrPrimaryReferenceSpace(pub XrReferenceSpace);
#[derive( #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, Component, ExtractComponent, Default)]
Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, Component, ExtractComponent, Default, #[cfg_attr(feature = "reflect", derive(Reflect))]
)]
pub struct XrSpaceLocationFlags { pub struct XrSpaceLocationFlags {
pub position_tracked: bool, pub position_tracked: bool,
pub rotation_tracked: bool, pub rotation_tracked: bool,
} }
#[derive( #[derive(
Clone, Copy, Hash, PartialEq, Eq, Reflect, Debug, Component, ExtractComponent, Default, Clone, Copy, Hash, PartialEq, Eq, Debug, Component, ExtractComponent, Default,
)] )]
#[cfg_attr(feature = "reflect", derive(Reflect))]
pub struct XrSpaceVelocityFlags { pub struct XrSpaceVelocityFlags {
pub linear_valid: bool, pub linear_valid: bool,
pub angular_valid: bool, pub angular_valid: bool,

View File

@@ -1,4 +0,0 @@
use bevy::math::Isometry3d;
#[deprecated = "Use Isometry3d instead"]
pub type XrPose = Isometry3d;

View File

@@ -9,12 +9,20 @@ description = "utils for bevy_mod_xr and bevy_mod_openxr"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
bevy = { workspace = true, features = ["bevy_gizmos"] } # bevy = { workspace = true, features = ["bevy_gizmos"] }
bevy_mod_xr.workspace = true bevy_mod_xr.workspace = true
bevy_mod_openxr.workspace = true bevy_mod_openxr.workspace = true
bevy_ecs.workspace=true
bevy_app.workspace=true
bevy_transform.workspace=true
bevy_color.workspace=true
bevy_gizmos.workspace=true
bevy_log.workspace=true
bevy_derive.workspace=true
bevy_math.workspace=true
[dev-dependencies] [dev-dependencies]
bevy = { workspace = true, default-features = true } bevy.workspace = true
[target.'cfg(not(target_family = "wasm"))'.dependencies] [target.'cfg(not(target_family = "wasm"))'.dependencies]
openxr.workspace = true openxr.workspace = true

View File

@@ -3,7 +3,7 @@ use bevy::{math::vec3, prelude::*};
use bevy_mod_openxr::{add_xr_plugins, helper_traits::ToQuat, resources::OxrViews}; use bevy_mod_openxr::{add_xr_plugins, helper_traits::ToQuat, resources::OxrViews};
use bevy_mod_xr::session::XrTrackingRoot; use bevy_mod_xr::session::XrTrackingRoot;
use bevy_xr_utils::xr_utils_actions::{ use bevy_xr_utils::xr_utils_actions::{
ActiveSet, XRUtilsAction, XRUtilsActionSet, XRUtilsActionState, XRUtilsActionSystemSet, ActiveSet, XRUtilsAction, XRUtilsActionSet, XRUtilsActionState, XRUtilsActionSystems,
XRUtilsActionsPlugin, XRUtilsBinding, XRUtilsActionsPlugin, XRUtilsBinding,
}; };
@@ -14,7 +14,7 @@ fn main() {
.add_systems(Startup, setup_scene) .add_systems(Startup, setup_scene)
.add_systems( .add_systems(
Startup, Startup,
create_action_entities.before(XRUtilsActionSystemSet::CreateEvents), create_action_entities.before(XRUtilsActionSystems::CreateEvents),
) )
.add_plugins(XRUtilsActionsPlugin) .add_plugins(XRUtilsActionsPlugin)
.add_systems(Update, read_action_with_marker_component) .add_systems(Update, read_action_with_marker_component)

View File

@@ -4,7 +4,7 @@ use bevy::prelude::*;
use bevy_mod_openxr::add_xr_plugins; use bevy_mod_openxr::add_xr_plugins;
use bevy_xr_utils::transform_utils::{self, SnapToPosition, SnapToRotation}; use bevy_xr_utils::transform_utils::{self, SnapToPosition, SnapToRotation};
use bevy_xr_utils::xr_utils_actions::{ use bevy_xr_utils::xr_utils_actions::{
ActiveSet, XRUtilsAction, XRUtilsActionSet, XRUtilsActionState, XRUtilsActionSystemSet, ActiveSet, XRUtilsAction, XRUtilsActionSet, XRUtilsActionState, XRUtilsActionSystems,
XRUtilsActionsPlugin, XRUtilsBinding, XRUtilsActionsPlugin, XRUtilsBinding,
}; };
@@ -17,15 +17,15 @@ fn main() -> AppExit {
.add_plugins(XRUtilsActionsPlugin) .add_plugins(XRUtilsActionsPlugin)
.add_systems( .add_systems(
Startup, Startup,
create_action_entities.before(XRUtilsActionSystemSet::CreateEvents), create_action_entities.before(XRUtilsActionSystems::CreateEvents),
) )
.add_systems( .add_systems(
Update, Update,
send_look_at_red_cube_event.after(XRUtilsActionSystemSet::SyncActionStates), send_look_at_red_cube_event.after(XRUtilsActionSystems::SyncActionStates),
) )
.add_systems( .add_systems(
Update, Update,
send_recenter.after(XRUtilsActionSystemSet::SyncActionStates), send_recenter.after(XRUtilsActionSystems::SyncActionStates),
) )
.insert_resource(AmbientLight { .insert_resource(AmbientLight {
brightness: 500.0, brightness: 500.0,

View File

@@ -1,4 +1,8 @@
use bevy::{color::palettes::css, prelude::*}; use bevy_app::{App, Plugin, PostUpdate};
use bevy_color::palettes::css;
use bevy_ecs::{component::Component, query::With, schedule::IntoScheduleConfigs as _, system::Query};
use bevy_gizmos::gizmos::Gizmos;
use bevy_transform::{TransformSystems, components::{GlobalTransform, Transform}};
#[derive(Clone, Copy, Component)] #[derive(Clone, Copy, Component)]
#[require(Transform)] #[require(Transform)]
@@ -8,10 +12,7 @@ pub struct GenericTrackerGizmoPlugin;
impl Plugin for GenericTrackerGizmoPlugin { impl Plugin for GenericTrackerGizmoPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems( app.add_systems(PostUpdate, draw_gizmos.after(TransformSystems::Propagate));
PostUpdate,
draw_gizmos.after(TransformSystem::TransformPropagate),
);
} }
} }

View File

@@ -1,6 +1,9 @@
use std::convert::identity; use std::convert::identity;
use bevy::prelude::*; use bevy_app::{App, Plugin, PreUpdate};
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::{component::Component, entity::Entity, query::With, resource::Resource, schedule::{IntoScheduleConfigs as _, common_conditions::resource_exists}, system::{Commands, Query, Res, ResMut}};
use bevy_log::{error, info};
use bevy_mod_openxr::{ use bevy_mod_openxr::{
resources::{OxrInstance, OxrSystemId}, resources::{OxrInstance, OxrSystemId},
session::OxrSession, session::OxrSession,

View File

@@ -1,4 +1,13 @@
use bevy::prelude::*; use bevy_app::{App, Plugin, PreUpdate, Startup};
use bevy_ecs::{
component::Component,
message::MessageWriter,
query::{With, Without},
resource::Resource,
schedule::IntoScheduleConfigs as _,
system::{Commands, Query, Res},
};
use bevy_math::{EulerRot, Isometry3d, Quat};
use bevy_mod_openxr::{ use bevy_mod_openxr::{
action_binding::OxrSuggestActionBinding, action_binding::OxrSuggestActionBinding,
action_set_attaching::OxrAttachActionSet, action_set_attaching::OxrAttachActionSet,
@@ -13,6 +22,7 @@ use bevy_mod_xr::{
session::{XrSessionCreated, XrTracker, XrTrackingRoot}, session::{XrSessionCreated, XrTracker, XrTrackingRoot},
spaces::{XrPrimaryReferenceSpace, XrReferenceSpace, XrSpaceSyncSet}, spaces::{XrPrimaryReferenceSpace, XrReferenceSpace, XrSpaceSyncSet},
}; };
use bevy_transform::components::Transform;
use openxr::Posef; use openxr::Posef;
//exernal api //exernal api
@@ -203,14 +213,9 @@ fn spawn_tracking_rig(
) { ) {
//head //head
let head_space = session let head_space = session
.create_reference_space(openxr::ReferenceSpaceType::VIEW, Transform::IDENTITY) .create_reference_space(openxr::ReferenceSpaceType::VIEW, Isometry3d::IDENTITY)
.unwrap(); .unwrap();
cmds.spawn(( cmds.spawn((Transform::default(), XrTracker, HeadXRSpace(head_space)));
Transform::default(),
Visibility::default(),
XrTracker,
HeadXRSpace(head_space),
));
// let local_floor = cmds.spawn((SpatialBundle::default(), LocalFloor)).id(); // let local_floor = cmds.spawn((SpatialBundle::default(), LocalFloor)).id();
let left_space = session let left_space = session
@@ -227,7 +232,7 @@ fn spawn_tracking_rig(
//TODO figure out how to make these better, specifically not be controller specific //TODO figure out how to make these better, specifically not be controller specific
pub fn suggest_action_bindings( pub fn suggest_action_bindings(
actions: Res<ControllerActions>, actions: Res<ControllerActions>,
mut bindings: EventWriter<OxrSuggestActionBinding>, mut bindings: MessageWriter<OxrSuggestActionBinding>,
) { ) {
bindings.write(OxrSuggestActionBinding { bindings.write(OxrSuggestActionBinding {
action: actions.left.as_raw(), action: actions.left.as_raw(),
@@ -241,11 +246,11 @@ pub fn suggest_action_bindings(
}); });
} }
fn sync_actions(actions: Res<ControllerActions>, mut sync: EventWriter<OxrSyncActionSet>) { fn sync_actions(actions: Res<ControllerActions>, mut sync: MessageWriter<OxrSyncActionSet>) {
sync.write(OxrSyncActionSet(actions.set.clone())); sync.write(OxrSyncActionSet(actions.set.clone()));
} }
fn attach_set(actions: Res<ControllerActions>, mut attach: EventWriter<OxrAttachActionSet>) { fn attach_set(actions: Res<ControllerActions>, mut attach: MessageWriter<OxrAttachActionSet>) {
attach.write(OxrAttachActionSet(actions.set.clone())); attach.write(OxrAttachActionSet(actions.set.clone()));
} }

View File

@@ -1,32 +1,36 @@
use bevy::prelude::*; use bevy_app::{App, Plugin, PostUpdate};
use bevy_ecs::{message::{Message, MessageReader}, query::With, system::{Query, ResMut}};
use bevy_log::debug;
use bevy_math::{Quat, Vec3};
use bevy_mod_openxr::{ use bevy_mod_openxr::{
helper_traits::{ToQuat, ToVec3}, helper_traits::{ToQuat, ToVec3},
resources::OxrViews, resources::OxrViews,
}; };
use bevy_mod_xr::session::XrTrackingRoot; use bevy_mod_xr::session::XrTrackingRoot;
use bevy_transform::components::Transform;
pub struct TransformUtilitiesPlugin; pub struct TransformUtilitiesPlugin;
impl Plugin for TransformUtilitiesPlugin { impl Plugin for TransformUtilitiesPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_event::<SnapToRotation>(); app.add_message::<SnapToRotation>();
app.add_event::<SnapToPosition>(); app.add_message::<SnapToPosition>();
app.add_systems(PostUpdate, handle_transform_events); app.add_systems(PostUpdate, handle_transform_events);
} }
} }
//events //events
#[derive(Event, Debug)] #[derive(Message, Debug)]
pub struct SnapToRotation(pub Quat); pub struct SnapToRotation(pub Quat);
#[derive(Event, Debug)] #[derive(Message, Debug)]
pub struct SnapToPosition(pub Vec3); pub struct SnapToPosition(pub Vec3);
pub fn handle_transform_events( pub fn handle_transform_events(
mut root_query: Query<&mut Transform, With<XrTrackingRoot>>, mut root_query: Query<&mut Transform, With<XrTrackingRoot>>,
views: ResMut<OxrViews>, views: ResMut<OxrViews>,
mut position_reader: EventReader<SnapToPosition>, mut position_reader: MessageReader<SnapToPosition>,
mut rotation_reader: EventReader<SnapToRotation>, mut rotation_reader: MessageReader<SnapToRotation>,
) { ) {
let result = root_query.single_mut(); let result = root_query.single_mut();
match result { match result {
@@ -52,11 +56,11 @@ pub fn handle_transform_events(
let root_rot = root_transform.rotation; let root_rot = root_transform.rotation;
let view_global_rotation = root_rot.mul_quat(view_rot).normalize(); let view_global_rotation = root_rot.mul_quat(view_rot).normalize();
let (global_view_yaw, _pitch, _roll) = let (global_view_yaw, _pitch, _roll) =
view_global_rotation.to_euler(bevy::math::EulerRot::YXZ); view_global_rotation.to_euler(bevy_math::EulerRot::YXZ);
let up = Vec3::Y; let up = Vec3::Y;
for rotation in rotation_reader.read() { for rotation in rotation_reader.read() {
let (target_yaw, _pitch, _roll) = let (target_yaw, _pitch, _roll) =
rotation.0.normalize().to_euler(bevy::math::EulerRot::YXZ); rotation.0.normalize().to_euler(bevy_math::EulerRot::YXZ);
let diff_yaw = target_yaw - global_view_yaw; let diff_yaw = target_yaw - global_view_yaw;
//build a rotation quat? //build a rotation quat?

View File

@@ -53,7 +53,9 @@
//! } //! }
//! //!
//! //!
use bevy::prelude::*; use bevy_app::{App, Plugin, PreUpdate, Startup, Update};
use bevy_ecs::{component::Component, entity::Entity, hierarchy::Children, message::MessageWriter, query::With, schedule::{IntoScheduleConfigs as _, SystemSet}, system::{Commands, Query, Res, ResMut}};
use bevy_log::info;
use bevy_mod_openxr::{ use bevy_mod_openxr::{
action_binding::OxrSuggestActionBinding, action_binding::OxrSuggestActionBinding,
action_set_attaching::OxrAttachActionSet, action_set_attaching::OxrAttachActionSet,
@@ -71,16 +73,16 @@ impl Plugin for XRUtilsActionsPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.configure_sets( app.configure_sets(
Startup, Startup,
XRUtilsActionSystemSet::CreateEvents.run_if(openxr_session_available), XRUtilsActionSystems::CreateEvents.run_if(openxr_session_available),
); );
app.configure_sets( app.configure_sets(
PreUpdate, PreUpdate,
XRUtilsActionSystemSet::SyncActionStates.run_if(openxr_session_running), XRUtilsActionSystems::SyncActionStates.run_if(openxr_session_running),
); );
app.add_systems( app.add_systems(
Startup, Startup,
create_openxr_events create_openxr_events
.in_set(XRUtilsActionSystemSet::CreateEvents) .in_set(XRUtilsActionSystems::CreateEvents)
.run_if(openxr_session_available), .run_if(openxr_session_available),
); );
app.add_systems( app.add_systems(
@@ -91,21 +93,21 @@ impl Plugin for XRUtilsActionsPlugin {
PreUpdate, PreUpdate,
sync_and_update_action_states_f32 sync_and_update_action_states_f32
.run_if(openxr_session_running) .run_if(openxr_session_running)
.in_set(XRUtilsActionSystemSet::SyncActionStates) .in_set(XRUtilsActionSystems::SyncActionStates)
.after(OxrActionSetSyncSet), .after(OxrActionSetSyncSet),
); );
app.add_systems( app.add_systems(
PreUpdate, PreUpdate,
sync_and_update_action_states_bool sync_and_update_action_states_bool
.run_if(openxr_session_running) .run_if(openxr_session_running)
.in_set(XRUtilsActionSystemSet::SyncActionStates) .in_set(XRUtilsActionSystems::SyncActionStates)
.after(OxrActionSetSyncSet), .after(OxrActionSetSyncSet),
); );
app.add_systems( app.add_systems(
PreUpdate, PreUpdate,
sync_and_update_action_states_vector sync_and_update_action_states_vector
.run_if(openxr_session_running) .run_if(openxr_session_running)
.in_set(XRUtilsActionSystemSet::SyncActionStates) .in_set(XRUtilsActionSystems::SyncActionStates)
.after(OxrActionSetSyncSet), .after(OxrActionSetSyncSet),
); );
} }
@@ -116,8 +118,8 @@ fn create_openxr_events(
actions_query: Query<(&XRUtilsAction, &Children)>, actions_query: Query<(&XRUtilsAction, &Children)>,
bindings_query: Query<&XRUtilsBinding>, bindings_query: Query<&XRUtilsBinding>,
instance: ResMut<OxrInstance>, instance: ResMut<OxrInstance>,
mut binding_writer: EventWriter<OxrSuggestActionBinding>, mut binding_writer: MessageWriter<OxrSuggestActionBinding>,
mut attach_writer: EventWriter<OxrAttachActionSet>, mut attach_writer: MessageWriter<OxrAttachActionSet>,
mut commands: Commands, mut commands: Commands,
) { ) {
//lets create some sets! //lets create some sets!
@@ -131,7 +133,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().copied() {
//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 +160,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().copied() {
//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 +199,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().copied() {
//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 +238,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().copied() {
//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();
@@ -260,7 +262,7 @@ fn create_openxr_events(
} }
fn sync_active_action_sets( fn sync_active_action_sets(
mut sync_set: EventWriter<OxrSyncActionSet>, mut sync_set: MessageWriter<OxrSyncActionSet>,
active_action_set_query: Query<&XRUtilsActionSetReference, With<ActiveSet>>, active_action_set_query: Query<&XRUtilsActionSetReference, With<ActiveSet>>,
) { ) {
for set in &active_action_set_query { for set in &active_action_set_query {
@@ -344,7 +346,7 @@ fn sync_and_update_action_states_vector(
} }
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)] #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, SystemSet)]
pub enum XRUtilsActionSystemSet { pub enum XRUtilsActionSystems {
/// Runs in Startup /// Runs in Startup
CreateEvents, CreateEvents,
/// Runs in PreUpdate /// Runs in PreUpdate