diff --git a/src/backend/input.rs b/src/backend/input.rs index 28a41f8..4f46cfd 100644 --- a/src/backend/input.rs +++ b/src/backend/input.rs @@ -71,6 +71,9 @@ impl InputState { if hand.now.space_drag != hand.before.space_drag { log::debug!("Hand {}: space_drag {}", hand.idx, hand.now.space_drag); } + if hand.now.space_rotate != hand.before.space_rotate { + log::debug!("Hand {}: space_rotate {}", hand.idx, hand.now.space_rotate); + } if hand.now.click_modifier_right != hand.before.click_modifier_right { log::debug!( "Hand {}: click_modifier_right {}", @@ -189,6 +192,7 @@ pub struct PointerState { pub alt_click: bool, pub show_hide: bool, pub space_drag: bool, + pub space_rotate: bool, pub click_modifier_right: bool, pub click_modifier_middle: bool, } diff --git a/src/backend/openvr/input.rs b/src/backend/openvr/input.rs index e690988..aaf1700 100644 --- a/src/backend/openvr/input.rs +++ b/src/backend/openvr/input.rs @@ -36,6 +36,7 @@ const PATH_SCROLL: &str = "/actions/default/in/Scroll"; const PATH_ALT_CLICK: &str = "/actions/default/in/AltClick"; const PATH_SHOW_HIDE: &str = "/actions/default/in/ShowHide"; const PATH_SPACE_DRAG: &str = "/actions/default/in/SpaceDrag"; +const PATH_SPACE_ROTATE: &str = "/actions/default/in/SpaceRotate"; const PATH_CLICK_MODIFIER_RIGHT: &str = "/actions/default/in/ClickModifierRight"; const PATH_CLICK_MODIFIER_MIDDLE: &str = "/actions/default/in/ClickModifierMiddle"; @@ -50,6 +51,7 @@ pub(super) struct OpenVrInputSource { alt_click_hnd: ActionHandle, show_hide_hnd: ActionHandle, space_drag_hnd: ActionHandle, + space_rotate_hnd: ActionHandle, click_modifier_right_hnd: ActionHandle, click_modifier_middle_hnd: ActionHandle, } @@ -72,6 +74,7 @@ impl OpenVrInputSource { let alt_click_hnd = input.get_action_handle(PATH_ALT_CLICK)?; let show_hide_hnd = input.get_action_handle(PATH_SHOW_HIDE)?; let space_drag_hnd = input.get_action_handle(PATH_SPACE_DRAG)?; + let space_rotate_hnd = input.get_action_handle(PATH_SPACE_ROTATE)?; let click_modifier_right_hnd = input.get_action_handle(PATH_CLICK_MODIFIER_RIGHT)?; let click_modifier_middle_hnd = input.get_action_handle(PATH_CLICK_MODIFIER_MIDDLE)?; @@ -106,6 +109,7 @@ impl OpenVrInputSource { alt_click_hnd, show_hide_hnd, space_drag_hnd, + space_rotate_hnd, click_modifier_right_hnd, click_modifier_middle_hnd, hands, @@ -193,6 +197,11 @@ impl OpenVrInputSource { .map(|x| x.0.bState) .unwrap_or(false); + app_hand.now.space_rotate = input + .get_digital_action_data(self.space_rotate_hnd, hand.input_hnd) + .map(|x| x.0.bState) + .unwrap_or(false); + app_hand.now.click_modifier_right = input .get_digital_action_data(self.click_modifier_right_hnd, hand.input_hnd) .map(|x| x.0.bState) @@ -302,27 +311,19 @@ fn get_tracked_device( pub fn set_action_manifest(input: &mut InputManager) -> anyhow::Result<()> { let action_path = CONFIG_ROOT_PATH.join("actions.json"); - if !action_path.is_file() { - File::create(&action_path)?.write_all(include_bytes!("../../res/actions.json"))?; - } + File::create(&action_path)?.write_all(include_bytes!("../../res/actions.json"))?; let binding_path = CONFIG_ROOT_PATH.join("actions_binding_knuckles.json"); - if !binding_path.is_file() { - File::create(&binding_path)? - .write_all(include_bytes!("../../res/actions_binding_knuckles.json"))?; - } + File::create(&binding_path)? + .write_all(include_bytes!("../../res/actions_binding_knuckles.json"))?; let binding_path = CONFIG_ROOT_PATH.join("actions_binding_vive.json"); - if !binding_path.is_file() { - File::create(&binding_path)? - .write_all(include_bytes!("../../res/actions_binding_vive.json"))?; - } + File::create(&binding_path)? + .write_all(include_bytes!("../../res/actions_binding_vive.json"))?; let binding_path = CONFIG_ROOT_PATH.join("actions_binding_oculus.json"); - if !binding_path.is_file() { - File::create(&binding_path)? - .write_all(include_bytes!("../../res/actions_binding_oculus.json"))?; - } + File::create(&binding_path)? + .write_all(include_bytes!("../../res/actions_binding_oculus.json"))?; if let Err(e) = input.set_action_manifest(action_path.as_path()) { bail!("Failed to set action manifest: {}", e); diff --git a/src/backend/openvr/playspace.rs b/src/backend/openvr/playspace.rs index 9bdf584..98bd197 100644 --- a/src/backend/openvr/playspace.rs +++ b/src/backend/openvr/playspace.rs @@ -1,4 +1,4 @@ -use glam::{Affine3A, Vec3, Vec3A}; +use glam::{Affine3A, Quat, Vec3, Vec3A}; use ovr_overlay::{ chaperone_setup::ChaperoneSetupManager, compositor::CompositorManager, @@ -12,22 +12,24 @@ use crate::{ use super::{helpers::Affine3AConvert, overlay::OpenVrOverlayData}; -struct DragData { +struct MoverData { pose: Affine3A, hand: usize, - hand_pos: Vec3A, + hand_pose: T, } pub(super) struct PlayspaceMover { universe: ETrackingUniverseOrigin, - last: Option, + drag: Option>, + rotate: Option>, } impl PlayspaceMover { pub fn new() -> Self { Self { universe: ETrackingUniverseOrigin::TrackingUniverseRawAndUncalibrated, - last: None, + drag: None, + rotate: None, } } @@ -38,10 +40,72 @@ impl PlayspaceMover { state: &AppState, ) { let universe = self.universe.clone(); - if let Some(data) = self.last.as_mut() { + + if let Some(data) = self.rotate.as_mut() { + let pointer = &state.input_state.pointers[data.hand]; + if !pointer.now.space_rotate { + self.rotate = None; + log::info!("End space rotate"); + return; + } + + let new_hand = Quat::from_affine3(&state.input_state.pointers[data.hand].raw_pose); + + let dq = new_hand * data.hand_pose.conjugate(); + let rel_y = f32::atan2( + 2.0 * (dq.y * dq.w + dq.x * dq.z), + (2.0 * (dq.w * dq.w + dq.x * dq.x)) - 1.0, + ); + + let mut space_transform = Affine3A::from_rotation_y(rel_y); + let offset = (space_transform.transform_vector3a(state.input_state.hmd.translation) + - state.input_state.hmd.translation) + * -1.0; + let mut overlay_transform = Affine3A::from_rotation_y(-rel_y); + + overlay_transform.translation = offset; + space_transform.translation = offset; + + overlays.iter_mut().for_each(|overlay| { + if overlay.state.grabbable { + overlay.state.dirty = true; + overlay.state.transform.translation = + overlay_transform.transform_point3a(overlay.state.transform.translation); + } + }); + + data.pose = data.pose * space_transform; + data.hand_pose = new_hand; + + if self.universe == ETrackingUniverseOrigin::TrackingUniverseStanding { + apply_chaperone_transform(space_transform.inverse(), chaperone_mgr); + } + set_working_copy(&universe, chaperone_mgr, &data.pose); + chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live); + } else { + for (i, pointer) in state.input_state.pointers.iter().enumerate() { + if pointer.now.space_rotate { + let Some(mat) = get_working_copy(&universe, chaperone_mgr) else { + log::warn!("Can't space rotate - failed to get zero pose"); + return; + }; + let hand_pose = Quat::from_affine3(&pointer.raw_pose); + self.rotate = Some(MoverData { + pose: mat, + hand: i, + hand_pose, + }); + self.drag = None; + log::info!("Start space rotate"); + return; + } + } + } + + if let Some(data) = self.drag.as_mut() { let pointer = &state.input_state.pointers[data.hand]; if !pointer.now.space_drag { - self.last = None; + self.drag = None; log::info!("End space drag"); return; } @@ -49,7 +113,7 @@ impl PlayspaceMover { let new_hand = data .pose .transform_point3a(state.input_state.pointers[data.hand].raw_pose.translation); - let relative_pos = new_hand - data.hand_pos; + let relative_pos = new_hand - data.hand_pose; if relative_pos.length_squared() > 1000.0 { log::warn!("Space drag too fast, ignoring"); @@ -66,7 +130,7 @@ impl PlayspaceMover { }); data.pose.translation += relative_pos; - data.hand_pos = new_hand; + data.hand_pose = new_hand; if self.universe == ETrackingUniverseOrigin::TrackingUniverseStanding { apply_chaperone_offset(overlay_offset, chaperone_mgr); @@ -81,35 +145,44 @@ impl PlayspaceMover { return; }; let hand_pos = mat.transform_point3a(pointer.raw_pose.translation); - self.last = Some(DragData { + self.drag = Some(MoverData { pose: mat, hand: i, - hand_pos, + hand_pose: hand_pos, }); + self.rotate = None; log::info!("Start space drag"); - break; + return; } } } } pub fn reset_offset(&mut self, chaperone_mgr: &mut ChaperoneSetupManager, input: &InputState) { - let mut height = 1.7; + let mut height = 1.6; if let Some(mat) = get_working_copy(&self.universe, chaperone_mgr) { height = input.hmd.translation.y - mat.translation.y; + if self.universe == ETrackingUniverseOrigin::TrackingUniverseStanding { + apply_chaperone_transform(mat, chaperone_mgr); + } } - let xform = Affine3A::from_translation(Vec3::Y * height); - if self.universe == ETrackingUniverseOrigin::TrackingUniverseStanding { - chaperone_mgr.reload_from_disk(EChaperoneConfigFile::EChaperoneConfigFile_Live); - } + + let xform = if self.universe == ETrackingUniverseOrigin::TrackingUniverseSeated { + Affine3A::from_translation(Vec3::NEG_Y * height) + } else { + Affine3A::IDENTITY + }; + set_working_copy(&self.universe, chaperone_mgr, &xform); chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live); - if self.last.is_some() { + if self.drag.is_some() { log::info!("Space drag interrupted by manual reset"); - self.last = None; - } else { - log::info!("Playspace reset"); + self.drag = None; + } + if self.rotate.is_some() { + log::info!("Space rotate interrupted by manual reset"); + self.rotate = None; } } @@ -142,9 +215,13 @@ impl PlayspaceMover { self.universe = new_universe; } - if self.last.is_some() { + if self.drag.is_some() { log::info!("Space drag interrupted by external change"); - self.last = None; + self.drag = None; + } + if self.rotate.is_some() { + log::info!("Space rotate interrupted by external change"); + self.rotate = None; } } diff --git a/src/res/actions.json b/src/res/actions.json index 0411b91..64ee4ae 100644 --- a/src/res/actions.json +++ b/src/res/actions.json @@ -40,6 +40,11 @@ "type": "boolean", "requirement": "optional" }, + { + "name": "/actions/default/in/SpaceRotate", + "type": "boolean", + "requirement": "optional" + }, { "name": "/actions/default/in/LeftHand", "type": "pose",