clean up passthrough, change hand entity behavior and add cleanup steps to some plugins
This commit is contained in:
@@ -16,10 +16,10 @@ bevy_oxr.path = "../.."
|
|||||||
bevy = "0.12"
|
bevy = "0.12"
|
||||||
openxr = { git = "https://github.com/Ralith/openxrs", rev = "0177d2d", features = ["mint"] }
|
openxr = { git = "https://github.com/Ralith/openxrs", rev = "0177d2d", features = ["mint"] }
|
||||||
|
|
||||||
[profile.release]
|
# [profile.release]
|
||||||
lto = "fat"
|
# lto = "fat"
|
||||||
codegen-units = 1
|
# codegen-units = 1
|
||||||
panic = "abort"
|
# panic = "abort"
|
||||||
|
|
||||||
# This metadata is used by `cargo-apk` - `xbuild` uses the `manifest.yaml` instead.
|
# This metadata is used by `cargo-apk` - `xbuild` uses the `manifest.yaml` instead.
|
||||||
[package.metadata.android]
|
[package.metadata.android]
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ use bevy::prelude::*;
|
|||||||
use bevy::transform::components::Transform;
|
use bevy::transform::components::Transform;
|
||||||
use bevy_oxr::graphics::extensions::XrExtensions;
|
use bevy_oxr::graphics::extensions::XrExtensions;
|
||||||
use bevy_oxr::graphics::XrAppInfo;
|
use bevy_oxr::graphics::XrAppInfo;
|
||||||
use bevy_oxr::graphics::XrPreferdBlendMode::AlphaBlend;
|
use bevy_oxr::passthrough::{PausePassthrough, ResumePassthrough, XrPassthroughState};
|
||||||
use bevy_oxr::passthrough::{passthrough_layer_pause, passthrough_layer_resume};
|
use bevy_oxr::xr_init::xr_only;
|
||||||
use bevy_oxr::xr_init::XrRenderData;
|
|
||||||
use bevy_oxr::xr_input::debug_gizmos::OpenXrDebugRenderer;
|
use bevy_oxr::xr_input::debug_gizmos::OpenXrDebugRenderer;
|
||||||
|
use bevy_oxr::xr_input::hands::HandBone;
|
||||||
use bevy_oxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig};
|
use bevy_oxr::xr_input::prototype_locomotion::{proto_locomotion, PrototypeLocomotionConfig};
|
||||||
use bevy_oxr::xr_input::trackers::{
|
use bevy_oxr::xr_input::trackers::{
|
||||||
OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker,
|
OpenXRController, OpenXRLeftController, OpenXRRightController, OpenXRTracker,
|
||||||
@@ -25,16 +25,23 @@ fn main() {
|
|||||||
},
|
},
|
||||||
prefered_blend_mode: bevy_oxr::graphics::XrPreferdBlendMode::Opaque,
|
prefered_blend_mode: bevy_oxr::graphics::XrPreferdBlendMode::Opaque,
|
||||||
})
|
})
|
||||||
.add_plugins(OpenXrDebugRenderer)
|
// .add_plugins(OpenXrDebugRenderer)
|
||||||
.add_plugins(LogDiagnosticsPlugin::default())
|
.add_plugins(LogDiagnosticsPlugin::default())
|
||||||
.add_plugins(FrameTimeDiagnosticsPlugin)
|
.add_plugins(FrameTimeDiagnosticsPlugin)
|
||||||
.add_systems(Startup, setup)
|
.add_systems(Startup, setup)
|
||||||
.add_systems(Update, (proto_locomotion, toggle_passthrough))
|
.add_systems(Update, (proto_locomotion, toggle_passthrough).run_if(xr_only()))
|
||||||
|
.add_systems(Update, debug_hand_render.run_if(xr_only()))
|
||||||
.add_systems(Startup, spawn_controllers_example)
|
.add_systems(Startup, spawn_controllers_example)
|
||||||
.insert_resource(PrototypeLocomotionConfig::default())
|
.insert_resource(PrototypeLocomotionConfig::default())
|
||||||
.run();
|
.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn debug_hand_render(query: Query<&GlobalTransform, With<HandBone>>, mut gizmos: Gizmos) {
|
||||||
|
for transform in &query {
|
||||||
|
gizmos.sphere(transform.translation(), Quat::IDENTITY, 0.01, Color::RED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// set up a simple 3D scene
|
/// set up a simple 3D scene
|
||||||
fn setup(
|
fn setup(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
@@ -90,15 +97,18 @@ fn spawn_controllers_example(mut commands: Commands) {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does this work? Not getting logs
|
// TODO: make this a vr button
|
||||||
fn toggle_passthrough(keys: Res<Input<KeyCode>>, mut xr_data: ResMut<XrRenderData>) {
|
fn toggle_passthrough(
|
||||||
|
keys: Res<Input<KeyCode>>,
|
||||||
|
passthrough_state: Res<XrPassthroughState>,
|
||||||
|
mut resume: EventWriter<ResumePassthrough>,
|
||||||
|
mut pause: EventWriter<PausePassthrough>,
|
||||||
|
) {
|
||||||
if keys.just_pressed(KeyCode::Space) {
|
if keys.just_pressed(KeyCode::Space) {
|
||||||
if xr_data.xr_passthrough_active {
|
match *passthrough_state {
|
||||||
passthrough_layer_pause(xr_data);
|
XrPassthroughState::Unsupported => {}
|
||||||
bevy::log::info!("Passthrough paused");
|
XrPassthroughState::Running => pause.send_default(),
|
||||||
} else {
|
XrPassthroughState::Paused => resume.send_default(),
|
||||||
passthrough_layer_resume(xr_data);
|
|
||||||
bevy::log::info!("Passthrough resumed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ use bevy_oxr::{
|
|||||||
xr_input::{
|
xr_input::{
|
||||||
actions::XrActionSets,
|
actions::XrActionSets,
|
||||||
debug_gizmos::OpenXrDebugRenderer,
|
debug_gizmos::OpenXrDebugRenderer,
|
||||||
hands::common::{HandInputDebugRenderer, HandResource, HandsResource, OpenXrHandInput},
|
hands::common::{HandInputDebugRenderer, HandResource, HandsResource},
|
||||||
hands::HandBone,
|
hands::HandBone,
|
||||||
interactions::{
|
interactions::{
|
||||||
draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions,
|
draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions,
|
||||||
@@ -120,7 +120,7 @@ pub fn main() {
|
|||||||
//test capsule
|
//test capsule
|
||||||
.add_systems(Startup, spawn_capsule)
|
.add_systems(Startup, spawn_capsule)
|
||||||
//physics hands
|
//physics hands
|
||||||
.add_plugins(OpenXrHandInput)
|
// .add_plugins(OpenXrHandInput)
|
||||||
.add_plugins(HandInputDebugRenderer)
|
.add_plugins(HandInputDebugRenderer)
|
||||||
.add_systems(Startup, spawn_physics_hands)
|
.add_systems(Startup, spawn_physics_hands)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use bevy::prelude::*;
|
|||||||
use bevy::transform::components::Transform;
|
use bevy::transform::components::Transform;
|
||||||
use bevy_oxr::graphics::XrAppInfo;
|
use bevy_oxr::graphics::XrAppInfo;
|
||||||
use bevy_oxr::resources::XrViews;
|
use bevy_oxr::resources::XrViews;
|
||||||
use bevy_oxr::xr_input::hands::common::{HandInputDebugRenderer, OpenXrHandInput};
|
use bevy_oxr::xr_input::hands::common::HandInputDebugRenderer;
|
||||||
use bevy_oxr::xr_input::interactions::{
|
use bevy_oxr::xr_input::interactions::{
|
||||||
InteractionEvent, XRDirectInteractor, XRInteractorState, XRRayInteractor, XRSocketInteractor,
|
InteractionEvent, XRDirectInteractor, XRInteractorState, XRRayInteractor, XRSocketInteractor,
|
||||||
};
|
};
|
||||||
@@ -31,7 +31,6 @@ fn main() {
|
|||||||
.add_systems(Update, (proto_locomotion, pull_to_ground).chain())
|
.add_systems(Update, (proto_locomotion, pull_to_ground).chain())
|
||||||
.insert_resource(PrototypeLocomotionConfig::default())
|
.insert_resource(PrototypeLocomotionConfig::default())
|
||||||
.add_systems(Startup, spawn_controllers_example)
|
.add_systems(Startup, spawn_controllers_example)
|
||||||
.add_plugins(OpenXrHandInput)
|
|
||||||
.add_plugins(HandInputDebugRenderer)
|
.add_plugins(HandInputDebugRenderer)
|
||||||
.add_event::<InteractionEvent>()
|
.add_event::<InteractionEvent>()
|
||||||
.run();
|
.run();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use bevy_oxr::input::XrInput;
|
|||||||
use bevy_oxr::resources::{XrFrameState, XrSession};
|
use bevy_oxr::resources::{XrFrameState, XrSession};
|
||||||
|
|
||||||
use bevy_oxr::xr_input::actions::XrActionSets;
|
use bevy_oxr::xr_input::actions::XrActionSets;
|
||||||
use bevy_oxr::xr_input::hands::common::{HandInputDebugRenderer, OpenXrHandInput};
|
use bevy_oxr::xr_input::hands::common::HandInputDebugRenderer;
|
||||||
use bevy_oxr::xr_input::interactions::{
|
use bevy_oxr::xr_input::interactions::{
|
||||||
draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions,
|
draw_interaction_gizmos, draw_socket_gizmos, interactions, socket_interactions,
|
||||||
update_interactable_states, InteractionEvent, Touched, XRDirectInteractor, XRInteractable,
|
update_interactable_states, InteractionEvent, Touched, XRDirectInteractor, XRInteractable,
|
||||||
@@ -39,7 +39,6 @@ fn main() {
|
|||||||
.add_systems(Update, proto_locomotion)
|
.add_systems(Update, proto_locomotion)
|
||||||
.insert_resource(PrototypeLocomotionConfig::default())
|
.insert_resource(PrototypeLocomotionConfig::default())
|
||||||
.add_systems(Startup, spawn_controllers_example)
|
.add_systems(Startup, spawn_controllers_example)
|
||||||
.add_plugins(OpenXrHandInput)
|
|
||||||
.add_plugins(HandInputDebugRenderer)
|
.add_plugins(HandInputDebugRenderer)
|
||||||
.add_systems(
|
.add_systems(
|
||||||
Update,
|
Update,
|
||||||
|
|||||||
23
src/lib.rs
23
src/lib.rs
@@ -31,11 +31,13 @@ use openxr as xr;
|
|||||||
use passthrough::{PassthroughPlugin, XrPassthroughLayer, XrPassthroughState};
|
use passthrough::{PassthroughPlugin, XrPassthroughLayer, XrPassthroughState};
|
||||||
use resources::*;
|
use resources::*;
|
||||||
use xr_init::{
|
use xr_init::{
|
||||||
xr_after_wait_only, xr_only, xr_render_only, CleanupXrData, XrEarlyInitPlugin, XrHasWaited,
|
xr_after_wait_only, xr_only, xr_render_only, CleanupXrData, SetupXrData, XrEarlyInitPlugin,
|
||||||
XrShouldRender, XrStatus,
|
XrHasWaited, XrShouldRender, XrStatus,
|
||||||
};
|
};
|
||||||
use xr_input::controllers::XrControllerType;
|
use xr_input::controllers::XrControllerType;
|
||||||
use xr_input::hands::XrHandPlugins;
|
use xr_input::hands::emulated::HandEmulationPlugin;
|
||||||
|
use xr_input::hands::hand_tracking::HandTrackingPlugin;
|
||||||
|
use xr_input::hands::HandPlugin;
|
||||||
use xr_input::OpenXrInput;
|
use xr_input::OpenXrInput;
|
||||||
|
|
||||||
const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
|
const VIEW_TYPE: xr::ViewConfigurationType = xr::ViewConfigurationType::PRIMARY_STEREO;
|
||||||
@@ -51,11 +53,6 @@ pub struct OpenXrPlugin {
|
|||||||
app_info: XrAppInfo,
|
app_info: XrAppInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mr_test(mut commands: Commands, mut resume: EventWriter<ResumePassthrough>) {
|
|
||||||
commands.insert_resource(ClearColor(Color::rgba(0.0, 0.0, 0.0, 0.0)));
|
|
||||||
resume.send_default();
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Plugin for OpenXrPlugin {
|
impl Plugin for OpenXrPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.insert_resource(XrSessionRunning::new(AtomicBool::new(false)));
|
app.insert_resource(XrSessionRunning::new(AtomicBool::new(false)));
|
||||||
@@ -114,7 +111,6 @@ impl Plugin for OpenXrPlugin {
|
|||||||
app.add_plugins(RenderPlugin::default());
|
app.add_plugins(RenderPlugin::default());
|
||||||
app.insert_resource(XrStatus::Disabled);
|
app.insert_resource(XrStatus::Disabled);
|
||||||
}
|
}
|
||||||
app.add_systems(Update, mr_test.run_if(xr_only()));
|
|
||||||
app.add_systems(
|
app.add_systems(
|
||||||
PreUpdate,
|
PreUpdate,
|
||||||
xr_poll_events.run_if(|status: Res<XrStatus>| *status != XrStatus::NoInstance),
|
xr_poll_events.run_if(|status: Res<XrStatus>| *status != XrStatus::NoInstance),
|
||||||
@@ -146,8 +142,6 @@ impl Plugin for OpenXrPlugin {
|
|||||||
.run_if(xr_only())
|
.run_if(xr_only())
|
||||||
.run_if(xr_after_wait_only())
|
.run_if(xr_after_wait_only())
|
||||||
.run_if(xr_render_only())
|
.run_if(xr_render_only())
|
||||||
// Do NOT touch this ordering! idk why but you can NOT just put in a RenderSet
|
|
||||||
// right before rendering
|
|
||||||
.before(render_system)
|
.before(render_system)
|
||||||
.after(RenderSet::ExtractCommands),
|
.after(RenderSet::ExtractCommands),
|
||||||
// .in_set(RenderSet::Prepare),
|
// .in_set(RenderSet::Prepare),
|
||||||
@@ -224,7 +218,9 @@ impl PluginGroup for DefaultXrPlugins {
|
|||||||
.add_after::<OpenXrPlugin, _>(OpenXrInput::new(XrControllerType::OculusTouch))
|
.add_after::<OpenXrPlugin, _>(OpenXrInput::new(XrControllerType::OculusTouch))
|
||||||
.add_after::<OpenXrPlugin, _>(XrInitPlugin)
|
.add_after::<OpenXrPlugin, _>(XrInitPlugin)
|
||||||
.add_before::<OpenXrPlugin, _>(XrEarlyInitPlugin)
|
.add_before::<OpenXrPlugin, _>(XrEarlyInitPlugin)
|
||||||
.add(XrHandPlugins)
|
.add(HandPlugin)
|
||||||
|
.add(HandTrackingPlugin)
|
||||||
|
.add(HandEmulationPlugin)
|
||||||
.add(PassthroughPlugin)
|
.add(PassthroughPlugin)
|
||||||
.add(XrResourcePlugin)
|
.add(XrResourcePlugin)
|
||||||
.set(WindowPlugin {
|
.set(WindowPlugin {
|
||||||
@@ -259,6 +255,7 @@ fn xr_poll_events(
|
|||||||
session: Option<Res<XrSession>>,
|
session: Option<Res<XrSession>>,
|
||||||
session_running: Res<XrSessionRunning>,
|
session_running: Res<XrSessionRunning>,
|
||||||
mut app_exit: EventWriter<AppExit>,
|
mut app_exit: EventWriter<AppExit>,
|
||||||
|
mut setup_xr: EventWriter<SetupXrData>,
|
||||||
mut cleanup_xr: EventWriter<CleanupXrData>,
|
mut cleanup_xr: EventWriter<CleanupXrData>,
|
||||||
) {
|
) {
|
||||||
if let (Some(instance), Some(session)) = (instance, session) {
|
if let (Some(instance), Some(session)) = (instance, session) {
|
||||||
@@ -274,6 +271,7 @@ fn xr_poll_events(
|
|||||||
xr::SessionState::READY => {
|
xr::SessionState::READY => {
|
||||||
info!("Calling Session begin :3");
|
info!("Calling Session begin :3");
|
||||||
session.begin(VIEW_TYPE).unwrap();
|
session.begin(VIEW_TYPE).unwrap();
|
||||||
|
setup_xr.send_default();
|
||||||
session_running.store(true, std::sync::atomic::Ordering::Relaxed);
|
session_running.store(true, std::sync::atomic::Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
xr::SessionState::STOPPING => {
|
xr::SessionState::STOPPING => {
|
||||||
@@ -283,7 +281,6 @@ fn xr_poll_events(
|
|||||||
}
|
}
|
||||||
xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => {
|
xr::SessionState::EXITING | xr::SessionState::LOSS_PENDING => {
|
||||||
// app_exit.send(AppExit);
|
// app_exit.send(AppExit);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|||||||
@@ -25,10 +25,11 @@ pub enum XrPassthroughState {
|
|||||||
Paused,
|
Paused,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PassthroughPlugin;
|
|
||||||
xr_arc_resource_wrapper!(XrPassthrough, xr::Passthrough);
|
xr_arc_resource_wrapper!(XrPassthrough, xr::Passthrough);
|
||||||
xr_arc_resource_wrapper!(XrPassthroughLayer, xr::PassthroughLayer);
|
xr_arc_resource_wrapper!(XrPassthroughLayer, xr::PassthroughLayer);
|
||||||
|
|
||||||
|
pub struct PassthroughPlugin;
|
||||||
|
|
||||||
impl Plugin for PassthroughPlugin {
|
impl Plugin for PassthroughPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_event::<ResumePassthrough>();
|
app.add_event::<ResumePassthrough>();
|
||||||
@@ -78,20 +79,31 @@ fn check_passthrough_support(mut cmds: Commands, instance: Option<Res<XrInstance
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resume_passthrough(layer: Res<XrPassthroughLayer>, mut state: ResMut<XrPassthroughState>) {
|
fn resume_passthrough(
|
||||||
|
layer: Res<XrPassthroughLayer>,
|
||||||
|
mut state: ResMut<XrPassthroughState>,
|
||||||
|
mut clear_color: ResMut<ClearColor>,
|
||||||
|
) {
|
||||||
if let Err(e) = layer.resume() {
|
if let Err(e) = layer.resume() {
|
||||||
warn!("Unable to resume Passthrough: {}", e);
|
warn!("Unable to resume Passthrough: {}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
info!("<=> Resume Passthrough");
|
clear_color.set_a(0.0);
|
||||||
|
clear_color.set_r(0.0);
|
||||||
|
clear_color.set_g(0.0);
|
||||||
|
clear_color.set_b(0.0);
|
||||||
*state = XrPassthroughState::Running;
|
*state = XrPassthroughState::Running;
|
||||||
}
|
}
|
||||||
fn pause_passthrough(layer: Res<XrPassthroughLayer>, mut state: ResMut<XrPassthroughState>) {
|
fn pause_passthrough(
|
||||||
|
layer: Res<XrPassthroughLayer>,
|
||||||
|
mut state: ResMut<XrPassthroughState>,
|
||||||
|
mut clear_color: ResMut<ClearColor>,
|
||||||
|
) {
|
||||||
if let Err(e) = layer.pause() {
|
if let Err(e) = layer.pause() {
|
||||||
warn!("Unable to resume Passthrough: {}", e);
|
warn!("Unable to resume Passthrough: {}", e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
info!("<=> Pausing Passthrough");
|
clear_color.set_a(1.0);
|
||||||
*state = XrPassthroughState::Paused;
|
*state = XrPassthroughState::Paused;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,8 +112,8 @@ fn cleanup_passthrough(mut cmds: Commands) {
|
|||||||
cmds.remove_resource::<XrPassthroughLayer>();
|
cmds.remove_resource::<XrPassthroughLayer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_passthrough(mut cmds: Commands, instance: Res<XrInstance>, session: Res<XrSession>) {
|
fn setup_passthrough(mut cmds: Commands, session: Res<XrSession>) {
|
||||||
match create_passthrough(&instance, &session) {
|
match create_passthrough(&session) {
|
||||||
Ok((passthrough, layer)) => {
|
Ok((passthrough, layer)) => {
|
||||||
cmds.insert_resource(XrPassthrough::from(passthrough));
|
cmds.insert_resource(XrPassthrough::from(passthrough));
|
||||||
cmds.insert_resource(XrPassthroughLayer::from(layer));
|
cmds.insert_resource(XrPassthroughLayer::from(layer));
|
||||||
@@ -181,7 +193,6 @@ pub fn supports_passthrough(instance: &XrInstance, system: xr::SystemId) -> xr::
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn create_passthrough(
|
pub fn create_passthrough(
|
||||||
instance: &XrInstance,
|
|
||||||
xr_session: &XrSession,
|
xr_session: &XrSession,
|
||||||
) -> xr::Result<(xr::Passthrough, xr::PassthroughLayer)> {
|
) -> xr::Result<(xr::Passthrough, xr::PassthroughLayer)> {
|
||||||
let passthrough = match xr_session {
|
let passthrough = match xr_session {
|
||||||
@@ -199,28 +210,14 @@ pub fn create_passthrough(
|
|||||||
Ok((passthrough, passthrough_layer))
|
Ok((passthrough, passthrough_layer))
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[inline]
|
/// Enable Passthrough on xr startup
|
||||||
// pub fn passthrough_layer_resume(mut layer: ResMut<XrPassthroughLayer>, mut passthrough: ResMut<XrPassthrough>) -> xr::Result<()> {
|
/// just sends the [`ResumePassthrough`] event in [`XrSetup`]
|
||||||
// layer.resume()
|
pub struct EnablePassthroughStartup;
|
||||||
// }
|
|
||||||
|
|
||||||
// #[inline]
|
impl Plugin for EnablePassthroughStartup {
|
||||||
// pub fn passthrough_layer_pause(mut xr_data_resource: ResMut<XrRenderData>) -> xr::Result<()> {
|
fn build(&self, app: &mut App) {
|
||||||
// unsafe {
|
app.add_systems(XrSetup, |mut e: EventWriter<ResumePassthrough>| {
|
||||||
// let passthrough_layer = &xr_data_resource.xr_passthrough_layer;
|
e.send_default();
|
||||||
// {
|
});
|
||||||
// let passthrough_layer_locked = passthrough_layer.lock().unwrap();
|
}
|
||||||
// cvt((xr_data_resource
|
}
|
||||||
// .xr_instance
|
|
||||||
// .exts()
|
|
||||||
// .fb_passthrough
|
|
||||||
// .unwrap()
|
|
||||||
// .passthrough_layer_pause)(
|
|
||||||
// *passthrough_layer_locked
|
|
||||||
// ))?;
|
|
||||||
// }
|
|
||||||
// xr_data_resource.xr_passthrough_active = false;
|
|
||||||
// bevy::log::info!("Paused passthrough layer");
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ pub struct StartXrSession;
|
|||||||
pub struct EndXrSession;
|
pub struct EndXrSession;
|
||||||
|
|
||||||
#[derive(Event, Clone, Copy, Default)]
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
struct SetupXrData;
|
pub(crate) struct SetupXrData;
|
||||||
#[derive(Event, Clone, Copy, Default)]
|
#[derive(Event, Clone, Copy, Default)]
|
||||||
pub(crate) struct CleanupXrData;
|
pub(crate) struct CleanupXrData;
|
||||||
|
|
||||||
@@ -192,7 +192,6 @@ fn start_xr_session(
|
|||||||
commands.insert_resource(xr_views);
|
commands.insert_resource(xr_views);
|
||||||
commands.insert_resource(xr_frame_state);
|
commands.insert_resource(xr_frame_state);
|
||||||
*status = XrStatus::Enabling;
|
*status = XrStatus::Enabling;
|
||||||
setup_xr.send_default();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop_xr_session(session: ResMut<XrSession>, mut status: ResMut<XrStatus>) {
|
fn stop_xr_session(session: ResMut<XrSession>, mut status: ResMut<XrStatus>) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use xr::{Action, Binding, Haptic, Posef, Vector2f};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
resources::{XrInstance, XrSession},
|
resources::{XrInstance, XrSession},
|
||||||
xr_init::XrPrePostSetup,
|
xr_init::{XrCleanup, XrPrePostSetup, XrPreSetup},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::oculus_touch::ActionSets;
|
use super::oculus_touch::ActionSets;
|
||||||
@@ -16,11 +16,21 @@ pub use xr::sys::NULL_PATH;
|
|||||||
pub struct OpenXrActionsPlugin;
|
pub struct OpenXrActionsPlugin;
|
||||||
impl Plugin for OpenXrActionsPlugin {
|
impl Plugin for OpenXrActionsPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.insert_resource(SetupActionSets {
|
app.add_systems(XrPreSetup, insert_setup_action_sets);
|
||||||
|
app.add_systems(XrPrePostSetup, setup_oxr_actions);
|
||||||
|
app.add_systems(XrCleanup, clean_actions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn insert_setup_action_sets(mut cmds: Commands) {
|
||||||
|
cmds.insert_resource(SetupActionSets {
|
||||||
sets: HashMap::new(),
|
sets: HashMap::new(),
|
||||||
});
|
});
|
||||||
app.add_systems(XrPrePostSetup, setup_oxr_actions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clean_actions(mut cmds: Commands) {
|
||||||
|
cmds.remove_resource::<ActionSets>();
|
||||||
|
cmds.remove_resource::<XrActionSets>();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
use bevy::prelude::{
|
use bevy::{
|
||||||
|
core::Name,
|
||||||
|
prelude::{
|
||||||
default, Color, Commands, Component, Deref, DerefMut, Entity, Gizmos, Plugin, PostUpdate,
|
default, Color, Commands, Component, Deref, DerefMut, Entity, Gizmos, Plugin, PostUpdate,
|
||||||
Query, Resource, SpatialBundle, Startup, Transform,
|
Query, Resource, SpatialBundle, Startup, Transform,
|
||||||
|
},
|
||||||
|
transform::components::GlobalTransform,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::xr_input::{trackers::OpenXRTracker, Hand};
|
use crate::xr_input::{trackers::OpenXRTracker, Hand};
|
||||||
@@ -8,14 +12,14 @@ use crate::xr_input::{trackers::OpenXRTracker, Hand};
|
|||||||
use super::{BoneTrackingStatus, HandBone};
|
use super::{BoneTrackingStatus, HandBone};
|
||||||
|
|
||||||
/// add debug renderer for controllers
|
/// add debug renderer for controllers
|
||||||
#[derive(Default)]
|
// #[derive(Default)]
|
||||||
pub struct OpenXrHandInput;
|
// pub struct OpenXrHandInput;
|
||||||
|
//
|
||||||
impl Plugin for OpenXrHandInput {
|
// impl Plugin for OpenXrHandInput {
|
||||||
fn build(&self, app: &mut bevy::prelude::App) {
|
// fn build(&self, app: &mut bevy::prelude::App) {
|
||||||
app.add_systems(Startup, spawn_hand_entities);
|
// app.add_systems(Startup, spawn_hand_entities);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// add debug renderer for controllers
|
/// add debug renderer for controllers
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@@ -161,75 +165,46 @@ pub fn spawn_hand_entities(mut commands: Commands) {
|
|||||||
for bone in bones.iter() {
|
for bone in bones.iter() {
|
||||||
let boneid = commands
|
let boneid = commands
|
||||||
.spawn((
|
.spawn((
|
||||||
|
Name::new(format!("{:?} {:?}", hand, bone)),
|
||||||
SpatialBundle::default(),
|
SpatialBundle::default(),
|
||||||
bone.clone(),
|
*bone,
|
||||||
OpenXRTracker,
|
OpenXRTracker,
|
||||||
hand.clone(),
|
*hand,
|
||||||
BoneTrackingStatus::Emulated,
|
BoneTrackingStatus::Emulated,
|
||||||
HandBoneRadius(0.1),
|
HandBoneRadius(0.1),
|
||||||
))
|
))
|
||||||
.id();
|
.id();
|
||||||
match hand {
|
let hand_res = match hand {
|
||||||
Hand::Left => match bone {
|
Hand::Left => &mut hand_resource.left,
|
||||||
HandBone::Palm => hand_resource.left.palm = boneid,
|
Hand::Right => &mut hand_resource.right,
|
||||||
HandBone::Wrist => hand_resource.left.wrist = boneid,
|
};
|
||||||
HandBone::ThumbMetacarpal => hand_resource.left.thumb.metacarpal = boneid,
|
match bone {
|
||||||
HandBone::ThumbProximal => hand_resource.left.thumb.proximal = boneid,
|
HandBone::Palm => hand_res.palm = boneid,
|
||||||
HandBone::ThumbDistal => hand_resource.left.thumb.distal = boneid,
|
HandBone::Wrist => hand_res.wrist = boneid,
|
||||||
HandBone::ThumbTip => hand_resource.left.thumb.tip = boneid,
|
HandBone::ThumbMetacarpal => hand_res.thumb.metacarpal = boneid,
|
||||||
HandBone::IndexMetacarpal => hand_resource.left.index.metacarpal = boneid,
|
HandBone::ThumbProximal => hand_res.thumb.proximal = boneid,
|
||||||
HandBone::IndexProximal => hand_resource.left.index.proximal = boneid,
|
HandBone::ThumbDistal => hand_res.thumb.distal = boneid,
|
||||||
HandBone::IndexIntermediate => hand_resource.left.index.intermediate = boneid,
|
HandBone::ThumbTip => hand_res.thumb.tip = boneid,
|
||||||
HandBone::IndexDistal => hand_resource.left.index.distal = boneid,
|
HandBone::IndexMetacarpal => hand_res.index.metacarpal = boneid,
|
||||||
HandBone::IndexTip => hand_resource.left.index.tip = boneid,
|
HandBone::IndexProximal => hand_res.index.proximal = boneid,
|
||||||
HandBone::MiddleMetacarpal => hand_resource.left.middle.metacarpal = boneid,
|
HandBone::IndexIntermediate => hand_res.index.intermediate = boneid,
|
||||||
HandBone::MiddleProximal => hand_resource.left.middle.proximal = boneid,
|
HandBone::IndexDistal => hand_res.index.distal = boneid,
|
||||||
HandBone::MiddleIntermediate => hand_resource.left.middle.intermediate = boneid,
|
HandBone::IndexTip => hand_res.index.tip = boneid,
|
||||||
HandBone::MiddleDistal => hand_resource.left.middle.distal = boneid,
|
HandBone::MiddleMetacarpal => hand_res.middle.metacarpal = boneid,
|
||||||
HandBone::MiddleTip => hand_resource.left.middle.tip = boneid,
|
HandBone::MiddleProximal => hand_res.middle.proximal = boneid,
|
||||||
HandBone::RingMetacarpal => hand_resource.left.ring.metacarpal = boneid,
|
HandBone::MiddleIntermediate => hand_res.middle.intermediate = boneid,
|
||||||
HandBone::RingProximal => hand_resource.left.ring.proximal = boneid,
|
HandBone::MiddleDistal => hand_res.middle.distal = boneid,
|
||||||
HandBone::RingIntermediate => hand_resource.left.ring.intermediate = boneid,
|
HandBone::MiddleTip => hand_res.middle.tip = boneid,
|
||||||
HandBone::RingDistal => hand_resource.left.ring.distal = boneid,
|
HandBone::RingMetacarpal => hand_res.ring.metacarpal = boneid,
|
||||||
HandBone::RingTip => hand_resource.left.ring.tip = boneid,
|
HandBone::RingProximal => hand_res.ring.proximal = boneid,
|
||||||
HandBone::LittleMetacarpal => hand_resource.left.little.metacarpal = boneid,
|
HandBone::RingIntermediate => hand_res.ring.intermediate = boneid,
|
||||||
HandBone::LittleProximal => hand_resource.left.little.proximal = boneid,
|
HandBone::RingDistal => hand_res.ring.distal = boneid,
|
||||||
HandBone::LittleIntermediate => hand_resource.left.little.intermediate = boneid,
|
HandBone::RingTip => hand_res.ring.tip = boneid,
|
||||||
HandBone::LittleDistal => hand_resource.left.little.distal = boneid,
|
HandBone::LittleMetacarpal => hand_res.little.metacarpal = boneid,
|
||||||
HandBone::LittleTip => hand_resource.left.little.tip = boneid,
|
HandBone::LittleProximal => hand_res.little.proximal = boneid,
|
||||||
},
|
HandBone::LittleIntermediate => hand_res.little.intermediate = boneid,
|
||||||
Hand::Right => match bone {
|
HandBone::LittleDistal => hand_res.little.distal = boneid,
|
||||||
HandBone::Palm => hand_resource.right.palm = boneid,
|
HandBone::LittleTip => hand_res.little.tip = boneid,
|
||||||
HandBone::Wrist => hand_resource.right.wrist = boneid,
|
|
||||||
HandBone::ThumbMetacarpal => hand_resource.right.thumb.metacarpal = boneid,
|
|
||||||
HandBone::ThumbProximal => hand_resource.right.thumb.proximal = boneid,
|
|
||||||
HandBone::ThumbDistal => hand_resource.right.thumb.distal = boneid,
|
|
||||||
HandBone::ThumbTip => hand_resource.right.thumb.tip = boneid,
|
|
||||||
HandBone::IndexMetacarpal => hand_resource.right.index.metacarpal = boneid,
|
|
||||||
HandBone::IndexProximal => hand_resource.right.index.proximal = boneid,
|
|
||||||
HandBone::IndexIntermediate => hand_resource.right.index.intermediate = boneid,
|
|
||||||
HandBone::IndexDistal => hand_resource.right.index.distal = boneid,
|
|
||||||
HandBone::IndexTip => hand_resource.right.index.tip = boneid,
|
|
||||||
HandBone::MiddleMetacarpal => hand_resource.right.middle.metacarpal = boneid,
|
|
||||||
HandBone::MiddleProximal => hand_resource.right.middle.proximal = boneid,
|
|
||||||
HandBone::MiddleIntermediate => {
|
|
||||||
hand_resource.right.middle.intermediate = boneid
|
|
||||||
}
|
|
||||||
HandBone::MiddleDistal => hand_resource.right.middle.distal = boneid,
|
|
||||||
HandBone::MiddleTip => hand_resource.right.middle.tip = boneid,
|
|
||||||
HandBone::RingMetacarpal => hand_resource.right.ring.metacarpal = boneid,
|
|
||||||
HandBone::RingProximal => hand_resource.right.ring.proximal = boneid,
|
|
||||||
HandBone::RingIntermediate => hand_resource.right.ring.intermediate = boneid,
|
|
||||||
HandBone::RingDistal => hand_resource.right.ring.distal = boneid,
|
|
||||||
HandBone::RingTip => hand_resource.right.ring.tip = boneid,
|
|
||||||
HandBone::LittleMetacarpal => hand_resource.right.little.metacarpal = boneid,
|
|
||||||
HandBone::LittleProximal => hand_resource.right.little.proximal = boneid,
|
|
||||||
HandBone::LittleIntermediate => {
|
|
||||||
hand_resource.right.little.intermediate = boneid
|
|
||||||
}
|
|
||||||
HandBone::LittleDistal => hand_resource.right.little.distal = boneid,
|
|
||||||
HandBone::LittleTip => hand_resource.right.little.tip = boneid,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,16 +216,12 @@ pub struct HandBoneRadius(pub f32);
|
|||||||
|
|
||||||
pub fn draw_hand_entities(
|
pub fn draw_hand_entities(
|
||||||
mut gizmos: Gizmos,
|
mut gizmos: Gizmos,
|
||||||
query: Query<(&Transform, &HandBone, &HandBoneRadius)>,
|
query: Query<(&GlobalTransform, &HandBone, &HandBoneRadius)>,
|
||||||
) {
|
) {
|
||||||
for (transform, hand_bone, hand_bone_radius) in query.iter() {
|
for (transform, hand_bone, hand_bone_radius) in query.iter() {
|
||||||
let (_, color) = get_bone_gizmo_style(hand_bone);
|
let (_, color) = get_bone_gizmo_style(hand_bone);
|
||||||
gizmos.sphere(
|
let (_, rotation, translation) = transform.to_scale_rotation_translation();
|
||||||
transform.translation,
|
gizmos.sphere(translation, rotation, hand_bone_radius.0, color);
|
||||||
transform.rotation,
|
|
||||||
hand_bone_radius.0,
|
|
||||||
color,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,8 +92,6 @@ fn setup_hand_emulation_action_set(mut action_sets: ResMut<SetupActionSets>) {
|
|||||||
suggest_oculus_touch_profile(action_set);
|
suggest_oculus_touch_profile(action_set);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct EmulatedHandPoseData {}
|
|
||||||
|
|
||||||
fn suggest_oculus_touch_profile(action_set: &mut SetupActionSet) {
|
fn suggest_oculus_touch_profile(action_set: &mut SetupActionSet) {
|
||||||
action_set.suggest_binding(
|
action_set.suggest_binding(
|
||||||
"/interaction_profiles/oculus/touch_controller",
|
"/interaction_profiles/oculus/touch_controller",
|
||||||
@@ -131,7 +129,6 @@ pub(crate) fn update_hand_skeleton_from_emulated(
|
|||||||
action_sets: Res<XrActionSets>,
|
action_sets: Res<XrActionSets>,
|
||||||
left_controller_transform: Query<&Transform, With<OpenXRLeftController>>,
|
left_controller_transform: Query<&Transform, With<OpenXRLeftController>>,
|
||||||
right_controller_transform: Query<&Transform, With<OpenXRRightController>>,
|
right_controller_transform: Query<&Transform, With<OpenXRRightController>>,
|
||||||
tracking_root_transform: Query<&Transform, With<OpenXRTrackingRoot>>,
|
|
||||||
mut bones: Query<
|
mut bones: Query<
|
||||||
(
|
(
|
||||||
&mut Transform,
|
&mut Transform,
|
||||||
@@ -226,7 +223,6 @@ pub(crate) fn update_hand_skeleton_from_emulated(
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let trt = tracking_root_transform.single();
|
|
||||||
for (mut t, bone, hand, status, mut radius) in bones.iter_mut() {
|
for (mut t, bone, hand, status, mut radius) in bones.iter_mut() {
|
||||||
match status {
|
match status {
|
||||||
BoneTrackingStatus::Emulated => {}
|
BoneTrackingStatus::Emulated => {}
|
||||||
@@ -238,9 +234,9 @@ pub(crate) fn update_hand_skeleton_from_emulated(
|
|||||||
Hand::Left => 0,
|
Hand::Left => 0,
|
||||||
Hand::Right => 1,
|
Hand::Right => 1,
|
||||||
}][bone.get_index_from_bone()];
|
}][bone.get_index_from_bone()];
|
||||||
*t = t.with_scale(trt.scale);
|
// *t = t.with_scale(trt.scale);
|
||||||
*t = t.with_rotation(trt.rotation * t.rotation);
|
// *t = t.with_rotation(trt.rotation * t.rotation);
|
||||||
*t = t.with_translation(trt.transform_point(t.translation));
|
// *t = t.with_translation(trt.transform_point(t.translation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn update_hand_bones_emulated(
|
pub fn update_hand_bones_emulated(
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::{
|
|||||||
input::XrInput,
|
input::XrInput,
|
||||||
resources::{XrFrameState, XrSession},
|
resources::{XrFrameState, XrSession},
|
||||||
xr_init::xr_only,
|
xr_init::xr_only,
|
||||||
xr_input::{hands::HandBone, trackers::OpenXRTrackingRoot, Hand, QuatConv, Vec3Conv},
|
xr_input::{hands::HandBone, Hand, QuatConv, Vec3Conv},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::BoneTrackingStatus;
|
use super::BoneTrackingStatus;
|
||||||
@@ -158,7 +158,6 @@ pub fn update_hand_bones(
|
|||||||
hand_tracking: Option<Res<HandTrackingData>>,
|
hand_tracking: Option<Res<HandTrackingData>>,
|
||||||
xr_input: Res<XrInput>,
|
xr_input: Res<XrInput>,
|
||||||
xr_frame_state: Res<XrFrameState>,
|
xr_frame_state: Res<XrFrameState>,
|
||||||
root_query: Query<(&Transform, With<OpenXRTrackingRoot>, Without<HandBone>)>,
|
|
||||||
mut bones: Query<(
|
mut bones: Query<(
|
||||||
&mut Transform,
|
&mut Transform,
|
||||||
&Hand,
|
&Hand,
|
||||||
@@ -174,7 +173,6 @@ pub fn update_hand_bones(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (root_transform, _, _) = root_query.get_single().unwrap();
|
|
||||||
let left_hand_data = hand_ref.get_poses(Hand::Left);
|
let left_hand_data = hand_ref.get_poses(Hand::Left);
|
||||||
let right_hand_data = hand_ref.get_poses(Hand::Right);
|
let right_hand_data = hand_ref.get_poses(Hand::Right);
|
||||||
bones
|
bones
|
||||||
@@ -203,8 +201,7 @@ pub fn update_hand_bones(
|
|||||||
*status = BoneTrackingStatus::Tracked;
|
*status = BoneTrackingStatus::Tracked;
|
||||||
}
|
}
|
||||||
radius.0 = bone_data.radius;
|
radius.0 = bone_data.radius;
|
||||||
*transform = transform
|
transform.translation = bone_data.position;
|
||||||
.with_translation(root_transform.transform_point(bone_data.position))
|
transform.rotation = bone_data.orientation;
|
||||||
.with_rotation(root_transform.rotation * bone_data.orientation)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +1,50 @@
|
|||||||
use bevy::{app::PluginGroupBuilder, prelude::*};
|
use bevy::prelude::*;
|
||||||
use openxr::FormFactor;
|
use openxr::FormFactor;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
resources::{XrInstance, XrSession},
|
resources::{XrInstance, XrSession},
|
||||||
xr_init::XrPreSetup,
|
xr_init::{XrCleanup, XrPreSetup, XrSetup},
|
||||||
};
|
};
|
||||||
|
|
||||||
use self::{
|
use self::{
|
||||||
emulated::HandEmulationPlugin,
|
common::{spawn_hand_entities, HandBoneRadius, HandsResource},
|
||||||
hand_tracking::{DisableHandTracking, HandTrackingData, HandTrackingPlugin},
|
hand_tracking::{DisableHandTracking, HandTrackingData},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::{trackers::OpenXRTracker, Hand};
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
pub mod emulated;
|
pub mod emulated;
|
||||||
pub mod hand_tracking;
|
pub mod hand_tracking;
|
||||||
|
|
||||||
pub struct XrHandPlugins;
|
|
||||||
|
|
||||||
impl Plugin for XrHandPlugins {
|
|
||||||
fn build(&self, app: &mut App) {
|
|
||||||
app.add_plugins(HandTrackingPlugin)
|
|
||||||
.add_plugins(HandPlugin)
|
|
||||||
.add_plugins(HandEmulationPlugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct HandPlugin;
|
pub struct HandPlugin;
|
||||||
|
|
||||||
impl Plugin for HandPlugin {
|
impl Plugin for HandPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(XrPreSetup, check_for_handtracking);
|
app.add_systems(XrPreSetup, check_for_handtracking);
|
||||||
|
app.add_systems(XrSetup, spawn_hand_entities);
|
||||||
|
app.add_systems(XrCleanup, despawn_hand_entities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn despawn_hand_entities(
|
||||||
|
mut commands: Commands,
|
||||||
|
hand_entities: Query<
|
||||||
|
Entity,
|
||||||
|
(
|
||||||
|
With<OpenXRTracker>,
|
||||||
|
With<HandBone>,
|
||||||
|
With<BoneTrackingStatus>,
|
||||||
|
),
|
||||||
|
>,
|
||||||
|
) {
|
||||||
|
for e in &hand_entities {
|
||||||
|
commands.entity(e).despawn_recursive();
|
||||||
|
}
|
||||||
|
commands.remove_resource::<HandsResource>()
|
||||||
|
}
|
||||||
|
|
||||||
fn check_for_handtracking(
|
fn check_for_handtracking(
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
instance: Res<XrInstance>,
|
instance: Res<XrInstance>,
|
||||||
@@ -86,21 +98,17 @@ pub enum HandBone {
|
|||||||
}
|
}
|
||||||
impl HandBone {
|
impl HandBone {
|
||||||
pub fn is_finger(&self) -> bool {
|
pub fn is_finger(&self) -> bool {
|
||||||
match &self {
|
!matches!(self, HandBone::Wrist | HandBone::Palm)
|
||||||
HandBone::Wrist => false,
|
|
||||||
HandBone::Palm => false,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pub fn is_metacarpal(&self) -> bool {
|
pub fn is_metacarpal(&self) -> bool {
|
||||||
match &self {
|
matches!(
|
||||||
HandBone::ThumbMetacarpal => true,
|
self,
|
||||||
HandBone::IndexMetacarpal => true,
|
HandBone::ThumbMetacarpal
|
||||||
HandBone::MiddleMetacarpal => true,
|
| HandBone::IndexMetacarpal
|
||||||
HandBone::RingMetacarpal => true,
|
| HandBone::MiddleMetacarpal
|
||||||
HandBone::LittleTip => true,
|
| HandBone::RingMetacarpal
|
||||||
_ => false,
|
| HandBone::LittleTip
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
pub const fn get_all_bones() -> [HandBone; 26] {
|
pub const fn get_all_bones() -> [HandBone; 26] {
|
||||||
[
|
[
|
||||||
|
|||||||
Reference in New Issue
Block a user