diff --git a/examples/demo/manifest.yaml b/examples/demo/manifest.yaml
index 730187a..6cba5b8 100644
--- a/examples/demo/manifest.yaml
+++ b/examples/demo/manifest.yaml
@@ -13,6 +13,7 @@ android:
# required: true
uses_permission:
- name: "com.oculus.permission.HAND_TRACKING"
+ - name: "android.permission.INTERNET"
application:
label: "Bevy Openxr Android"
theme: "@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen"
diff --git a/examples/demo/src/lib.rs b/examples/demo/src/lib.rs
index 2867a23..e7feb94 100644
--- a/examples/demo/src/lib.rs
+++ b/examples/demo/src/lib.rs
@@ -19,7 +19,7 @@ use bevy_oxr::{
graphics::{extensions::XrExtensions, XrAppInfo, XrPreferdBlendMode},
input::XrInput,
resources::{XrFrameState, XrInstance, XrSession},
- xr_init::{xr_only, XrEnableRequest, XrEnableStatus},
+ xr_init::{xr_only, XrStatus},
xr_input::{
actions::XrActionSets,
debug_gizmos::OpenXrDebugRenderer,
@@ -41,18 +41,18 @@ use bevy_oxr::{
DefaultXrPlugins,
};
-fn input_stuff(
- keys: Res>,
- status: Res,
- mut request: EventWriter,
-) {
- if keys.just_pressed(KeyCode::Space) {
- match status.into_inner() {
- XrEnableStatus::Enabled => request.send(XrEnableRequest::TryDisable),
- XrEnableStatus::Disabled => request.send(XrEnableRequest::TryEnable),
- }
- }
-}
+// fn input_stuff(
+// keys: Res>,
+// status: Res,
+// mut request: EventWriter,
+// ) {
+// if keys.just_pressed(KeyCode::Space) {
+// match status.into_inner() {
+// XrEnableStatus::Enabled => request.send(XrEnableRequest::TryDisable),
+// XrEnableStatus::Disabled => request.send(XrEnableRequest::TryEnable),
+// }
+// }
+// }
mod setup;
use crate::setup::setup_scene;
@@ -66,7 +66,7 @@ pub fn main() {
let mut app = App::new();
let mut xr_extensions = XrExtensions::default();
- app.add_systems(Update, input_stuff)
+ app
//lets get the usual diagnostic stuff added
.add_plugins(LogDiagnosticsPlugin::default())
.add_plugins(FrameTimeDiagnosticsPlugin)
diff --git a/src/graphics/mod.rs b/src/graphics/mod.rs
index 24e80ff..33dc317 100644
--- a/src/graphics/mod.rs
+++ b/src/graphics/mod.rs
@@ -103,7 +103,7 @@ pub fn try_full_init(
)> {
let mut system_state: SystemState>> =
SystemState::new(world);
- let primary_window = system_state.get(&world).get_single().ok().cloned();
+ let primary_window = system_state.get(world).get_single().ok().cloned();
let (
xr_instance,
setup_info,
diff --git a/src/lib.rs b/src/lib.rs
index 4705e54..3b52be6 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -6,10 +6,13 @@ pub mod resources;
pub mod xr_init;
pub mod xr_input;
+use std::fs::File;
+use std::io::{BufWriter, Write};
+use std::net::TcpStream;
use std::sync::atomic::AtomicBool;
use std::sync::{Arc, Mutex};
-use crate::xr_init::RenderRestartPlugin;
+use crate::xr_init::{StartXrSession, XrInitPlugin};
use crate::xr_input::hands::hand_tracking::DisableHandTracking;
use crate::xr_input::oculus_touch::ActionSets;
use bevy::app::{AppExit, PluginGroupBuilder};
@@ -18,22 +21,25 @@ use bevy::prelude::*;
use bevy::render::camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews};
use bevy::render::extract_resource::ExtractResourcePlugin;
use bevy::render::pipelined_rendering::PipelinedRenderingPlugin;
-use bevy::render::renderer::{render_system, RenderInstance};
+use bevy::render::renderer::RenderInstance;
use bevy::render::settings::RenderCreation;
use bevy::render::{Render, RenderApp, RenderPlugin, RenderSet};
use bevy::window::{PresentMode, PrimaryWindow, RawHandleWrapper};
-use eyre::anyhow;
use graphics::extensions::XrExtensions;
use graphics::{XrAppInfo, XrPreferdBlendMode};
use input::XrInput;
use openxr as xr;
// use passthrough::{start_passthrough, supports_passthrough, XrPassthroughLayer};
use resources::*;
-use xr::{FormFactor, FrameWaiter};
-use xr_init::{xr_only, XrEnableStatus, XrRenderData};
+use xr::FormFactor;
+use xr_init::{
+ xr_only, xr_render_only, CleanupXrData, XrEarlyInitPlugin, XrShouldRender, XrStatus,
+};
use xr_input::controllers::XrControllerType;
use xr_input::hands::emulated::HandEmulationPlugin;
use xr_input::hands::hand_tracking::{HandTrackingData, HandTrackingPlugin};
+use xr_input::hands::XrHandPlugins;
+use xr_input::xr_camera::XrCameraType;
use xr_input::OpenXrInput;
const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
@@ -49,141 +55,119 @@ pub struct OpenXrPlugin {
app_info: XrAppInfo,
}
-#[derive(Resource)]
-pub struct FutureXrResources(
- pub Arc<
- Mutex<
- Option<(
- XrInstance,
- XrSession,
- XrEnvironmentBlendMode,
- XrResolution,
- XrFormat,
- XrSessionRunning,
- XrSwapchain,
- XrInput,
- XrViews,
- XrFrameState,
- )>,
- >,
- >,
-);
-
impl Plugin for OpenXrPlugin {
fn build(&self, app: &mut App) {
app.insert_resource(XrSessionRunning::new(AtomicBool::new(false)));
- // #[cfg(target_os = "android")]
- // {
- // let ctx = ndk_context::android_context();
- // let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.unwrap();
- // let env = vm.attach_current_thread_permanently();
- // }
#[cfg(not(target_arch = "wasm32"))]
- match graphics::try_full_init(
- &mut app.world,
+ match graphics::initialize_xr_instance(
+ SystemState::>>::new(&mut app.world)
+ .get(&app.world)
+ .get_single()
+ .ok()
+ .cloned(),
self.reqeusted_extensions.clone(),
self.prefered_blend_mode,
self.app_info.clone(),
) {
- Ok((device, queue, adapter_info, render_adapter, instance)) => {
+ Ok((
+ xr_instance,
+ oxr_session_setup_info,
+ blend_mode,
+ device,
+ queue,
+ adapter_info,
+ render_adapter,
+ instance,
+ )) => {
debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
debug!("Configured wgpu adapter Features: {:#?}", device.features());
- warn!("Starting in Xr");
+ warn!("Starting with OpenXR Instance");
app.insert_resource(ActionSets(vec![]));
+ app.insert_resource(xr_instance);
+ app.insert_resource(blend_mode);
+ app.insert_non_send_resource(oxr_session_setup_info);
+ let render_instance = RenderInstance(instance.into());
+ app.insert_resource(render_instance.clone());
app.add_plugins(RenderPlugin {
render_creation: RenderCreation::Manual(
device,
queue,
adapter_info,
render_adapter,
- instance,
+ render_instance,
),
});
- app.insert_resource(XrEnableStatus::Disabled);
+ app.insert_resource(XrStatus::Disabled);
+ app.world.send_event(StartXrSession);
}
Err(err) => {
- warn!("OpenXR Failed to initialize: {}", err);
+ warn!("OpenXR Instance Failed to initialize: {}", err);
app.add_plugins(RenderPlugin::default());
- app.add_plugins(ExtractResourcePlugin::::default());
- app.insert_resource(XrEnableStatus::Disabled);
+ app.insert_resource(XrStatus::NoInstance);
}
}
- // app.add_systems(PreUpdate, mr_test);
#[cfg(target_arch = "wasm32")]
{
app.add_plugins(RenderPlugin::default());
- app.insert_resource(XrEnableStatus::Disabled);
+ app.insert_resource(XrStatus::Disabled);
}
- app.add_plugins(ExtractResourcePlugin::::default());
app.add_systems(
PreUpdate,
- (xr_poll_events, xr_begin_frame.run_if(xr_only())).chain(),
+ xr_poll_events.run_if(|status: Res| *status != XrStatus::NoInstance),
);
- }
-
- fn finish(&self, app: &mut App) {
- // TODO: Split this up into the indevidual resources
- // app.world.get_resource::() == Some(&XrEnableStatus::Enabled)
- if true {
- warn!("finished xr init");
- let xr_instance = app
- .world
- .get_resource::()
- .expect("should exist");
- let xr_session = app.world.get_resource::().expect("should exist");
- let hands = xr_instance.exts().ext_hand_tracking.is_some()
- && xr_instance
- .supports_hand_tracking(
- xr_instance
- .system(FormFactor::HEAD_MOUNTED_DISPLAY)
- .unwrap(),
- )
- .is_ok_and(|v| v);
- if hands {
- app.insert_resource(HandTrackingData::new(xr_session).unwrap());
- } else {
- app.insert_resource(DisableHandTracking::Both);
- }
- let xr_swapchain = app
- .world
- .get_resource::()
- .expect("should exist");
- let xr_resolution = app
- .world
- .get_resource::()
- .expect("should exist");
- let xr_format = app.world.get_resource::().expect("should exist");
-
- let (left, right) = xr_swapchain.get_render_views();
- let left = ManualTextureView {
- texture_view: left.into(),
- size: **xr_resolution,
- format: **xr_format,
- };
- let right = ManualTextureView {
- texture_view: right.into(),
- size: **xr_resolution,
- format: **xr_format,
- };
- let mut manual_texture_views = app.world.resource_mut::();
- manual_texture_views.insert(LEFT_XR_TEXTURE_HANDLE, left);
- manual_texture_views.insert(RIGHT_XR_TEXTURE_HANDLE, right);
- drop(manual_texture_views);
- let render_app = app.sub_app_mut(RenderApp);
- render_app.add_systems(
- Render,
- (
- post_frame
- .run_if(xr_only())
- .before(render_system)
- .after(RenderSet::ExtractCommands),
- end_frame.run_if(xr_only()).after(render_system),
- ),
- );
- }
+ app.add_systems(
+ PreUpdate,
+ (
+ xr_reset_should_render,
+ apply_deferred,
+ xr_wait_frame.run_if(xr_only()),
+ apply_deferred,
+ locate_views.run_if(xr_only()),
+ apply_deferred,
+ )
+ .chain()
+ .after(xr_poll_events),
+ );
+ let render_app = app.sub_app_mut(RenderApp);
+ render_app.add_systems(
+ Render,
+ xr_begin_frame
+ .run_if(xr_only())
+ .run_if(xr_render_only())
+ .after(RenderSet::ExtractCommands)
+ .before(xr_pre_frame),
+ );
+ render_app.add_systems(
+ Render,
+ xr_pre_frame
+ .run_if(xr_only())
+ .run_if(xr_render_only())
+ .in_set(RenderSet::Prepare),
+ );
+ render_app.add_systems(
+ Render,
+ (locate_views, xr_input::xr_camera::xr_camera_head_sync)
+ .chain()
+ .run_if(xr_only())
+ .run_if(xr_render_only())
+ .in_set(RenderSet::Prepare),
+ );
+ render_app.add_systems(
+ Render,
+ xr_end_frame
+ .run_if(xr_only())
+ .run_if(xr_render_only())
+ .after(RenderSet::Render),
+ );
+ render_app.insert_resource(TcpConnection(
+ TcpStream::connect("192.168.2.100:6969").unwrap(),
+ ));
}
}
+#[derive(Resource)]
+struct TcpConnection(TcpStream);
+
#[derive(Default)]
pub struct DefaultXrPlugins {
pub reqeusted_extensions: XrExtensions,
@@ -203,11 +187,10 @@ impl PluginGroup for DefaultXrPlugins {
app_info: self.app_info.clone(),
})
.add_after::(OpenXrInput::new(XrControllerType::OculusTouch))
- .add_before::(RenderRestartPlugin)
- .add(HandEmulationPlugin)
- .add(HandTrackingPlugin)
+ .add_after::(XrInitPlugin)
+ .add_before::(XrEarlyInitPlugin)
+ .add(XrHandPlugins)
.add(XrResourcePlugin)
- // .add(xr_init::RenderRestartPlugin)
.set(WindowPlugin {
#[cfg(not(target_os = "android"))]
primary_window: Some(Window {
@@ -227,11 +210,16 @@ impl PluginGroup for DefaultXrPlugins {
}
}
-pub fn xr_poll_events(
+fn xr_reset_should_render(mut should: ResMut) {
+ **should = false;
+}
+
+fn xr_poll_events(
instance: Option>,
session: Option>,
session_running: Res,
mut app_exit: EventWriter,
+ mut cleanup_xr: EventWriter,
) {
if let (Some(instance), Some(session)) = (instance, session) {
let _span = info_span!("xr_poll_events");
@@ -251,6 +239,7 @@ pub fn xr_poll_events(
xr::SessionState::STOPPING => {
session.end().unwrap();
session_running.store(false, std::sync::atomic::Ordering::Relaxed);
+ cleanup_xr.send_default();
}
xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => {
// app_exit.send(AppExit);
@@ -260,7 +249,9 @@ pub fn xr_poll_events(
_ => {}
}
}
- InstanceLossPending(_) => return,
+ InstanceLossPending(_) => {
+ app_exit.send_default();
+ }
EventsLost(e) => {
warn!("lost {} XR events", e.lost_event_count());
}
@@ -270,13 +261,15 @@ pub fn xr_poll_events(
}
}
-pub fn xr_begin_frame(
- session: Res,
+fn xr_begin_frame(swapchain: Res) {
+ let _span = info_span!("xr_begin_frame").entered();
+ swapchain.begin().unwrap()
+}
+
+pub fn xr_wait_frame(
mut frame_state: ResMut,
mut frame_waiter: ResMut,
- swapchain: Res,
- mut views: ResMut,
- input: Res,
+ mut should_render: ResMut,
) {
{
let _span = info_span!("xr_wait_frame").entered();
@@ -287,21 +280,11 @@ pub fn xr_begin_frame(
return;
}
};
- }
- {
- let _span = info_span!("xr_begin_frame").entered();
- swapchain.begin().unwrap()
- }
- {
- let _span = info_span!("xr_locate_views").entered();
- **views = session
- .locate_views(VIEW_TYPE, frame_state.predicted_display_time, &input.stage)
- .unwrap()
- .1;
+ **should_render = frame_state.should_render;
}
}
-pub fn post_frame(
+pub fn xr_pre_frame(
resolution: Res,
format: Res,
swapchain: Res,
@@ -313,7 +296,9 @@ pub fn post_frame(
}
{
let _span = info_span!("xr_wait_image").entered();
+ info!("wait image");
swapchain.wait_image().unwrap();
+ info!("waited image");
}
{
let _span = info_span!("xr_update_manual_texture_views").entered();
@@ -333,36 +318,51 @@ pub fn post_frame(
}
}
-pub fn end_frame(
- xr_frame_state: Option>,
- views: Option>,
- input: Option>,
- swapchain: Option>,
- resolution: Option>,
- environment_blend_mode: Option>,
- // _main_thread: NonSend<()>,
- #[cfg(target_os = "android")] mut attached: Local,
- // passthrough_layer: Option>,
+pub fn xr_end_frame(
+ xr_frame_state: Res,
+ views: Res,
+ input: Res,
+ swapchain: Res,
+ resolution: Res,
+ environment_blend_mode: Res,
+ mut connection: ResMut,
+ cams: Query<(&Transform, &XrCameraType)>,
) {
- let xr_frame_state = xr_frame_state.unwrap();
- let views = views.unwrap();
- let input = input.unwrap();
- let swapchain = swapchain.unwrap();
- let resolution = resolution.unwrap();
- let environment_blend_mode = environment_blend_mode.unwrap();
-
#[cfg(target_os = "android")]
- // if !*attached {
{
let ctx = ndk_context::android_context();
let vm = unsafe { jni::JavaVM::from_raw(ctx.vm().cast()) }.unwrap();
let env = vm.attach_current_thread_as_daemon();
- *attached = true;
}
{
let _span = info_span!("xr_release_image").entered();
swapchain.release_image().unwrap();
}
+ let mut cam = None;
+ for (t, c) in &cams {
+ if *c == XrCameraType::Xr(xr_input::xr_camera::Eye::Left) {
+ cam = Some(*t);
+ break;
+ }
+ }
+ let _ = std::writeln!(
+ &mut connection.0,
+ "{},{},{},{},{},{},{},{},{},{},{},{},{},{}",
+ views[0].pose.position.x,
+ views[0].pose.position.y,
+ views[0].pose.position.z,
+ views[0].pose.orientation.x,
+ views[0].pose.orientation.y,
+ views[0].pose.orientation.z,
+ views[0].pose.orientation.w,
+ cam.unwrap().translation.x,
+ cam.unwrap().translation.y,
+ cam.unwrap().translation.z,
+ cam.unwrap().rotation.x,
+ cam.unwrap().rotation.y,
+ cam.unwrap().rotation.z,
+ cam.unwrap().rotation.w,
+ );
{
let _span = info_span!("xr_end_frame").entered();
let result = swapchain.end(
diff --git a/src/resources.rs b/src/resources.rs
index 584cb16..da72cf6 100644
--- a/src/resources.rs
+++ b/src/resources.rs
@@ -5,7 +5,7 @@ use std::sync::Mutex;
use crate::input::XrInput;
// use crate::passthrough::XrPassthroughLayer;
use crate::resource_macros::*;
-use crate::xr_init::XrEnableStatus;
+use crate::xr_init::XrStatus;
use bevy::prelude::*;
use bevy::render::extract_resource::ExtractResourcePlugin;
use openxr as xr;
@@ -27,7 +27,6 @@ pub(crate) struct VulkanOXrSessionSetupInfo {
pub(crate) vk_instance_ptr: *const c_void,
pub(crate) queue_family_index: u32,
pub(crate) xr_system_id: xr::SystemId,
- // pub(crate) swapchain_create_info: xr::SwapchainCreateInfo
}
pub(crate) enum OXrSessionSetupInfo {
@@ -46,6 +45,7 @@ impl Plugin for XrResourcePlugin {
app.add_plugins(ExtractResourcePlugin::::default());
app.add_plugins(ExtractResourcePlugin::::default());
app.add_plugins(ExtractResourcePlugin::::default());
+ app.add_plugins(ExtractResourcePlugin::::default());
}
}
@@ -219,7 +219,6 @@ impl SwapchainInner {
// }
// None =>
- info!("swapchain stream lock");
let r = self.stream.lock().unwrap().end(
predicted_display_time,
environment_blend_mode,
@@ -244,7 +243,6 @@ impl SwapchainInner {
),
])],
);
- info!("swapchain stream done");
r
// }
}
diff --git a/src/xr_init.rs b/src/xr_init.rs
deleted file mode 100644
index fb4917a..0000000
--- a/src/xr_init.rs
+++ /dev/null
@@ -1,433 +0,0 @@
-// Just a lot of code that is meant for something way more complex but hey.
-// maybe will work on that soon
-
-use std::sync::Arc;
-
-use bevy::{
- ecs::schedule::{ExecutorKind, ScheduleLabel},
- prelude::*,
- render::{
- extract_resource::{ExtractResource, ExtractResourcePlugin},
- renderer::{
- self, RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue,
- },
- settings::WgpuSettings,
- },
- window::{PrimaryWindow, RawHandleWrapper},
-};
-use wgpu::Instance;
-
-use crate::{
- graphics,
- input::XrInput,
- resources::{
- OXrSessionSetupInfo, XrEnvironmentBlendMode, XrFormat, XrFrameState, XrInstance,
- XrResolution, XrSession, XrSessionRunning, XrSwapchain, XrViews,
- },
-};
-
-#[derive(Resource, Clone)]
-pub struct RenderCreationData {
- pub device: RenderDevice,
- pub queue: RenderQueue,
- pub adapter_info: RenderAdapterInfo,
- pub render_adapter: RenderAdapter,
- pub instance: Arc,
-}
-
-#[derive(Resource, Clone, ExtractResource)]
-pub struct XrRenderData {
- pub xr_instance: XrInstance,
- pub xr_session: XrSession,
- pub xr_blend_mode: XrEnvironmentBlendMode,
- pub xr_resolution: XrResolution,
- pub xr_format: XrFormat,
- pub xr_session_running: XrSessionRunning,
- // pub xr_frame_waiter: XrFrameWaiter,
- pub xr_swapchain: XrSwapchain,
- pub xr_input: XrInput,
- pub xr_views: XrViews,
- pub xr_frame_state: XrFrameState,
-}
-
-#[derive(Event, Clone, Copy, Debug)]
-pub enum XrEnableRequest {
- TryEnable,
- TryDisable,
-}
-#[derive(Resource, Event, Copy, Clone, PartialEq, Eq, Reflect, ExtractResource)]
-pub enum XrEnableStatus {
- Enabled,
- Disabled,
-}
-
-#[derive(Resource, Event, Copy, Clone, PartialEq, Eq, Debug, ExtractResource)]
-pub enum XrNextEnabledState {
- Enabled,
- Disabled,
-}
-
-pub struct RenderRestartPlugin;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrPreSetup;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrSetup;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrPrePostSetup;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrPostSetup;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrPreCleanup;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrCleanup;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrPostCleanup;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrPreRenderUpdate;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrRenderUpdate;
-
-#[derive(Debug, ScheduleLabel, Clone, Copy, Hash, PartialEq, Eq)]
-pub struct XrPostRenderUpdate;
-
-pub fn xr_only() -> impl FnMut(Option>, Res) -> bool {
- |status, running| {
- resource_exists_and_equals(XrEnableStatus::Enabled)(status)
- && running.load(std::sync::atomic::Ordering::Relaxed)
- }
-}
-
-impl Plugin for RenderRestartPlugin {
- fn build(&self, app: &mut App) {
- add_schedules(app);
- app.add_plugins(ExtractResourcePlugin::::default())
- .add_event::()
- .add_event::()
- .add_event::()
- .add_event::()
- .add_systems(
- PreUpdate,
- setup_xr
- .run_if(|running: Res| {
- running.load(std::sync::atomic::Ordering::Relaxed)
- })
- .run_if(run_once()),
- )
- .add_systems(
- PostUpdate,
- update_xr_stuff.run_if(on_event::()),
- )
- .add_systems(XrPreRenderUpdate, decide_next_xr_state)
- .add_systems(XrPostRenderUpdate, clear_events)
- .add_systems(
- XrRenderUpdate,
- (
- cleanup_xr.run_if(resource_exists_and_equals(XrNextEnabledState::Disabled)),
- // handle_xr_enable_requests,
- apply_deferred,
- setup_xr, /* .run_if(resource_exists_and_equals(XrEnableStatus::Enabled)) */
- )
- .chain(),
- )
- .add_systems(XrCleanup, cleanup_oxr_session);
- app.add_systems(
- PostUpdate,
- start_xr_session.run_if(on_event::()),
- );
- app.add_systems(
- PostUpdate,
- stop_xr_session.run_if(on_event::()),
- );
- }
-}
-
-fn clear_events(mut events: ResMut>) {
- events.clear();
-}
-
-fn add_schedules(app: &mut App) {
- let schedules = [
- Schedule::new(XrPreSetup),
- Schedule::new(XrSetup),
- Schedule::new(XrPrePostSetup),
- Schedule::new(XrPostSetup),
- Schedule::new(XrPreRenderUpdate),
- Schedule::new(XrRenderUpdate),
- Schedule::new(XrPostRenderUpdate),
- Schedule::new(XrPreCleanup),
- Schedule::new(XrCleanup),
- Schedule::new(XrPostCleanup),
- ];
- for mut schedule in schedules {
- schedule.set_executor_kind(ExecutorKind::SingleThreaded);
- schedule.set_apply_final_deferred(true);
- app.add_schedule(schedule);
- }
-}
-
-pub fn setup_xr(world: &mut World) {
- info!("running setup schedule :3");
- world.insert_resource(XrEnableStatus::Enabled);
- world.run_schedule(XrPreSetup);
- world.run_schedule(XrSetup);
- world.run_schedule(XrPrePostSetup);
- world.run_schedule(XrPostSetup);
-}
-fn cleanup_xr(world: &mut World) {
- world.run_schedule(XrPreCleanup);
- world.run_schedule(XrCleanup);
- world.run_schedule(XrPostCleanup);
-}
-
-fn cleanup_oxr_session(xr_status: Option>, session: Option>) {
- if let (Some(XrEnableStatus::Disabled), Some(s)) = (xr_status.map(|v| v.into_inner()), session)
- {
- s.into_inner().request_exit().unwrap();
- }
-}
-
-pub fn update_xr_stuff(world: &mut World) {
- world.run_schedule(XrPreRenderUpdate);
- world.run_schedule(XrRenderUpdate);
- world.run_schedule(XrPostRenderUpdate);
-}
-
-#[derive(Event, Clone, Copy, Default)]
-pub struct StartXrSession;
-
-#[derive(Event, Clone, Copy, Default)]
-pub struct EndXrSession;
-
-fn start_xr_session(
- mut commands: Commands,
- instance: Res,
- primary_window: Query<&RawHandleWrapper, With>,
- setup_info: NonSend,
- render_device: Res,
- render_adapter: Res,
- render_instance: Res,
-) {
- let (
- xr_session,
- xr_resolution,
- xr_format,
- xr_session_running,
- xr_frame_waiter,
- xr_swapchain,
- xr_input,
- xr_views,
- xr_frame_state,
- ) = match graphics::start_xr_session(
- primary_window.get_single().cloned().ok(),
- &setup_info,
- &instance,
- &render_device,
- &render_adapter,
- &render_instance,
- ) {
- Ok(data) => data,
- Err(err) => {
- error!("Unable to start OpenXR Session: {}", err);
- return;
- }
- };
- commands.insert_resource(xr_session);
- commands.insert_resource(xr_resolution);
- commands.insert_resource(xr_format);
- commands.insert_resource(xr_session_running);
- commands.insert_resource(xr_frame_waiter);
- commands.insert_resource(xr_swapchain);
- commands.insert_resource(xr_input);
- commands.insert_resource(xr_views);
- commands.insert_resource(xr_frame_state);
-}
-
-fn stop_xr_session(mut commands: Commands, session: ResMut) {
- match session.request_exit() {
- Ok(_) => {}
- Err(err) => {
- error!("Error while trying to request session exit: {}", err)
- }
- }
-}
-
-// fn handle_xr_enable_requests(
-// primary_window: Query<&RawHandleWrapper, With>,
-// mut commands: Commands,
-// next_state: Res,
-// on_main: Option>,
-// ) {
-// // Just to force this system onto the main thread because of unsafe code
-// let _ = on_main;
-//
-// let (creation_data, xr_data) = match next_state.into_inner() {
-// XrNextEnabledState::Enabled => {
-// let (
-// device,
-// queue,
-// adapter_info,
-// render_adapter,
-// instance,
-// xr_instance,
-// session,
-// blend_mode,
-// resolution,
-// format,
-// session_running,
-// frame_waiter,
-// swapchain,
-// input,
-// views,
-// frame_state,
-// ) = graphics::initialize_xr_graphics(primary_window.get_single().ok().cloned())
-// .unwrap();
-//
-// commands.insert_resource(XrEnableStatus::Enabled);
-// (
-// RenderCreationData {
-// device,
-// queue,
-// adapter_info,
-// render_adapter,
-// instance: Arc::new(instance),
-// },
-// Some(XrRenderData {
-// xr_instance,
-// xr_session: session,
-// xr_blend_mode: blend_mode,
-// xr_resolution: resolution,
-// xr_format: format,
-// xr_session_running: session_running,
-// xr_frame_waiter: frame_waiter,
-// xr_swapchain: swapchain,
-// xr_input: input,
-// xr_views: views,
-// xr_frame_state: frame_state,
-// }),
-// )
-// }
-// XrNextEnabledState::Disabled => (
-// init_non_xr_graphics(primary_window.get_single().ok().cloned()),
-// None,
-// ),
-// };
-//
-// commands.insert_resource(creation_data.device);
-// commands.insert_resource(creation_data.queue);
-// commands.insert_resource(RenderInstance(creation_data.instance));
-// commands.insert_resource(creation_data.adapter_info);
-// commands.insert_resource(creation_data.render_adapter);
-//
-// if let Some(xr_data) = xr_data {
-// // TODO: Remove this lib.rs:144
-// commands.insert_resource(xr_data.clone());
-//
-// commands.insert_resource(xr_data.xr_instance);
-// commands.insert_resource(xr_data.xr_session);
-// commands.insert_resource(xr_data.xr_blend_mode);
-// commands.insert_resource(xr_data.xr_resolution);
-// commands.insert_resource(xr_data.xr_format);
-// commands.insert_resource(xr_data.xr_session_running);
-// commands.insert_resource(xr_data.xr_frame_waiter);
-// commands.insert_resource(xr_data.xr_input);
-// commands.insert_resource(xr_data.xr_views);
-// commands.insert_resource(xr_data.xr_frame_state);
-// commands.insert_resource(xr_data.xr_swapchain);
-// } else {
-// commands.remove_resource::();
-//
-// commands.remove_resource::();
-// commands.remove_resource::();
-// commands.remove_resource::();
-// commands.remove_resource::();
-// commands.remove_resource::();
-// commands.remove_resource::();
-// commands.remove_resource::();
-// commands.remove_resource::();
-// commands.remove_resource::();
-// commands.remove_resource::();
-// commands.remove_resource::();
-// }
-// }
-
-fn decide_next_xr_state(
- mut commands: Commands,
- mut events: EventReader,
- xr_status: Option>,
-) {
- info!("hm");
- let request = match events.read().next() {
- Some(v) => v,
- None => return,
- };
- info!("ok");
- match (request, xr_status.as_deref()) {
- (XrEnableRequest::TryEnable, Some(XrEnableStatus::Enabled)) => {
- info!("Xr Already Enabled! ignoring request");
- return;
- }
- (XrEnableRequest::TryDisable, Some(XrEnableStatus::Disabled)) => {
- info!("Xr Already Disabled! ignoring request");
- return;
- }
- // (_, Some(XrEnableStatus::Waiting)) => {
- // info!("Already Handling Request! ignoring request");
- // return;
- // }
- _ => {}
- }
- let r = match request {
- XrEnableRequest::TryEnable => XrNextEnabledState::Enabled,
- XrEnableRequest::TryDisable => XrNextEnabledState::Disabled,
- };
- info!("{:#?}", r);
- commands.insert_resource(r);
-}
-
-pub fn init_non_xr_graphics(primary_window: Option) -> RenderCreationData {
- let settings = WgpuSettings::default();
-
- let async_renderer = async move {
- let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
- // Probably a bad idea unwraping here but on the other hand no backends
- backends: settings.backends.unwrap(),
- dx12_shader_compiler: settings.dx12_shader_compiler.clone(),
- });
- let surface = primary_window.map(|wrapper| unsafe {
- // SAFETY: Plugins should be set up on the main thread.
- let handle = wrapper.get_handle();
- instance
- .create_surface(&handle)
- .expect("Failed to create wgpu surface")
- });
-
- let request_adapter_options = wgpu::RequestAdapterOptions {
- power_preference: settings.power_preference,
- compatible_surface: surface.as_ref(),
- ..Default::default()
- };
-
- let (device, queue, adapter_info, render_adapter) =
- renderer::initialize_renderer(&instance, &settings, &request_adapter_options).await;
- debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
- debug!("Configured wgpu adapter Features: {:#?}", device.features());
- RenderCreationData {
- device,
- queue,
- adapter_info,
- render_adapter,
- instance: Arc::new(instance),
- }
- };
- // No need for wasm in bevy_oxr web xr would be a different crate
- futures_lite::future::block_on(async_renderer)
-}
diff --git a/src/xr_input/hands/mod.rs b/src/xr_input/hands/mod.rs
index 06eb5c1..fa85cf8 100644
--- a/src/xr_input/hands/mod.rs
+++ b/src/xr_input/hands/mod.rs
@@ -1,6 +1,15 @@
use bevy::{app::PluginGroupBuilder, prelude::*};
+use openxr::FormFactor;
-use self::{emulated::HandEmulationPlugin, hand_tracking::HandTrackingPlugin};
+use crate::{
+ resources::{XrInstance, XrSession},
+ xr_init::XrPreSetup,
+};
+
+use self::{
+ emulated::HandEmulationPlugin,
+ hand_tracking::{DisableHandTracking, HandTrackingData, HandTrackingPlugin},
+};
pub mod common;
pub mod emulated;
@@ -8,12 +17,35 @@ pub mod hand_tracking;
pub struct XrHandPlugins;
-impl PluginGroup for XrHandPlugins {
- fn build(self) -> PluginGroupBuilder {
- PluginGroupBuilder::start::()
- .add(HandTrackingPlugin)
- .add(HandEmulationPlugin)
- .build()
+impl Plugin for XrHandPlugins {
+ fn build(&self, app: &mut App) {
+ app.add_plugins(HandTrackingPlugin)
+ .add_plugins(HandPlugin)
+ .add_plugins(HandEmulationPlugin);
+ }
+}
+
+pub struct HandPlugin;
+
+impl Plugin for HandPlugin {
+ fn build(&self, app: &mut App) {
+ app.add_systems(XrPreSetup, check_for_handtracking);
+ }
+}
+
+fn check_for_handtracking(
+ mut commands: Commands,
+ instance: Res,
+ session: Res,
+) {
+ let hands = instance.exts().ext_hand_tracking.is_some()
+ && instance
+ .supports_hand_tracking(instance.system(FormFactor::HEAD_MOUNTED_DISPLAY).unwrap())
+ .is_ok_and(|v| v);
+ if hands {
+ commands.insert_resource(HandTrackingData::new(&session).unwrap());
+ } else {
+ commands.insert_resource(DisableHandTracking::Both);
}
}
diff --git a/src/xr_input/mod.rs b/src/xr_input/mod.rs
index 540f2e2..ac2e13b 100644
--- a/src/xr_input/mod.rs
+++ b/src/xr_input/mod.rs
@@ -10,11 +10,11 @@ pub mod trackers;
pub mod xr_camera;
use crate::resources::{XrInstance, XrSession};
-use crate::xr_begin_frame;
-use crate::xr_init::{xr_only, XrPostSetup, XrSetup, XrPreSetup};
+use crate::xr_init::{xr_only, XrPostSetup, XrPreSetup, XrSetup};
use crate::xr_input::controllers::XrControllerType;
use crate::xr_input::oculus_touch::setup_oculus_controller;
use crate::xr_input::xr_camera::{xr_camera_head_sync, Eye, XRProjection, XrCameraBundle};
+use crate::{locate_views, xr_wait_frame};
use bevy::app::{App, PostUpdate, Startup};
use bevy::ecs::entity::Entity;
use bevy::ecs::query::With;
@@ -24,17 +24,19 @@ use bevy::math::Vec2;
use bevy::prelude::{BuildChildren, Component, Deref, DerefMut, IntoSystemConfigs, Resource};
use bevy::prelude::{Commands, Plugin, PreUpdate, Quat, Res, SpatialBundle, Update, Vec3};
use bevy::render::camera::CameraProjectionPlugin;
+use bevy::render::extract_component::ExtractComponentPlugin;
use bevy::render::view::{update_frusta, VisibilitySystems};
use bevy::transform::TransformSystem;
use bevy::utils::HashMap;
use openxr::Binding;
use self::actions::{setup_oxr_actions, OpenXrActionsPlugin};
-use self::oculus_touch::{post_action_setup_oculus_controller, ActionSets, init_subaction_path};
+use self::oculus_touch::{init_subaction_path, post_action_setup_oculus_controller, ActionSets};
use self::trackers::{
adopt_open_xr_trackers, update_open_xr_controllers, OpenXRLeftEye, OpenXRRightEye,
OpenXRTrackingRoot,
};
+use self::xr_camera::{XrCameraType, TransformExtract};
#[derive(Copy, Clone)]
pub struct OpenXrInput {
@@ -67,7 +69,10 @@ impl Plugin for OpenXrInput {
app.add_systems(PreUpdate, action_set_system.run_if(xr_only()));
app.add_systems(
PreUpdate,
- xr_camera_head_sync.run_if(xr_only()).after(xr_begin_frame),
+ xr_camera_head_sync
+ .run_if(xr_only())
+ .after(xr_wait_frame)
+ .after(locate_views),
);
//update controller trackers
app.add_systems(Update, update_open_xr_controllers.run_if(xr_only()));
@@ -79,6 +84,9 @@ impl Plugin for OpenXrInput {
);
app.add_systems(XrPreSetup, init_subaction_path);
app.add_systems(XrSetup, setup_xr_cameras);
+ app.add_plugins(ExtractComponentPlugin::::default());
+ app.add_plugins(ExtractComponentPlugin::::default());
+ app.add_plugins(ExtractComponentPlugin::::default());
}
}
diff --git a/src/xr_input/xr_camera.rs b/src/xr_input/xr_camera.rs
index 210feaa..1d143c3 100644
--- a/src/xr_input/xr_camera.rs
+++ b/src/xr_input/xr_camera.rs
@@ -1,9 +1,11 @@
use crate::xr_input::{QuatConv, Vec3Conv};
use crate::{LEFT_XR_TEXTURE_HANDLE, RIGHT_XR_TEXTURE_HANDLE};
use bevy::core_pipeline::tonemapping::{DebandDither, Tonemapping};
+use bevy::ecs::system::lifetimeless::Read;
use bevy::math::Vec3A;
use bevy::prelude::*;
use bevy::render::camera::{CameraProjection, CameraRenderGraph, RenderTarget};
+use bevy::render::extract_component::ExtractComponent;
use bevy::render::primitives::Frustum;
use bevy::render::view::{ColorGrading, VisibleEntities};
use openxr::Fovf;
@@ -48,6 +50,35 @@ pub enum XrCameraType {
Flatscreen,
}
+
+#[derive(Component)]
+pub(super) struct TransformExtract;
+
+
+impl ExtractComponent for TransformExtract {
+ type Query = Read;
+
+ type Filter = ();
+
+ type Out = Transform;
+
+ fn extract_component(item: bevy::ecs::query::QueryItem<'_, Self::Query>) -> Option {
+ Some(*item)
+ }
+}
+
+impl ExtractComponent for XrCameraType {
+ type Query = Read;
+
+ type Filter = ();
+
+ type Out = Self;
+
+ fn extract_component(item: bevy::ecs::query::QueryItem<'_, Self::Query>) -> Option {
+ Some(*item)
+ }
+}
+
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub enum Eye {
Left = 0,
@@ -81,7 +112,7 @@ impl XrCameraBundle {
}
}
-#[derive(Debug, Clone, Component, Reflect)]
+#[derive(Debug, Clone, Component, Reflect, ExtractComponent)]
#[reflect(Component, Default)]
pub struct XRProjection {
pub near: f32,
@@ -241,24 +272,21 @@ impl CameraProjection for XRProjection {
pub fn xr_camera_head_sync(
views: ResMut,
- query: Query<(&mut Transform, &XrCameraType, &mut XRProjection)>,
+ mut query: Query<(&mut Transform, &XrCameraType, &mut XRProjection)>,
) {
- fn f(
- views: ResMut,
- mut query: Query<(&mut Transform, &XrCameraType, &mut XRProjection)>,
- ) -> Option<()> {
- //TODO calculate HMD position
- for (mut transform, camera_type, mut xr_projection) in query.iter_mut() {
- let view_idx = match camera_type {
- XrCameraType::Xr(eye) => *eye as usize,
- XrCameraType::Flatscreen => return None,
- };
- let view = views.get(view_idx)?;
- xr_projection.fov = view.fov;
- transform.rotation = view.pose.orientation.to_quat();
- transform.translation = view.pose.position.to_vec3();
- }
- Some(())
+ //TODO calculate HMD position
+ for (mut transform, camera_type, mut xr_projection) in query.iter_mut() {
+ let view_idx = match camera_type {
+ XrCameraType::Xr(eye) => *eye as usize,
+ // I don't belive we need a flatscrenn cam, that's just a cam without this component
+ XrCameraType::Flatscreen => continue,
+ };
+ let view = match views.get(view_idx) {
+ Some(views) => views,
+ None => continue,
+ };
+ xr_projection.fov = view.fov;
+ transform.rotation = view.pose.orientation.to_quat();
+ transform.translation = view.pose.position.to_vec3();
}
- let _ = f(views, query);
}