Fallback to flat when no oxr runtime is found (#51)

* basics done? now to the fun part: changing the ENTIRE lib to work with xr and non xr

* updated stuff and renamed file

* actually add the renamed file into git lol :3

* made lib fallback to flat when no runtime is found but can't compile with default settings under those circumstances
This commit is contained in:
Schmarni
2023-12-09 06:09:48 +01:00
committed by GitHub
parent d9ebd5bf0c
commit 28008f7964
15 changed files with 547 additions and 783 deletions

View File

@@ -18,6 +18,7 @@ members = ["examples/android", "examples/demo"]
anyhow = "1.0.75" anyhow = "1.0.75"
ash = "0.37.3" ash = "0.37.3"
bevy = "0.12" bevy = "0.12"
futures-lite = "2.1.0"
mint = "0.5.9" mint = "0.5.9"
wgpu = "0.17.1" wgpu = "0.17.1"
wgpu-core = { version = "0.17.1", features = ["vulkan"] } wgpu-core = { version = "0.17.1", features = ["vulkan"] }

View File

@@ -17,4 +17,5 @@ color-eyre = "0.6.2"
[target.'cfg(not(target_os="android"))'.dependencies.bevy_oxr] [target.'cfg(not(target_os="android"))'.dependencies.bevy_oxr]
path = "../../" path = "../../"
# May need to be more specific. needs to be false at least on linux without an active runtime to run in flat
default-features = true default-features = true

View File

@@ -1,24 +0,0 @@
[package]
name = "demo"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bevy = { git = "https://github.com/bevyengine/bevy.git" }
# bevy = "0.11.3"
# default-features is false because it for some reason complains when trying to statically link openxr
bevy_oxr = { path = "../../" }
# bevy_openxr = { git = "https://github.com/Schmarni-Dev/bevy_openxr", default-features = false, branch = "demo"}
bevy_rapier3d = { git = "https://github.com/devil-ira/bevy_rapier", version = "0.22.0", branch = "bevy-0.12" }
# bevy_rapier3d = { git = "https://github.com/Schmarni-Dev/bevy_rapier" }
color-eyre = "0.6.2"
[profile.release]
lto = "fat"
codegen-units = 1
panic = "abort"

View File

@@ -3,6 +3,7 @@ use std::{f32::consts::PI, ops::Mul, time::Duration};
use bevy::{ use bevy::{
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin}, diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
ecs::schedule::ScheduleLabel, ecs::schedule::ScheduleLabel,
input::{keyboard::KeyCode, Input},
log::info, log::info,
prelude::{ prelude::{
bevy_main, default, shape, App, Assets, Color, Commands, Component, Entity, Event, bevy_main, default, shape, App, Assets, Color, Commands, Component, Entity, Event,
@@ -16,10 +17,12 @@ use bevy::{
}; };
use bevy_oxr::{ use bevy_oxr::{
input::XrInput, input::XrInput,
xr_init::{XrEnableRequest, XrEnableStatus, xr_only},
resources::{XrFrameState, XrInstance, XrSession}, resources::{XrFrameState, XrInstance, XrSession},
xr_input::{ xr_input::{
actions::XrActionSets,
debug_gizmos::OpenXrDebugRenderer, debug_gizmos::OpenXrDebugRenderer,
hands::common::{ HandInputDebugRenderer, HandResource, HandsResource, OpenXrHandInput}, hands::common::{HandInputDebugRenderer, HandResource, HandsResource, OpenXrHandInput},
hands::HandBone, hands::HandBone,
interactions::{ interactions::{
draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions, draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions,
@@ -29,11 +32,25 @@ use bevy_oxr::{
oculus_touch::OculusController, oculus_touch::OculusController,
prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig}, prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig},
trackers::{OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker}, trackers::{OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker},
Hand, actions::XrActionSets, Hand,
}, },
DefaultXrPlugins, DefaultXrPlugins,
}; };
fn input_stuff(
keys: Res<Input<KeyCode>>,
status: Res<XrEnableStatus>,
mut request: EventWriter<XrEnableRequest>,
) {
if keys.just_pressed(KeyCode::Space) {
match status.into_inner() {
XrEnableStatus::Enabled => request.send(XrEnableRequest::TryDisable),
XrEnableStatus::Disabled => request.send(XrEnableRequest::TryEnable),
XrEnableStatus::Waiting => (),
}
}
}
mod setup; mod setup;
use crate::setup::setup_scene; use crate::setup::setup_scene;
use bevy_rapier3d::prelude::*; use bevy_rapier3d::prelude::*;
@@ -45,7 +62,7 @@ pub fn main() {
info!("Running bevy_openxr demo"); info!("Running bevy_openxr demo");
let mut app = App::new(); let mut app = App::new();
app app.add_systems(Update, input_stuff)
//lets get the usual diagnostic stuff added //lets get the usual diagnostic stuff added
.add_plugins(LogDiagnosticsPlugin::default()) .add_plugins(LogDiagnosticsPlugin::default())
.add_plugins(FrameTimeDiagnosticsPlugin) .add_plugins(FrameTimeDiagnosticsPlugin)
@@ -60,11 +77,11 @@ pub fn main() {
.add_systems(Startup, setup_scene) .add_systems(Startup, setup_scene)
.add_systems(Startup, spawn_controllers_example) //you need to spawn controllers or it crashes TODO:: Fix this .add_systems(Startup, spawn_controllers_example) //you need to spawn controllers or it crashes TODO:: Fix this
//add locomotion //add locomotion
.add_systems(Update, proto_locomotion) .add_systems(Update, proto_locomotion.run_if(xr_only()))
.insert_resource(PrototypeLocomotionConfig::default()) .insert_resource(PrototypeLocomotionConfig::default())
//lets add the interaction systems //lets add the interaction systems
.add_event::<InteractionEvent>() .add_event::<InteractionEvent>()
.add_systems(Update, prototype_interaction_input) .add_systems(Update, prototype_interaction_input.run_if(xr_only()))
.add_systems(Update, interactions.before(update_interactable_states)) .add_systems(Update, interactions.before(update_interactable_states))
.add_systems(Update, update_interactable_states) .add_systems(Update, update_interactable_states)
.add_systems( .add_systems(
@@ -76,7 +93,7 @@ pub fn main() {
//draw the interaction gizmos //draw the interaction gizmos
.add_systems( .add_systems(
Update, Update,
draw_interaction_gizmos.after(update_interactable_states), draw_interaction_gizmos.run_if(xr_only()).after(update_interactable_states),
) )
.add_systems(Update, draw_socket_gizmos.after(update_interactable_states)) .add_systems(Update, draw_socket_gizmos.after(update_interactable_states))
//add our cube spawning system //add our cube spawning system
@@ -85,7 +102,7 @@ pub fn main() {
0.25, 0.25,
bevy::time::TimerMode::Once, bevy::time::TimerMode::Once,
))) )))
.add_systems(Update, request_cube_spawn) .add_systems(Update, request_cube_spawn.run_if(xr_only()))
.add_systems(Update, cube_spawner.after(request_cube_spawn)) .add_systems(Update, cube_spawner.after(request_cube_spawn))
//test capsule //test capsule
.add_systems(Startup, spawn_capsule) .add_systems(Startup, spawn_capsule)

View File

@@ -1,609 +0,0 @@
use bevy::{
diagnostic::{FrameTimeDiagnosticsPlugin, LogDiagnosticsPlugin},
log::info,
prelude::{
*,
bevy_main, default, shape, App, Assets, Color, Commands, Component, Event, EventReader,
EventWriter, GlobalTransform, IntoSystemConfigs, IntoSystemSetConfigs, Mesh, PbrBundle,
PostUpdate, Query, Res, ResMut, Resource, SpatialBundle, StandardMaterial, Startup,
Transform, Update, With, Without,
},
time::{Time, Timer},
transform::TransformSystem,
};
use bevy_openxr::{
input::XrInput,
resources::{XrFrameState, XrInstance, XrSession},
xr_input::{
debug_gizmos::OpenXrDebugRenderer,
hand::{HandBone, HandInputDebugRenderer, HandResource, HandsResource, OpenXrHandInput},
interactions::{
draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions,
update_interactable_states, InteractionEvent, Touched, XRDirectInteractor,
XRInteractable, XRInteractableState, XRInteractorState, XRSelection,
},
oculus_touch::OculusController,
prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig},
trackers::{OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker},
Hand,
},
DefaultXrPlugins,
};
mod setup;
use crate::setup::setup_scene;
use bevy_rapier3d::prelude::*;
#[bevy_main]
pub fn main() {
color_eyre::install().unwrap();
info!("Running bevy_openxr demo");
let mut app = App::new();
app
//lets get the usual diagnostic stuff added
.add_plugins(LogDiagnosticsPlugin::default())
.add_plugins(FrameTimeDiagnosticsPlugin)
//lets get the xr defaults added
.add_plugins(DefaultXrPlugins)
//lets add the debug renderer for the controllers
.add_plugins(OpenXrDebugRenderer)
//rapier goes here
.add_plugins(RapierPhysicsPlugin::<NoUserData>::default().with_default_system_setup(false))
.add_plugins(RapierDebugRenderPlugin::default())
//lets setup the starting scene
.add_systems(Startup, setup_scene)
.add_systems(Startup, spawn_controllers_example) //you need to spawn controllers or it crashes TODO:: Fix this
//add locomotion
.add_systems(Update, proto_locomotion)
.insert_resource(PrototypeLocomotionConfig::default())
//lets add the interaction systems
.add_event::<InteractionEvent>()
.add_systems(Update, prototype_interaction_input)
.add_systems(Update, interactions.before(update_interactable_states))
.add_systems(Update, update_interactable_states)
.add_systems(
Update,
socket_interactions.before(update_interactable_states),
)
//add the grabbable system
.add_systems(Update, update_grabbables.after(update_interactable_states))
//draw the interaction gizmos
.add_systems(
Update,
draw_interaction_gizmos.after(update_interactable_states),
)
.add_systems(Update, draw_socket_gizmos.after(update_interactable_states))
//add our cube spawning system
.add_event::<SpawnCubeRequest>()
.insert_resource(SpawnCubeTimer(Timer::from_seconds(
0.25,
bevy::time::TimerMode::Once,
)))
.add_systems(Update, request_cube_spawn)
.add_systems(Update, cube_spawner.after(request_cube_spawn))
//test capsule
.add_systems(Startup, spawn_capsule)
//physics hands
.add_plugins(OpenXrHandInput)
.add_plugins(HandInputDebugRenderer)
.add_systems(Startup, spawn_physics_hands)
.add_systems(Update, update_physics_hands);
//configure rapier sets
app.configure_sets(
PostUpdate,
(
PhysicsSet::SyncBackend,
PhysicsSet::StepSimulation,
PhysicsSet::Writeback,
)
.chain()
.before(TransformSystem::TransformPropagate),
);
//add rapier systems
app.add_systems(
PostUpdate,
(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsSet::SyncBackend)
.in_set(PhysicsSet::SyncBackend),
(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsSet::StepSimulation),
// despawn_one_box,
)
.in_set(PhysicsSet::StepSimulation),
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsSet::Writeback)
.in_set(PhysicsSet::Writeback),
),
);
app.run();
}
fn spawn_controllers_example(mut commands: Commands) {
//left hand
commands.spawn((
OpenXRLeftController,
OpenXRController,
OpenXRTracker,
SpatialBundle::default(),
XRDirectInteractor,
XRInteractorState::default(),
XRSelection::default(),
));
//right hand
commands.spawn((
OpenXRRightController,
OpenXRController,
OpenXRTracker,
SpatialBundle::default(),
XRDirectInteractor,
XRInteractorState::default(),
XRSelection::default(),
));
}
fn spawn_capsule(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Capsule {
radius: 0.033,
depth: 0.115,
..default()
})),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
transform: Transform::from_xyz(0.0, 2.0, 0.0),
..default()
},
// Collider::capsule_y(0.0575, 0.034),
Collider::capsule(
Vec3 {
x: 0.0,
y: -0.0575,
z: 0.0,
},
Vec3 {
x: 0.0,
y: 0.0575,
z: 0.0,
},
0.034,
),
RigidBody::Dynamic,
));
}
#[derive(Component, PartialEq, Debug, Clone, Copy)]
pub enum PhysicsHandBone {
Palm,
Wrist,
ThumbMetacarpal,
ThumbProximal,
ThumbDistal,
ThumbTip,
IndexMetacarpal,
IndexProximal,
IndexIntermediate,
IndexDistal,
IndexTip,
MiddleMetacarpal,
MiddleProximal,
MiddleIntermediate,
MiddleDistal,
MiddleTip,
RingMetacarpal,
RingProximal,
RingIntermediate,
RingDistal,
RingTip,
LittleMetacarpal,
LittleProximal,
LittleIntermediate,
LittleDistal,
LittleTip,
}
#[derive(Component, PartialEq)]
pub enum BoneInitState {
True,
False,
}
fn spawn_physics_hands(mut commands: Commands) {
//here we go
let hands = [Hand::Left, Hand::Right];
let bones = [
PhysicsHandBone::Palm,
PhysicsHandBone::Wrist,
PhysicsHandBone::ThumbMetacarpal,
PhysicsHandBone::ThumbProximal,
PhysicsHandBone::ThumbDistal,
PhysicsHandBone::ThumbTip,
PhysicsHandBone::IndexMetacarpal,
PhysicsHandBone::IndexProximal,
PhysicsHandBone::IndexIntermediate,
PhysicsHandBone::IndexDistal,
PhysicsHandBone::IndexTip,
PhysicsHandBone::MiddleMetacarpal,
PhysicsHandBone::MiddleProximal,
PhysicsHandBone::MiddleIntermediate,
PhysicsHandBone::MiddleDistal,
PhysicsHandBone::MiddleTip,
PhysicsHandBone::RingMetacarpal,
PhysicsHandBone::RingProximal,
PhysicsHandBone::RingIntermediate,
PhysicsHandBone::RingDistal,
PhysicsHandBone::RingTip,
PhysicsHandBone::LittleMetacarpal,
PhysicsHandBone::LittleProximal,
PhysicsHandBone::LittleIntermediate,
PhysicsHandBone::LittleDistal,
PhysicsHandBone::LittleTip,
];
//lets just do the Right ThumbMetacarpal for now
//i dont understand the groups yet
let self_group = Group::GROUP_1;
let interaction_group = Group::ALL;
let radius = 0.010;
for hand in hands.iter() {
for bone in bones.iter() {
//spawn the thing
commands.spawn((
SpatialBundle::default(),
Collider::capsule(
Vec3 {
x: 0.0,
y: -0.0575,
z: 0.0,
},
Vec3 {
x: 0.0,
y: 0.0575,
z: 0.0,
},
radius,
),
RigidBody::KinematicPositionBased,
// CollisionGroups::new(self_group, interaction_group),
// SolverGroups::new(self_group, interaction_group),
bone.clone(),
BoneInitState::False,
hand.clone(),
));
}
}
}
fn update_physics_hands(
hands_res: Option<Res<HandsResource>>,
mut bone_query: Query<(
&mut Transform,
&mut Collider,
&PhysicsHandBone,
&mut BoneInitState,
&Hand,
)>,
hand_query: Query<(&Transform, &HandBone, &Hand, Without<PhysicsHandBone>)>,
) {
//sanity check do we even have hands?
match hands_res {
Some(res) => {
//config stuff
let radius = 0.010;
for mut bone in bone_query.iter_mut() {
let hand_res = match bone.4 {
Hand::Left => res.left,
Hand::Right => res.right,
};
//lets just do the Right ThumbMetacarpal for now
let result = get_start_and_end_entities(hand_res, bone.2);
if let Some((start_entity, end_entity)) = result {
//now we need their transforms
let start_components = hand_query.get(start_entity);
let end_components = hand_query.get(end_entity);
let direction = end_components.unwrap().0.translation
- start_components.unwrap().0.translation;
if direction.length() < 0.001 {
//i hate this but we need to skip init if the length is zero
return;
}
match *bone.3 {
BoneInitState::True => {
//if we are init then we just move em?
*bone.0 = start_components
.unwrap()
.0
.clone()
.looking_at(end_components.unwrap().0.translation, Vec3::Y);
}
BoneInitState::False => {
//build a new collider?
*bone.1 = Collider::capsule(
Vec3::splat(0.0),
Vec3 {
x: 0.0,
y: 0.0,
z: -direction.length(),
},
radius,
);
*bone.3 = BoneInitState::True;
}
}
}
}
}
None => info!("hand states resource not initialized yet"),
}
}
fn get_start_and_end_entities(
hand_res: HandResource,
bone: &PhysicsHandBone,
) -> Option<(Entity, Entity)> {
match bone {
PhysicsHandBone::Palm => return None,
PhysicsHandBone::Wrist => return None,
PhysicsHandBone::ThumbMetacarpal => {
return Some((hand_res.thumb.metacarpal, hand_res.thumb.proximal))
}
PhysicsHandBone::ThumbProximal => {
return Some((hand_res.thumb.proximal, hand_res.thumb.distal))
}
PhysicsHandBone::ThumbDistal => return Some((hand_res.thumb.distal, hand_res.thumb.tip)),
PhysicsHandBone::ThumbTip => return None,
PhysicsHandBone::IndexMetacarpal => {
return Some((hand_res.index.metacarpal, hand_res.index.proximal))
}
PhysicsHandBone::IndexProximal => {
return Some((hand_res.index.proximal, hand_res.index.intermediate))
}
PhysicsHandBone::IndexIntermediate => {
return Some((hand_res.index.intermediate, hand_res.index.distal))
}
PhysicsHandBone::IndexDistal => return Some((hand_res.index.distal, hand_res.index.tip)),
PhysicsHandBone::IndexTip => return None,
PhysicsHandBone::MiddleMetacarpal => {
return Some((hand_res.middle.metacarpal, hand_res.middle.proximal))
}
PhysicsHandBone::MiddleProximal => {
return Some((hand_res.middle.proximal, hand_res.middle.intermediate))
}
PhysicsHandBone::MiddleIntermediate => {
return Some((hand_res.middle.intermediate, hand_res.middle.distal))
}
PhysicsHandBone::MiddleDistal => {
return Some((hand_res.middle.distal, hand_res.middle.tip))
}
PhysicsHandBone::MiddleTip => return None,
PhysicsHandBone::RingMetacarpal => {
return Some((hand_res.ring.metacarpal, hand_res.ring.proximal))
}
PhysicsHandBone::RingProximal => {
return Some((hand_res.ring.proximal, hand_res.ring.intermediate))
}
PhysicsHandBone::RingIntermediate => {
return Some((hand_res.ring.intermediate, hand_res.ring.distal))
}
PhysicsHandBone::RingDistal => return Some((hand_res.ring.distal, hand_res.ring.tip)),
PhysicsHandBone::RingTip => return None,
PhysicsHandBone::LittleMetacarpal => {
return Some((hand_res.little.metacarpal, hand_res.little.proximal))
}
PhysicsHandBone::LittleProximal => {
return Some((hand_res.little.proximal, hand_res.little.intermediate))
}
PhysicsHandBone::LittleIntermediate => {
return Some((hand_res.little.intermediate, hand_res.little.distal))
}
PhysicsHandBone::LittleDistal => {
return Some((hand_res.little.distal, hand_res.little.tip))
}
PhysicsHandBone::LittleTip => return None,
};
}
fn get_hand_res(res: &Res<'_, HandsResource>, hand: Hand) -> HandResource {
match hand {
Hand::Left => res.left.clone(),
Hand::Right => res.right.clone(),
}
}
#[derive(Event, Default)]
pub struct SpawnCubeRequest;
#[derive(Resource)]
pub struct SpawnCubeTimer(Timer);
fn request_cube_spawn(
oculus_controller: Res<OculusController>,
frame_state: Res<XrFrameState>,
xr_input: Res<XrInput>,
instance: Res<XrInstance>,
session: Res<XrSession>,
mut writer: EventWriter<SpawnCubeRequest>,
time: Res<Time>,
mut timer: ResMut<SpawnCubeTimer>,
) {
timer.0.tick(time.delta());
if timer.0.finished() {
//lock frame
let frame_state = *frame_state.lock().unwrap();
//get controller
let controller = oculus_controller.get_ref(&instance, &session, &frame_state, &xr_input);
//get controller triggers
let left_main_button = controller.a_button();
if left_main_button {
writer.send(SpawnCubeRequest::default());
timer.0.reset();
}
let right_main_button = controller.x_button();
if right_main_button {
writer.send(SpawnCubeRequest::default());
timer.0.reset();
}
}
}
fn cube_spawner(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut events: EventReader<SpawnCubeRequest>,
) {
for request in events.iter() {
// cube
commands.spawn((
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 0.1 })),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
transform: Transform::from_xyz(0.0, 1.0, 0.0),
..default()
},
RigidBody::Dynamic,
Collider::cuboid(0.05, 0.05, 0.05),
ColliderDebugColor(Color::hsl(220.0, 1.0, 0.3)),
XRInteractable,
XRInteractableState::default(),
Grabbable,
Touched(false),
));
}
}
//TODO: find a real place for this
fn prototype_interaction_input(
oculus_controller: Res<OculusController>,
frame_state: Res<XrFrameState>,
xr_input: Res<XrInput>,
instance: Res<XrInstance>,
session: Res<XrSession>,
mut right_interactor_query: Query<
(&mut XRInteractorState),
(
With<XRDirectInteractor>,
With<OpenXRRightController>,
Without<OpenXRLeftController>,
),
>,
mut left_interactor_query: Query<
(&mut XRInteractorState),
(
With<XRDirectInteractor>,
With<OpenXRLeftController>,
Without<OpenXRRightController>,
),
>,
) {
//lock frame
let frame_state = *frame_state.lock().unwrap();
//get controller
let controller = oculus_controller.get_ref(&instance, &session, &frame_state, &xr_input);
//get controller triggers
let left_trigger = controller.trigger(Hand::Left);
let right_trigger = controller.trigger(Hand::Right);
//get the interactors and do state stuff
let mut left_state = left_interactor_query.single_mut();
if left_trigger > 0.8 {
*left_state = XRInteractorState::Selecting;
} else {
*left_state = XRInteractorState::Idle;
}
let mut right_state = right_interactor_query.single_mut();
if right_trigger > 0.8 {
*right_state = XRInteractorState::Selecting;
} else {
*right_state = XRInteractorState::Idle;
}
}
#[derive(Component)]
pub struct Grabbable;
pub fn update_grabbables(
mut events: EventReader<InteractionEvent>,
mut grabbable_query: Query<(
Entity,
&mut Transform,
With<Grabbable>,
Without<XRDirectInteractor>,
Option<&mut RigidBody>,
)>,
mut interactor_query: Query<(
&GlobalTransform,
&XRInteractorState,
&mut XRSelection,
Without<Grabbable>,
)>,
) {
//so basically the idea is to try all the events?
for event in events.read() {
// info!("some event");
match grabbable_query.get_mut(event.interactable) {
Ok(mut grabbable_transform) => {
// info!("we got a grabbable");
//now we need the location of our interactor
match interactor_query.get_mut(event.interactor) {
Ok(mut interactor_transform) => {
match *interactor_transform.2 {
XRSelection::Empty => {
match interactor_transform.1 {
XRInteractorState::Idle => match grabbable_transform.4 {
Some(mut thing) => {
*thing = RigidBody::Dynamic;
*interactor_transform.2 = XRSelection::Empty;
}
None => (),
},
XRInteractorState::Selecting => {
// info!("its a direct interactor?");
match grabbable_transform.4 {
Some(mut thing) => {
*thing = RigidBody::KinematicPositionBased;
*interactor_transform.2 =
XRSelection::Full(grabbable_transform.0);
}
None => (),
}
*grabbable_transform.1 =
interactor_transform.0.compute_transform();
}
}
}
XRSelection::Full(ent) => {
info!("nah bro we holding something");
match grabbable_transform.0 == ent {
true => {
*grabbable_transform.1 =
interactor_transform.0.compute_transform();
}
false => {}
}
match interactor_transform.1 {
XRInteractorState::Idle => {
*interactor_transform.2 = XRSelection::Empty
}
XRInteractorState::Selecting => {}
}
}
}
}
Err(_) => {
// info!("not a direct interactor")
}
}
}
Err(_) => {
// info!("not a grabbable?")
}
}
}
}

