borked
This commit is contained in:
294
+
Normal file
294
+
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
#[derive(Bundle)]
|
||||||
|
pub struct XrCamerasBundle {
|
||||||
|
pub left: XrCameraBundle,
|
||||||
|
pub right: XrCameraBundle,
|
||||||
|
}
|
||||||
|
impl XrCamerasBundle {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Default for XrCamerasBundle {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
left: XrCameraBundle::new(Eye::Left),
|
||||||
|
right: XrCameraBundle::new(Eye::Right),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Bundle)]
|
||||||
|
pub struct XrCameraBundle {
|
||||||
|
pub camera: Camera,
|
||||||
|
pub camera_render_graph: CameraRenderGraph,
|
||||||
|
pub xr_projection: XRProjection,
|
||||||
|
pub visible_entities: VisibleEntities,
|
||||||
|
pub frustum: Frustum,
|
||||||
|
pub transform: Transform,
|
||||||
|
pub global_transform: GlobalTransform,
|
||||||
|
pub camera_3d: Camera3d,
|
||||||
|
pub tonemapping: Tonemapping,
|
||||||
|
pub dither: DebandDither,
|
||||||
|
pub color_grading: ColorGrading,
|
||||||
|
pub xr_camera_type: XrCameraType,
|
||||||
|
}
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Component)]
|
||||||
|
pub enum XrCameraType {
|
||||||
|
Xr(Eye),
|
||||||
|
Flatscreen,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub(super) struct TransformExtract;
|
||||||
|
|
||||||
|
|
||||||
|
impl ExtractComponent for TransformExtract {
|
||||||
|
type Query = Read<Transform>;
|
||||||
|
|
||||||
|
type Filter = ();
|
||||||
|
|
||||||
|
type Out = Transform;
|
||||||
|
|
||||||
|
fn extract_component(item: bevy::ecs::query::QueryItem<'_, Self::Query>) -> Option<Self::Out> {
|
||||||
|
info!("extracting Transform");
|
||||||
|
Some(*item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExtractComponent for XrCameraType {
|
||||||
|
type Query = Read<Self>;
|
||||||
|
|
||||||
|
type Filter = ();
|
||||||
|
|
||||||
|
type Out = Self;
|
||||||
|
|
||||||
|
fn extract_component(item: bevy::ecs::query::QueryItem<'_, Self::Query>) -> Option<Self::Out> {
|
||||||
|
info!("extracting Cam Type");
|
||||||
|
Some(*item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||||
|
pub enum Eye {
|
||||||
|
Left = 0,
|
||||||
|
Right = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XrCameraBundle {
|
||||||
|
pub fn new(eye: Eye) -> Self {
|
||||||
|
Self {
|
||||||
|
camera: Camera {
|
||||||
|
order: -1,
|
||||||
|
target: RenderTarget::TextureView(match eye {
|
||||||
|
Eye::Left => LEFT_XR_TEXTURE_HANDLE,
|
||||||
|
Eye::Right => RIGHT_XR_TEXTURE_HANDLE,
|
||||||
|
}),
|
||||||
|
viewport: None,
|
||||||
|
..default()
|
||||||
|
},
|
||||||
|
camera_render_graph: CameraRenderGraph::new(bevy::core_pipeline::core_3d::graph::NAME),
|
||||||
|
xr_projection: Default::default(),
|
||||||
|
visible_entities: Default::default(),
|
||||||
|
frustum: Default::default(),
|
||||||
|
transform: Default::default(),
|
||||||
|
global_transform: Default::default(),
|
||||||
|
camera_3d: Default::default(),
|
||||||
|
tonemapping: Default::default(),
|
||||||
|
dither: DebandDither::Enabled,
|
||||||
|
color_grading: Default::default(),
|
||||||
|
xr_camera_type: XrCameraType::Xr(eye),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Component, Reflect, ExtractComponent)]
|
||||||
|
#[reflect(Component, Default)]
|
||||||
|
pub struct XRProjection {
|
||||||
|
pub near: f32,
|
||||||
|
pub far: f32,
|
||||||
|
#[reflect(ignore)]
|
||||||
|
pub fov: Fovf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for XRProjection {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
near: 0.1,
|
||||||
|
far: 1000.,
|
||||||
|
fov: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl XRProjection {
|
||||||
|
pub fn new(near: f32, far: f32, fov: Fovf) -> Self {
|
||||||
|
XRProjection { near, far, fov }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CameraProjection for XRProjection {
|
||||||
|
// =============================================================================
|
||||||
|
// math code adapted from
|
||||||
|
// https://github.com/KhronosGroup/OpenXR-SDK-Source/blob/master/src/common/xr_linear.h
|
||||||
|
// Copyright (c) 2017 The Khronos Group Inc.
|
||||||
|
// Copyright (c) 2016 Oculus VR, LLC.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
// =============================================================================
|
||||||
|
fn get_projection_matrix(&self) -> Mat4 {
|
||||||
|
// symmetric perspective for debugging
|
||||||
|
// let x_fov = (self.fov.angle_left.abs() + self.fov.angle_right.abs());
|
||||||
|
// let y_fov = (self.fov.angle_up.abs() + self.fov.angle_down.abs());
|
||||||
|
// return Mat4::perspective_infinite_reverse_rh(y_fov, x_fov / y_fov, self.near);
|
||||||
|
|
||||||
|
let fov = self.fov;
|
||||||
|
let is_vulkan_api = false; // FIXME wgpu probably abstracts this
|
||||||
|
let near_z = self.near;
|
||||||
|
let far_z = -1.; // use infinite proj
|
||||||
|
// let far_z = self.far;
|
||||||
|
|
||||||
|
let tan_angle_left = fov.angle_left.tan();
|
||||||
|
let tan_angle_right = fov.angle_right.tan();
|
||||||
|
|
||||||
|
let tan_angle_down = fov.angle_down.tan();
|
||||||
|
let tan_angle_up = fov.angle_up.tan();
|
||||||
|
|
||||||
|
let tan_angle_width = tan_angle_right - tan_angle_left;
|
||||||
|
|
||||||
|
// Set to tanAngleDown - tanAngleUp for a clip space with positive Y
|
||||||
|
// down (Vulkan). Set to tanAngleUp - tanAngleDown for a clip space with
|
||||||
|
// positive Y up (OpenGL / D3D / Metal).
|
||||||
|
// const float tanAngleHeight =
|
||||||
|
// graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown);
|
||||||
|
let tan_angle_height = if is_vulkan_api {
|
||||||
|
tan_angle_down - tan_angle_up
|
||||||
|
} else {
|
||||||
|
tan_angle_up - tan_angle_down
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES).
|
||||||
|
// Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal).
|
||||||
|
// const float offsetZ =
|
||||||
|
// (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0;
|
||||||
|
// FIXME handle enum of graphics apis
|
||||||
|
let offset_z = 0.;
|
||||||
|
|
||||||
|
let mut cols: [f32; 16] = [0.0; 16];
|
||||||
|
|
||||||
|
if far_z <= near_z {
|
||||||
|
// place the far plane at infinity
|
||||||
|
cols[0] = 2. / tan_angle_width;
|
||||||
|
cols[4] = 0.;
|
||||||
|
cols[8] = (tan_angle_right + tan_angle_left) / tan_angle_width;
|
||||||
|
cols[12] = 0.;
|
||||||
|
|
||||||
|
cols[1] = 0.;
|
||||||
|
cols[5] = 2. / tan_angle_height;
|
||||||
|
cols[9] = (tan_angle_up + tan_angle_down) / tan_angle_height;
|
||||||
|
cols[13] = 0.;
|
||||||
|
|
||||||
|
cols[2] = 0.;
|
||||||
|
cols[6] = 0.;
|
||||||
|
cols[10] = -1.;
|
||||||
|
cols[14] = -(near_z + offset_z);
|
||||||
|
|
||||||
|
cols[3] = 0.;
|
||||||
|
cols[7] = 0.;
|
||||||
|
cols[11] = -1.;
|
||||||
|
cols[15] = 0.;
|
||||||
|
|
||||||
|
// bevy uses the _reverse_ infinite projection
|
||||||
|
// https://dev.theomader.com/depth-precision/
|
||||||
|
let z_reversal = Mat4::from_cols_array_2d(&[
|
||||||
|
[1f32, 0., 0., 0.],
|
||||||
|
[0., 1., 0., 0.],
|
||||||
|
[0., 0., -1., 0.],
|
||||||
|
[0., 0., 1., 1.],
|
||||||
|
]);
|
||||||
|
|
||||||
|
return z_reversal * Mat4::from_cols_array(&cols);
|
||||||
|
} else {
|
||||||
|
// normal projection
|
||||||
|
cols[0] = 2. / tan_angle_width;
|
||||||
|
cols[4] = 0.;
|
||||||
|
cols[8] = (tan_angle_right + tan_angle_left) / tan_angle_width;
|
||||||
|
cols[12] = 0.;
|
||||||
|
|
||||||
|
cols[1] = 0.;
|
||||||
|
cols[5] = 2. / tan_angle_height;
|
||||||
|
cols[9] = (tan_angle_up + tan_angle_down) / tan_angle_height;
|
||||||
|
cols[13] = 0.;
|
||||||
|
|
||||||
|
cols[2] = 0.;
|
||||||
|
cols[6] = 0.;
|
||||||
|
cols[10] = -(far_z + offset_z) / (far_z - near_z);
|
||||||
|
cols[14] = -(far_z * (near_z + offset_z)) / (far_z - near_z);
|
||||||
|
|
||||||
|
cols[3] = 0.;
|
||||||
|
cols[7] = 0.;
|
||||||
|
cols[11] = -1.;
|
||||||
|
cols[15] = 0.;
|
||||||
|
}
|
||||||
|
|
||||||
|
Mat4::from_cols_array(&cols)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, _width: f32, _height: f32) {}
|
||||||
|
|
||||||
|
fn far(&self) -> f32 {
|
||||||
|
self.far
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_frustum_corners(&self, z_near: f32, z_far: f32) -> [Vec3A; 8] {
|
||||||
|
let tan_angle_left = self.fov.angle_left.tan();
|
||||||
|
let tan_angle_right = self.fov.angle_right.tan();
|
||||||
|
|
||||||
|
let tan_angle_bottom = self.fov.angle_down.tan();
|
||||||
|
let tan_angle_top = self.fov.angle_up.tan();
|
||||||
|
|
||||||
|
// NOTE: These vertices are in the specific order required by [`calculate_cascade`].
|
||||||
|
[
|
||||||
|
Vec3A::new(tan_angle_right, tan_angle_bottom, 1.0) * z_near, // bottom right
|
||||||
|
Vec3A::new(tan_angle_right, tan_angle_top, 1.0) * z_near, // top right
|
||||||
|
Vec3A::new(tan_angle_left, tan_angle_top, 1.0) * z_near, // top left
|
||||||
|
Vec3A::new(tan_angle_left, tan_angle_bottom, 1.0) * z_near, // bottom left
|
||||||
|
Vec3A::new(tan_angle_right, tan_angle_bottom, 1.0) * z_far, // bottom right
|
||||||
|
Vec3A::new(tan_angle_right, tan_angle_top, 1.0) * z_far, // top right
|
||||||
|
Vec3A::new(tan_angle_left, tan_angle_top, 1.0) * z_far, // top left
|
||||||
|
Vec3A::new(tan_angle_left, tan_angle_bottom, 1.0) * z_far, // bottom left
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn xr_camera_head_sync(
|
||||||
|
views: ResMut<crate::resources::XrViews>,
|
||||||
|
mut query: Query<(&mut Transform, &XrCameraType, &mut XRProjection)>,
|
||||||
|
) {
|
||||||
|
//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();
|
||||||
|
}
|
||||||
|
}
|
||||||
197
src/xr_init/mod.rs
Normal file
197
src/xr_init/mod.rs
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
pub mod schedules;
|
||||||
|
pub use schedules::*;
|
||||||
|
|
||||||
|
use bevy::{
|
||||||
|
prelude::*,
|
||||||
|
render::{
|
||||||
|
camera::{ManualTextureView, ManualTextureViews},
|
||||||
|
extract_resource::{ExtractResource, ExtractResourcePlugin},
|
||||||
|
renderer::{RenderAdapter, RenderDevice, RenderInstance},
|
||||||
|
},
|
||||||
|
window::{PrimaryWindow, RawHandleWrapper},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
graphics,
|
||||||
|
resources::{
|
||||||
|
OXrSessionSetupInfo, XrFormat, XrInstance, XrResolution, XrSession, XrSessionRunning,
|
||||||
|
XrSwapchain,
|
||||||
|
},
|
||||||
|
LEFT_XR_TEXTURE_HANDLE, RIGHT_XR_TEXTURE_HANDLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Resource, Event, Clone, Copy, PartialEq, Eq, Reflect, Debug, ExtractResource)]
|
||||||
|
pub enum XrStatus {
|
||||||
|
NoInstance,
|
||||||
|
Enabled,
|
||||||
|
Enabling,
|
||||||
|
Disabled,
|
||||||
|
Disabling,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(
|
||||||
|
Resource, Clone, Copy, PartialEq, Eq, Reflect, Debug, ExtractResource, Default, Deref, DerefMut,
|
||||||
|
)]
|
||||||
|
pub struct XrShouldRender(bool);
|
||||||
|
|
||||||
|
pub struct XrEarlyInitPlugin;
|
||||||
|
|
||||||
|
pub struct XrInitPlugin;
|
||||||
|
|
||||||
|
pub fn xr_only() -> impl FnMut(Option<Res<XrStatus>>) -> bool {
|
||||||
|
resource_exists_and_equals(XrStatus::Enabled)
|
||||||
|
}
|
||||||
|
pub fn xr_render_only() -> impl FnMut(Option<Res<XrShouldRender>>) -> bool {
|
||||||
|
resource_exists_and_equals(XrShouldRender(true))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for XrEarlyInitPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_event::<SetupXrData>()
|
||||||
|
.add_event::<CleanupXrData>()
|
||||||
|
.add_event::<StartXrSession>()
|
||||||
|
.add_event::<EndXrSession>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for XrInitPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
add_schedules(app);
|
||||||
|
app.add_plugins(ExtractResourcePlugin::<XrStatus>::default());
|
||||||
|
app.add_plugins(ExtractResourcePlugin::<XrShouldRender>::default());
|
||||||
|
app.init_resource::<XrShouldRender>();
|
||||||
|
app.add_systems(PreUpdate, setup_xr.run_if(on_event::<SetupXrData>()))
|
||||||
|
.add_systems(PreUpdate, cleanup_xr.run_if(on_event::<CleanupXrData>()));
|
||||||
|
app.add_systems(
|
||||||
|
PostUpdate,
|
||||||
|
start_xr_session.run_if(on_event::<StartXrSession>()),
|
||||||
|
);
|
||||||
|
app.add_systems(
|
||||||
|
PostUpdate,
|
||||||
|
stop_xr_session.run_if(on_event::<EndXrSession>()),
|
||||||
|
);
|
||||||
|
app.add_systems(XrSetup, setup_manual_texture_views);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup_manual_texture_views(
|
||||||
|
mut manual_texture_views: ResMut<ManualTextureViews>,
|
||||||
|
swapchain: Res<XrSwapchain>,
|
||||||
|
xr_resolution: Res<XrResolution>,
|
||||||
|
xr_format: Res<XrFormat>,
|
||||||
|
) {
|
||||||
|
info!("Creating Texture views");
|
||||||
|
let (left, right) = 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,
|
||||||
|
};
|
||||||
|
manual_texture_views.insert(LEFT_XR_TEXTURE_HANDLE, left);
|
||||||
|
manual_texture_views.insert(RIGHT_XR_TEXTURE_HANDLE, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup_xr(world: &mut World) {
|
||||||
|
world.run_schedule(XrPreSetup);
|
||||||
|
world.run_schedule(XrSetup);
|
||||||
|
world.run_schedule(XrPrePostSetup);
|
||||||
|
world.run_schedule(XrPostSetup);
|
||||||
|
*world.resource_mut::<XrStatus>() = XrStatus::Enabled;
|
||||||
|
}
|
||||||
|
fn cleanup_xr(world: &mut World) {
|
||||||
|
world.run_schedule(XrPreCleanup);
|
||||||
|
world.run_schedule(XrCleanup);
|
||||||
|
world.run_schedule(XrPostCleanup);
|
||||||
|
*world.resource_mut::<XrStatus>() = XrStatus::Disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
pub struct StartXrSession;
|
||||||
|
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
pub struct EndXrSession;
|
||||||
|
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
struct SetupXrData;
|
||||||
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
|
pub(crate) struct CleanupXrData;
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
fn start_xr_session(
|
||||||
|
mut commands: Commands,
|
||||||
|
mut setup_xr: EventWriter<SetupXrData>,
|
||||||
|
mut status: ResMut<XrStatus>,
|
||||||
|
instance: Res<XrInstance>,
|
||||||
|
primary_window: Query<&RawHandleWrapper, With<PrimaryWindow>>,
|
||||||
|
setup_info: NonSend<OXrSessionSetupInfo>,
|
||||||
|
render_device: Res<RenderDevice>,
|
||||||
|
render_adapter: Res<RenderAdapter>,
|
||||||
|
render_instance: Res<RenderInstance>,
|
||||||
|
) {
|
||||||
|
info!("start Session");
|
||||||
|
match *status {
|
||||||
|
XrStatus::Disabled => {}
|
||||||
|
XrStatus::NoInstance => {
|
||||||
|
warn!("Trying to start OpenXR Session without instance, ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XrStatus::Enabled | XrStatus::Enabling => {
|
||||||
|
warn!("Trying to start OpenXR Session while one already exists, ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
XrStatus::Disabling => {
|
||||||
|
warn!("Trying to start OpenXR Session while one is stopping, ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
*status = XrStatus::Enabling;
|
||||||
|
setup_xr.send_default();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop_xr_session(session: ResMut<XrSession>, mut status: ResMut<XrStatus>) {
|
||||||
|
match session.request_exit() {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(err) => {
|
||||||
|
error!("Error while trying to request session exit: {}", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*status = XrStatus::Enabling;
|
||||||
|
}
|
||||||
51
src/xr_init/schedules.rs
Normal file
51
src/xr_init/schedules.rs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
use bevy::{ecs::schedule::{ScheduleLabel, Schedule, ExecutorKind}, app::App};
|
||||||
|
|
||||||
|
#[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(super) 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user