Skip to content

Commit

Permalink
move spawn_hand_bones from openxr to xr and add spawn handtracker com…
Browse files Browse the repository at this point in the history
…mand

Signed-off-by: Schmarni <marnistromer@gmail.com>
  • Loading branch information
Schmarni-Dev committed Oct 21, 2024
1 parent 302a455 commit 81b65c4
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 58 deletions.
108 changes: 52 additions & 56 deletions crates/bevy_openxr/src/openxr/features/handtracking.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use bevy::prelude::*;
use bevy_mod_xr::hands::{HandBone, HandBoneRadius};
use bevy_mod_xr::hands::{LeftHand, RightHand, XrHandBoneEntities, HAND_JOINT_COUNT};
use bevy_mod_xr::hands::{
spawn_hand_bones, HandBone, HandBoneRadius, HandSide, SpawnHandTracker,
SpawnHandTrackerCommandExecutor,
};
use bevy_mod_xr::hands::{LeftHand, RightHand, XrHandBoneEntities};
use bevy_mod_xr::session::{XrPreDestroySession, XrSessionCreated, XrTrackingRoot};
use bevy_mod_xr::spaces::{
XrPrimaryReferenceSpace, XrReferenceSpace, XrSpaceLocationFlags, XrSpaceVelocityFlags,
Expand All @@ -9,11 +12,11 @@ use bevy_mod_xr::spaces::{
use openxr::{SpaceLocationFlags, SpaceVelocityFlags};

use crate::helper_traits::ToVec3;
use crate::openxr_session_running;
use crate::resources::OxrFrameState;
use crate::resources::Pipelined;
use crate::session::OxrSession;
use crate::spaces::{OxrSpaceLocationFlags, OxrSpaceVelocityFlags};
use crate::{openxr_session_available, openxr_session_running};

pub struct HandTrackingPlugin {
default_hands: bool,
Expand All @@ -33,42 +36,24 @@ impl Plugin for HandTrackingPlugin {
app.add_systems(XrPreDestroySession, clean_up_default_hands)
.add_systems(XrSessionCreated, spawn_default_hands);
}
app.add_systems(Startup, set_spawn_executor.run_if(openxr_session_available));
}
}

pub fn spawn_hand_bones<T: Bundle + Clone>(
cmds: &mut Commands,
bundle: T,
) -> [Entity; HAND_JOINT_COUNT] {
let mut bones: [Entity; HAND_JOINT_COUNT] = [Entity::PLACEHOLDER; HAND_JOINT_COUNT];
// screw you clippy, i don't see a better way to init this array
#[allow(clippy::needless_range_loop)]
for bone in HandBone::get_all_bones().into_iter() {
bones[bone as usize] = cmds
.spawn((
SpatialBundle::default(),
bone,
HandBoneRadius(0.0),
OxrSpaceLocationFlags(openxr::SpaceLocationFlags::default()),
XrSpaceLocationFlags::default(),
))
.insert(bundle.clone())
.id();
}
bones
fn set_spawn_executor(mut cmds: Commands) {
cmds.insert_resource(SpawnHandTrackerCommandExecutor(handle_tracker_spawn))
}

fn spawn_default_hands(
mut cmds: Commands,
session: Res<OxrSession>,
root: Query<Entity, With<XrTrackingRoot>>,
) {
debug!("spawning default hands");
let Ok(root) = root.get_single() else {
error!("unable to get tracking root, skipping hand creation");
fn handle_tracker_spawn(world: &mut World, tracker: Entity, side: HandSide) {
let Some(session) = world.get_resource_mut::<OxrSession>() else {
error!("unable to get session while creating hand tracker");
return;
};
let tracker_left = match session.create_hand_tracker(openxr::HandEXT::LEFT) {
debug!("spawning hand");
let oxr_tracker = match session.create_hand_tracker(match side {
HandSide::Left => openxr::HandEXT::LEFT,
HandSide::Right => openxr::HandEXT::RIGHT,
}) {
Ok(t) => t,
Err(openxr::sys::Result::ERROR_EXTENSION_NOT_PRESENT) => {
warn!("Handtracking Extension not loaded, Unable to create Handtracker!");
Expand All @@ -79,33 +64,44 @@ fn spawn_default_hands(
return;
}
};
let tracker_right = match session.create_hand_tracker(openxr::HandEXT::RIGHT) {
Ok(t) => t,
Err(openxr::sys::Result::ERROR_EXTENSION_NOT_PRESENT) => {
warn!("Handtracking Extension not loaded, Unable to create Handtracker!");
return;
}
Err(err) => {
warn!("Error while creating Handtracker: {}", err.to_string());
return;
}

world
.entity_mut(tracker)
.insert(OxrHandTracker(oxr_tracker));
}

fn spawn_default_hands(mut cmds: Commands, root: Query<Entity, With<XrTrackingRoot>>) {
let Ok(root) = root.get_single() else {
error!("unable to get tracking root, skipping handtracker creation");
return;
};
let left_bones = spawn_hand_bones(&mut cmds, (DefaultHandBone, LeftHand));
let right_bones = spawn_hand_bones(&mut cmds, (DefaultHandBone, RightHand));
debug!("spawning default hands");
let left_bones = spawn_hand_bones(&mut cmds, |_| {
(
DefaultHandBone,
LeftHand,
OxrSpaceLocationFlags(openxr::SpaceLocationFlags::default()),
)
});
let right_bones = spawn_hand_bones(&mut cmds, |_| {
(
DefaultHandBone,
RightHand,
OxrSpaceLocationFlags(openxr::SpaceLocationFlags::default()),
)
});
cmds.entity(root).push_children(&left_bones);
cmds.entity(root).push_children(&right_bones);
cmds.spawn((
DefaultHandTracker,
OxrHandTracker(tracker_left),
XrHandBoneEntities(left_bones),
LeftHand,
));
cmds.spawn((
DefaultHandTracker,
OxrHandTracker(tracker_right),
XrHandBoneEntities(right_bones),
RightHand,
));
cmds.push(SpawnHandTracker {
joints: XrHandBoneEntities(left_bones),
tracker_bundle: DefaultHandTracker,
side: HandSide::Left,
});
cmds.push(SpawnHandTracker {
joints: XrHandBoneEntities(right_bones),
tracker_bundle: DefaultHandTracker,
side: HandSide::Right,
});
}

#[derive(Component, Clone, Copy)]
Expand Down
78 changes: 76 additions & 2 deletions crates/bevy_xr/src/hands.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,50 @@
use bevy::{
ecs::{component::Component, entity::Entity},
app::Plugin,
ecs::{component::Component, entity::Entity, world::Command},
hierarchy::BuildWorldChildren,
log::{error, warn},
math::bool,
prelude::{Deref, DerefMut},
prelude::{Bundle, Commands, Deref, DerefMut, Resource, SpatialBundle, With, World},
};

use crate::{
session::{XrSessionCreated, XrTrackingRoot},
spaces::XrSpaceLocationFlags,
};
pub const HAND_JOINT_COUNT: usize = 26;

pub fn spawn_hand_bones<T: Bundle>(
cmds: &mut Commands,
mut get_bundle: impl FnMut(HandBone) -> T,
) -> [Entity; HAND_JOINT_COUNT] {
let mut bones: [Entity; HAND_JOINT_COUNT] = [Entity::PLACEHOLDER; HAND_JOINT_COUNT];
for bone in HandBone::get_all_bones().into_iter() {
bones[bone as usize] = cmds
.spawn((
SpatialBundle::default(),
bone,
HandBoneRadius(0.0),
XrSpaceLocationFlags::default(),
))
.insert((get_bundle)(bone))
.id();
}
bones
}

#[derive(Clone, Copy, Component, Debug)]
pub enum HandSide {
Left,
Right,
}

#[derive(Clone, Copy, Component, Debug)]
pub struct LeftHand;

#[derive(Clone, Copy, Component, Debug)]
pub struct RightHand;

/// Hand Joint Entities orderd
#[derive(Deref, DerefMut, Component, Clone, Copy)]
pub struct XrHandBoneEntities(pub [Entity; HAND_JOINT_COUNT]);

Expand Down Expand Up @@ -141,3 +175,43 @@ impl HandBone {
]
}
}

/// Use by a backend to run custom logic when spawning a hand tracker
#[derive(Resource)]
pub struct SpawnHandTrackerCommandExecutor(pub fn(&mut World, Entity, HandSide));

/// `tracker_bundle` is inserted after the backend specific code is run
pub struct SpawnHandTracker<B: Bundle> {
pub joints: XrHandBoneEntities,
pub tracker_bundle: B,
pub side: HandSide,
}

impl<B: Bundle> Command for SpawnHandTracker<B> {
fn apply(self, world: &mut bevy::prelude::World) {
let Some(executor) = world.remove_resource::<SpawnHandTrackerCommandExecutor>() else {
warn!("no SpawnHandTracker executor defined, skipping handtracker creation");
return;
};
let Ok(root) = world
.query_filtered::<Entity, With<XrTrackingRoot>>()
.get_single(world)
else {
error!("unable to get tracking root, skipping handtracker creation");
return;
};
let mut tracker = world.spawn(self.joints);
match &self.side {
HandSide::Left => tracker.insert(LeftHand),
HandSide::Right => tracker.insert(LeftHand),
};
let tracker = tracker.id();
world.entity_mut(root).push_children(&[tracker]);
executor.0(world, tracker, self.side);
if let Some(mut tracker) = world.get_entity_mut(tracker) {
tracker.insert(self.side);
tracker.insert(self.tracker_bundle);
}
world.insert_resource(executor);
}
}

0 comments on commit 81b65c4

Please sign in to comment.