View File

@@ -56,15 +56,15 @@ pub fn setup_scene(
)); ));
// light // light
commands.spawn(PointLightBundle { // commands.spawn(PointLightBundle {
point_light: PointLight { // point_light: PointLight {
intensity: 1500.0, // intensity: 1500.0,
shadows_enabled: true, // shadows_enabled: true,
..default() // ..default()
}, // },
transform: Transform::from_xyz(4.0, 8.0, 4.0), // transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default() // ..default()
}); // });
// camera // camera
commands.spawn((Camera3dBundle { commands.spawn((Camera3dBundle {
transform: Transform::from_xyz(0.25, 1.25, 0.0).looking_at( transform: Transform::from_xyz(0.25, 1.25, 0.0).looking_at(

View File

@@ -35,10 +35,10 @@ pub fn initialize_xr_graphics(
vulkan::initialize_xr_graphics(window) vulkan::initialize_xr_graphics(window)
} }
pub fn xr_entry() -> xr::Entry { pub fn xr_entry() -> anyhow::Result<xr::Entry> {
#[cfg(feature = "linked")] #[cfg(feature = "linked")]
let entry = xr::Entry::linked(); let entry = Ok(xr::Entry::linked());
#[cfg(not(feature = "linked"))] #[cfg(not(feature = "linked"))]
let entry = unsafe { xr::Entry::load().unwrap() }; let entry = unsafe { xr::Entry::load().map_err(|e| anyhow::anyhow!(e)) };
entry entry
} }

View File

@@ -44,10 +44,10 @@ pub fn initialize_xr_graphics(
)> { )> {
use wgpu_hal::{api::Vulkan as V, Api}; use wgpu_hal::{api::Vulkan as V, Api};
let xr_entry = super::xr_entry(); let xr_entry = super::xr_entry()?;
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
xr_entry.initialize_android_loader().unwrap(); xr_entry.initialize_android_loader()?;
let available_extensions = xr_entry.enumerate_extensions()?; let available_extensions = xr_entry.enumerate_extensions()?;
assert!(available_extensions.khr_vulkan_enable2); assert!(available_extensions.khr_vulkan_enable2);

View File

@@ -2,25 +2,41 @@ mod graphics;
pub mod input; pub mod input;
pub mod resource_macros; pub mod resource_macros;
pub mod resources; pub mod resources;
pub mod xr_init;
pub mod xr_input; pub mod xr_input;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
use crate::xr_init::RenderRestartPlugin;
use crate::xr_input::hands::hand_tracking::DisableHandTracking; use crate::xr_input::hands::hand_tracking::DisableHandTracking;
use crate::xr_input::oculus_touch::ActionSets; use crate::xr_input::oculus_touch::ActionSets;
use bevy::app::PluginGroupBuilder; use bevy::app::PluginGroupBuilder;
use bevy::ecs::system::SystemState; use bevy::ecs::system::{RunSystemOnce, SystemState};
use bevy::prelude::*; use bevy::prelude::*;
use bevy::render::camera::{ManualTextureView, ManualTextureViewHandle, ManualTextureViews}; use bevy::render::camera::{
CameraPlugin, ManualTextureView, ManualTextureViewHandle, ManualTextureViews,
};
use bevy::render::globals::GlobalsPlugin;
use bevy::render::mesh::morph::MorphPlugin;
use bevy::render::mesh::MeshPlugin;
use bevy::render::pipelined_rendering::PipelinedRenderingPlugin; use bevy::render::pipelined_rendering::PipelinedRenderingPlugin;
use bevy::render::renderer::{render_system, RenderInstance}; use bevy::render::render_asset::RenderAssetDependency;
use bevy::render::render_resource::ShaderLoader;
use bevy::render::renderer::{
render_system, RenderAdapter, RenderAdapterInfo, RenderDevice, RenderInstance, RenderQueue,
};
use bevy::render::settings::RenderCreation; use bevy::render::settings::RenderCreation;
use bevy::render::{Render, RenderApp, RenderPlugin, RenderSet}; use bevy::render::view::{self, ViewPlugin, WindowRenderPlugin};
use bevy::render::{color, primitives, Render, RenderApp, RenderPlugin, RenderSet};
use bevy::window::{PresentMode, PrimaryWindow, RawHandleWrapper}; use bevy::window::{PresentMode, PrimaryWindow, RawHandleWrapper};
use input::XrInput; use input::XrInput;
use openxr as xr; use openxr as xr;
use resources::*; use resources::*;
use xr::FormFactor; use xr::FormFactor;
use xr_init::{
init_non_xr_graphics, update_xr_stuff, xr_only, RenderCreationData, XrEnableRequest,
XrEnableStatus, XrRenderData, XrRenderUpdate,
};
use xr_input::controllers::XrControllerType; use xr_input::controllers::XrControllerType;
use xr_input::hands::emulated::HandEmulationPlugin; use xr_input::hands::emulated::HandEmulationPlugin;
use xr_input::hands::hand_tracking::{HandTrackingData, HandTrackingPlugin}; use xr_input::hands::hand_tracking::{HandTrackingData, HandTrackingPlugin};
@@ -63,14 +79,10 @@ pub struct FutureXrResources(
impl Plugin for OpenXrPlugin { impl Plugin for OpenXrPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
let future_xr_resources_wrapper = Arc::new(Mutex::new(None));
app.insert_resource(FutureXrResources(future_xr_resources_wrapper.clone()));
let mut system_state: SystemState<Query<&RawHandleWrapper, With<PrimaryWindow>>> = let mut system_state: SystemState<Query<&RawHandleWrapper, With<PrimaryWindow>>> =
SystemState::new(&mut app.world); SystemState::new(&mut app.world);
let primary_window = system_state.get(&app.world).get_single().ok().cloned(); let primary_window = system_state.get(&app.world).get_single().ok().cloned();
if let Ok((
let (
device, device,
queue, queue,
adapter_info, adapter_info,
@@ -87,126 +99,121 @@ impl Plugin for OpenXrPlugin {
input, input,
views, views,
frame_state, frame_state,
) = graphics::initialize_xr_graphics(primary_window).unwrap(); )) = graphics::initialize_xr_graphics(primary_window.clone())
// std::thread::sleep(Duration::from_secs(5)); {
debug!("Configured wgpu adapter Limits: {:#?}", device.limits()); // std::thread::sleep(Duration::from_secs(5));
debug!("Configured wgpu adapter Features: {:#?}", device.features()); debug!("Configured wgpu adapter Limits: {:#?}", device.limits());
let mut future_xr_resources_inner = future_xr_resources_wrapper.lock().unwrap(); debug!("Configured wgpu adapter Features: {:#?}", device.features());
*future_xr_resources_inner = Some(( app.insert_resource(xr_instance.clone());
xr_instance, app.insert_resource(session.clone());
session, app.insert_resource(blend_mode.clone());
blend_mode, app.insert_resource(resolution.clone());
resolution, app.insert_resource(format.clone());
format, app.insert_resource(session_running.clone());
session_running, app.insert_resource(frame_waiter.clone());
frame_waiter, app.insert_resource(swapchain.clone());
swapchain, app.insert_resource(input.clone());
input, app.insert_resource(views.clone());
views, app.insert_resource(frame_state.clone());
frame_state, let xr_data = XrRenderData {
)); xr_instance,
app.insert_resource(ActionSets(vec![])); xr_session: session,
app.add_plugins(RenderPlugin { xr_blend_mode: blend_mode,
render_creation: RenderCreation::Manual( xr_resolution: resolution,
device, xr_format: format,
queue, xr_session_running: session_running,
adapter_info, xr_frame_waiter: frame_waiter,
render_adapter, xr_swapchain: swapchain,
RenderInstance(Arc::new(instance)), xr_input: input,
), xr_views: views,
}); xr_frame_state: frame_state,
};
app.insert_resource(xr_data);
app.insert_resource(ActionSets(vec![]));
app.add_plugins(RenderPlugin {
render_creation: RenderCreation::Manual(
device,
queue,
adapter_info,
render_adapter,
RenderInstance(Arc::new(instance)),
),
});
} else {
app.add_plugins(RenderPlugin::default());
app.insert_resource(XrEnableStatus::Disabled);
}
} }
fn ready(&self, app: &App) -> bool { fn ready(&self, app: &App) -> bool {
app.world app.world
.get_resource::<FutureXrResources>() .get_resource::<XrEnableStatus>()
.and_then(|frr| frr.0.try_lock().map(|locked| locked.is_some()).ok()) .map(|frr| *frr != XrEnableStatus::Waiting)
.unwrap_or(true) .unwrap_or(true)
} }
fn finish(&self, app: &mut App) { fn finish(&self, app: &mut App) {
if let Some(future_renderer_resources) = app.world.remove_resource::<FutureXrResources>() { // TODO: Split this up into the indevidual resources
let ( if let Some(data) = app.world.get_resource::<XrRenderData>().cloned() {
xr_instance, // just calling this stuff because I already had the code, so...
session, app.insert_resource(XrEnableStatus::Enabled);
blend_mode, app.world.send_event(XrEnableRequest::TryEnable);
resolution, app.world.run_system_once(update_xr_stuff);
format, app.insert_resource(XrEnableStatus::Enabled);
session_running, //
frame_waiter, let hands = data.xr_instance.exts().ext_hand_tracking.is_some()
swapchain, && data
input, .xr_instance
views,
frame_state,
) = future_renderer_resources.0.lock().unwrap().take().unwrap();
let action_sets = app.world.resource::<ActionSets>().clone();
app.insert_resource(xr_instance.clone())
.insert_resource(session.clone())
.insert_resource(blend_mode.clone())
.insert_resource(resolution.clone())
.insert_resource(format.clone())
.insert_resource(session_running.clone())
.insert_resource(frame_waiter.clone())
.insert_resource(swapchain.clone())
.insert_resource(input.clone())
.insert_resource(views.clone())
.insert_resource(frame_state.clone())
.insert_resource(action_sets.clone());
let hands = xr_instance.exts().ext_hand_tracking.is_some()
&& xr_instance
.supports_hand_tracking( .supports_hand_tracking(
xr_instance data.xr_instance
.system(FormFactor::HEAD_MOUNTED_DISPLAY) .system(FormFactor::HEAD_MOUNTED_DISPLAY)
.unwrap(), .unwrap(),
) )
.is_ok_and(|v| v); .is_ok_and(|v| v);
if hands { if hands {
app.insert_resource(HandTrackingData::new(&session).unwrap()); app.insert_resource(HandTrackingData::new(&data.xr_session).unwrap());
} else { } else {
app.insert_resource(DisableHandTracking::Both); app.insert_resource(DisableHandTracking::Both);
} }
let (left, right) = swapchain.get_render_views(); let (left, right) = data.xr_swapchain.get_render_views();
let left = ManualTextureView { let left = ManualTextureView {
texture_view: left.into(), texture_view: left.into(),
size: *resolution, size: *data.xr_resolution,
format: *format, format: *data.xr_format,
}; };
let right = ManualTextureView { let right = ManualTextureView {
texture_view: right.into(), texture_view: right.into(),
size: *resolution, size: *data.xr_resolution,
format: *format, format: *data.xr_format,
}; };
app.add_systems(PreUpdate, xr_begin_frame); app.add_systems(PreUpdate, xr_begin_frame.run_if(xr_only()));
let mut manual_texture_views = app.world.resource_mut::<ManualTextureViews>(); let mut manual_texture_views = app.world.resource_mut::<ManualTextureViews>();
manual_texture_views.insert(LEFT_XR_TEXTURE_HANDLE, left); manual_texture_views.insert(LEFT_XR_TEXTURE_HANDLE, left);
manual_texture_views.insert(RIGHT_XR_TEXTURE_HANDLE, right); manual_texture_views.insert(RIGHT_XR_TEXTURE_HANDLE, right);
drop(manual_texture_views); drop(manual_texture_views);
let render_app = app.sub_app_mut(RenderApp); let render_app = app.sub_app_mut(RenderApp);
render_app render_app.insert_resource(data.xr_instance.clone());
.insert_resource(xr_instance) render_app.insert_resource(data.xr_session.clone());
.insert_resource(session) render_app.insert_resource(data.xr_blend_mode.clone());
.insert_resource(blend_mode) render_app.insert_resource(data.xr_resolution.clone());
.insert_resource(resolution) render_app.insert_resource(data.xr_format.clone());
.insert_resource(format) render_app.insert_resource(data.xr_session_running.clone());
.insert_resource(session_running) render_app.insert_resource(data.xr_frame_waiter.clone());
.insert_resource(frame_waiter) render_app.insert_resource(data.xr_swapchain.clone());
.insert_resource(swapchain) render_app.insert_resource(data.xr_input.clone());
.insert_resource(input) render_app.insert_resource(data.xr_views.clone());
.insert_resource(views) render_app.insert_resource(data.xr_frame_state.clone());
.insert_resource(frame_state) render_app.insert_resource(XrEnableStatus::Enabled);
.insert_resource(action_sets);
render_app.add_systems( render_app.add_systems(
Render, Render,
( (
post_frame post_frame
.run_if(xr_only())
.before(render_system) .before(render_system)
.after(RenderSet::ExtractCommands), .after(RenderSet::ExtractCommands),
end_frame.after(render_system), end_frame.run_if(xr_only()).after(render_system),
), ),
); );
} }
@@ -221,8 +228,9 @@ impl PluginGroup for DefaultXrPlugins {
.build() .build()
.disable::<RenderPlugin>() .disable::<RenderPlugin>()
.disable::<PipelinedRenderingPlugin>() .disable::<PipelinedRenderingPlugin>()
.add_before::<RenderPlugin, _>(OpenXrPlugin::default()) .add_before::<RenderPlugin, _>(OpenXrPlugin)
.add_after::<OpenXrPlugin, _>(OpenXrInput::new(XrControllerType::OculusTouch)) .add_after::<OpenXrPlugin, _>(OpenXrInput::new(XrControllerType::OculusTouch))
.add_before::<OpenXrPlugin, _>(RenderRestartPlugin)
.add(HandEmulationPlugin) .add(HandEmulationPlugin)
.add(HandTrackingPlugin) .add(HandTrackingPlugin)
.set(WindowPlugin { .set(WindowPlugin {

354
src/xr_init.rs Normal file
View File

@@ -0,0 +1,354 @@
// 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::{
XrEnvironmentBlendMode, XrFormat, XrFrameState, XrFrameWaiter, 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<Instance>,
}
#[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)]
pub enum XrEnableStatus {
Enabled,
Disabled,
Waiting,
}
#[derive(Resource, Event, Copy, Clone, PartialEq, Eq, Debug)]
pub enum XrNextEnabledState {
Enabled,
Disabled,
}
pub struct RenderRestartPlugin;
#[derive(Resource)]
pub struct ForceMain;
#[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<'_, XrEnableStatus>>) -> bool {
resource_exists_and_equals(XrEnableStatus::Enabled)
}
impl Plugin for RenderRestartPlugin {
fn build(&self, app: &mut App) {
add_schedules(app);
app.add_plugins(ExtractResourcePlugin::<XrRenderData>::default())
.insert_resource(ForceMain)
.add_event::<XrEnableRequest>()
.add_event::<XrEnableStatus>()
.add_systems(
PostUpdate,
update_xr_stuff.run_if(on_event::<XrEnableRequest>()),
)
.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);
}
}
fn clear_events(mut events: ResMut<Events<XrEnableRequest>>) {
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);
}
}
fn setup_xr(world: &mut World) {
world.run_schedule(XrPreSetup);
info!("PreSetup Done");
world.run_schedule(XrSetup);
info!("Setup Done");
world.run_schedule(XrPrePostSetup);
info!("PrePostSetup Done");
world.run_schedule(XrPostSetup);
info!("PostSetup Done");
}
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<Res<XrEnableStatus>>, session: Option<ResMut<XrSession>>) {
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);
}
// fn handle_xr_enable_requests(
// primary_window: Query<&RawHandleWrapper, With<PrimaryWindow>>,
// mut commands: Commands,
// next_state: Res<XrNextEnabledState>,
// on_main: Option<NonSend<ForceMain>>,
// ) {
// // Just to force this system onto the main thread because of unsafe code
// let _ = on_main;
//
// commands.insert_resource(XrEnableStatus::Waiting);
// 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::<XrRenderData>();
//
// commands.remove_resource::<XrInstance>();
// commands.remove_resource::<XrSession>();
// commands.remove_resource::<XrEnvironmentBlendMode>();
// commands.remove_resource::<XrResolution>();
// commands.remove_resource::<XrFormat>();
// commands.remove_resource::<XrSessionRunning>();
// commands.remove_resource::<XrFrameWaiter>();
// commands.remove_resource::<XrSwapchain>();
// commands.remove_resource::<XrInput>();
// commands.remove_resource::<XrViews>();
// commands.remove_resource::<XrFrameState>();
// }
// }
fn decide_next_xr_state(
mut commands: Commands,
mut events: EventReader<XrEnableRequest>,
xr_status: Option<Res<XrEnableStatus>>,
) {
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<RawHandleWrapper>) -> 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)
}

View File

@@ -2,7 +2,7 @@ use bevy::{prelude::*, utils::HashMap};
use openxr as xr; use openxr as xr;
use xr::{Action, Binding, Haptic, Posef}; use xr::{Action, Binding, Haptic, Posef};
use crate::resources::{XrInstance, XrSession}; use crate::{resources::{XrInstance, XrSession}, xr_init::XrPrePostSetup};
use super::oculus_touch::ActionSets; use super::oculus_touch::ActionSets;
@@ -12,11 +12,12 @@ impl Plugin for OpenXrActionsPlugin {
app.insert_resource(SetupActionSets { app.insert_resource(SetupActionSets {
sets: HashMap::new(), sets: HashMap::new(),
}); });
app.add_systems(PostStartup, setup_oxr_actions); app.add_systems(XrPrePostSetup, setup_oxr_actions);
} }
} }
pub fn setup_oxr_actions(world: &mut World) { pub fn setup_oxr_actions(world: &mut World) {
info!("huh?!");
let actions = world.remove_resource::<SetupActionSets>().unwrap(); let actions = world.remove_resource::<SetupActionSets>().unwrap();
let instance = world.get_resource::<XrInstance>().unwrap(); let instance = world.get_resource::<XrInstance>().unwrap();
let session = world.get_resource::<XrSession>().unwrap(); let session = world.get_resource::<XrSession>().unwrap();

View File

@@ -1,9 +1,11 @@
use bevy::ecs::schedule::IntoSystemConfigs;
use bevy::log::{debug, info}; use bevy::log::{debug, info};
use bevy::prelude::{ use bevy::prelude::{
Color, Gizmos, GlobalTransform, Plugin, Quat, Query, Res, Transform, Update, Vec2, Vec3, With, Color, Gizmos, GlobalTransform, Plugin, Quat, Query, Res, Transform, Update, Vec2, Vec3, With,
Without, Without,
}; };
use crate::xr_init::xr_only;
use crate::{ use crate::{
input::XrInput, input::XrInput,
resources::{XrFrameState, XrSession}, resources::{XrFrameState, XrSession},
@@ -25,34 +27,41 @@ pub struct OpenXrDebugRenderer;
impl Plugin for OpenXrDebugRenderer { impl Plugin for OpenXrDebugRenderer {
fn build(&self, app: &mut bevy::prelude::App) { fn build(&self, app: &mut bevy::prelude::App) {
app.add_systems(Update, draw_gizmos); app.add_systems(Update, draw_gizmos.run_if(xr_only()));
} }
} }
#[allow(clippy::too_many_arguments, clippy::complexity)]
pub fn draw_gizmos( pub fn draw_gizmos(
mut gizmos: Gizmos, mut gizmos: Gizmos,
oculus_controller: Res<OculusController>, oculus_controller: Res<OculusController>,
frame_state: Res<XrFrameState>, frame_state: Res<XrFrameState>,
xr_input: Res<XrInput>, xr_input: Res<XrInput>,
session: Res<XrSession>, session: Res<XrSession>,
tracking_root_query: Query<( tracking_root_query: Query<
&mut Transform, &mut Transform,
With<OpenXRTrackingRoot>, (
Without<OpenXRLeftController>, With<OpenXRTrackingRoot>,
Without<OpenXRRightController>, Without<OpenXRLeftController>,
)>, Without<OpenXRRightController>,
left_controller_query: Query<( ),
>,
left_controller_query: Query<
&GlobalTransform, &GlobalTransform,
With<OpenXRLeftController>, (
Without<OpenXRRightController>, With<OpenXRLeftController>,
Without<OpenXRTrackingRoot>, Without<OpenXRRightController>,
)>, Without<OpenXRTrackingRoot>,
right_controller_query: Query<( ),
>,
right_controller_query: Query<
&GlobalTransform, &GlobalTransform,
With<OpenXRRightController>, (
Without<OpenXRLeftController>, With<OpenXRRightController>,
Without<OpenXRTrackingRoot>, Without<OpenXRLeftController>,
)>, Without<OpenXRTrackingRoot>,
),
>,
action_sets: Res<XrActionSets>, action_sets: Res<XrActionSets>,
) { ) {
// if let Some(hand_tracking) = hand_tracking { // if let Some(hand_tracking) = hand_tracking {
@@ -89,7 +98,7 @@ pub fn draw_gizmos(
match root { match root {
Ok(position) => { Ok(position) => {
gizmos.circle( gizmos.circle(
position.0.translation position.translation
+ Vec3 { + Vec3 {
x: 0.0, x: 0.0,
y: 0.01, y: 0.01,
@@ -107,7 +116,7 @@ pub fn draw_gizmos(
let left_transform = left_controller_query.get_single(); let left_transform = left_controller_query.get_single();
match left_transform { match left_transform {
Ok(left_entity) => { Ok(left_entity) => {
draw_hand_gizmo(&mut gizmos, &controller, Hand::Left, left_entity.0); draw_hand_gizmo(&mut gizmos, &controller, Hand::Left, left_entity);
} }
Err(_) => debug!("no left controller entity for debug gizmos"), Err(_) => debug!("no left controller entity for debug gizmos"),
} }
@@ -115,7 +124,7 @@ pub fn draw_gizmos(
let right_transform = right_controller_query.get_single(); let right_transform = right_controller_query.get_single();
match right_transform { match right_transform {
Ok(right_entity) => { Ok(right_entity) => {
draw_hand_gizmo(&mut gizmos, &controller, Hand::Right, right_entity.0); draw_hand_gizmo(&mut gizmos, &controller, Hand::Right, right_entity);
} }
Err(_) => debug!("no right controller entity for debug gizmos"), Err(_) => debug!("no right controller entity for debug gizmos"),
} }

View File

@@ -5,6 +5,7 @@ use openxr::{ActionTy, HandJoint};
use super::common::{get_bone_gizmo_style, HandBoneRadius}; use super::common::{get_bone_gizmo_style, HandBoneRadius};
use crate::{ use crate::{
xr_init::{xr_only, XrSetup},
resources::{XrInstance, XrSession}, resources::{XrInstance, XrSession},
xr_input::{ xr_input::{
actions::{ actions::{
@@ -27,8 +28,11 @@ pub struct HandEmulationPlugin;
impl Plugin for HandEmulationPlugin { impl Plugin for HandEmulationPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(PreUpdate, update_hand_skeleton_from_emulated); app.add_systems(
app.add_systems(Startup, setup_hand_emulation_action_set); Update,
update_hand_skeleton_from_emulated.run_if(xr_only()),
);
app.add_systems(XrSetup, setup_hand_emulation_action_set);
} }
} }
@@ -87,7 +91,7 @@ fn setup_hand_emulation_action_set(mut action_sets: ResMut<SetupActionSets>) {
ActionHandednes::Double, ActionHandednes::Double,
); );
suggest_oculus_touch_profile(&mut action_set); suggest_oculus_touch_profile(action_set);
} }
pub struct EmulatedHandPoseData {} pub struct EmulatedHandPoseData {}

View File

@@ -8,7 +8,7 @@ use crate::{
xr_input::{ xr_input::{
hands::HandBone, trackers::OpenXRTrackingRoot, Hand, QuatConv, hands::HandBone, trackers::OpenXRTrackingRoot, Hand, QuatConv,
Vec3Conv, Vec3Conv,
}, }, xr_init::xr_only,
}; };
use super::common::HandBoneRadius; use super::common::HandBoneRadius;
@@ -128,7 +128,7 @@ impl Plugin for HandTrackingPlugin {
( (
update_hand_bones.run_if(|dh: Option<Res<DisableHandTracking>>| { update_hand_bones.run_if(|dh: Option<Res<DisableHandTracking>>| {
!dh.is_some_and(|v| *v == DisableHandTracking::Both) !dh.is_some_and(|v| *v == DisableHandTracking::Both)
}), }).run_if(xr_only()),
update_tracking_state_on_disable, update_tracking_state_on_disable,
), ),
); );

View File

@@ -9,13 +9,14 @@ pub mod prototype_locomotion;
pub mod trackers; pub mod trackers;
pub mod xr_camera; pub mod xr_camera;
use crate::xr_init::{XrPostSetup, XrSetup, xr_only};
use crate::resources::{XrInstance, XrSession}; use crate::resources::{XrInstance, XrSession};
use crate::xr_begin_frame; use crate::xr_begin_frame;
use crate::xr_input::controllers::XrControllerType; use crate::xr_input::controllers::XrControllerType;
use crate::xr_input::oculus_touch::setup_oculus_controller; use crate::xr_input::oculus_touch::setup_oculus_controller;
use crate::xr_input::xr_camera::{xr_camera_head_sync, Eye, XRProjection, XrCameraBundle}; use crate::xr_input::xr_camera::{xr_camera_head_sync, Eye, XRProjection, XrCameraBundle};
use bevy::app::{App, PostUpdate, Startup}; use bevy::app::{App, PostUpdate, Startup};
use bevy::log::warn; use bevy::log::{warn, info};
use bevy::prelude::{BuildChildren, Component, Deref, DerefMut, IntoSystemConfigs, Resource}; use bevy::prelude::{BuildChildren, Component, Deref, DerefMut, IntoSystemConfigs, Resource};
use bevy::prelude::{Commands, Plugin, PreUpdate, Quat, Res, SpatialBundle, Update, Vec3}; use bevy::prelude::{Commands, Plugin, PreUpdate, Quat, Res, SpatialBundle, Update, Vec3};
use bevy::render::camera::CameraProjectionPlugin; use bevy::render::camera::CameraProjectionPlugin;
@@ -52,27 +53,27 @@ impl Plugin for OpenXrInput {
app.add_plugins(CameraProjectionPlugin::<XRProjection>::default()); app.add_plugins(CameraProjectionPlugin::<XRProjection>::default());
app.add_plugins(OpenXrActionsPlugin); app.add_plugins(OpenXrActionsPlugin);
app.add_systems( app.add_systems(
PreUpdate, XrPostSetup,
(post_action_setup_oculus_controller.after(setup_oxr_actions),), post_action_setup_oculus_controller,
); );
match self.controller_type { match self.controller_type {
XrControllerType::OculusTouch => { XrControllerType::OculusTouch => {
app.add_systems(Startup, setup_oculus_controller); app.add_systems(XrSetup, setup_oculus_controller);
} }
} }
//adopt any new trackers //adopt any new trackers
app.add_systems(PreUpdate, adopt_open_xr_trackers); app.add_systems(PreUpdate, adopt_open_xr_trackers.run_if(xr_only()));
app.add_systems(PreUpdate, action_set_system); // app.add_systems(PreUpdate, action_set_system);
app.add_systems(PreUpdate, xr_camera_head_sync.after(xr_begin_frame)); app.add_systems(PreUpdate, xr_camera_head_sync.run_if(xr_only()).after(xr_begin_frame));
//update controller trackers //update controller trackers
app.add_systems(Update, update_open_xr_controllers); app.add_systems(Update, update_open_xr_controllers.run_if(xr_only()));
app.add_systems( app.add_systems(
PostUpdate, PostUpdate,
update_frusta::<XRProjection> update_frusta::<XRProjection>
.after(TransformSystem::TransformPropagate) .after(TransformSystem::TransformPropagate)
.before(VisibilitySystems::UpdatePerspectiveFrusta), .before(VisibilitySystems::UpdatePerspectiveFrusta),
); );
app.add_systems(Startup, setup_xr_cameras); app.add_systems(XrSetup, setup_xr_cameras);
} }
} }
@@ -88,6 +89,7 @@ fn setup_binding_recommendations(
} }
fn setup_xr_cameras(mut commands: Commands) { fn setup_xr_cameras(mut commands: Commands) {
info!("WTF?!");
//this needs to do the whole xr tracking volume not just cameras //this needs to do the whole xr tracking volume not just cameras
//get the root? //get the root?
let tracking_root = commands let tracking_root = commands