wayvr/src/backend/openvr/playspace.rs

173 lines
5.7 KiB
Rust

use glam::{Affine3A, Vec3A};
use ovr_overlay::{
chaperone_setup::ChaperoneSetupManager,
compositor::CompositorManager,
sys::{EChaperoneConfigFile, ETrackingUniverseOrigin, HmdMatrix34_t},
};
use crate::{
backend::{common::OverlayContainer, input::InputState},
state::AppState,
};
use super::{helpers::Affine3AConvert, overlay::OpenVrOverlayData};
struct DragData {
pose: Affine3A,
hand: usize,
hand_pos: Vec3A,
}
pub(super) struct PlayspaceMover {
universe: ETrackingUniverseOrigin,
last: Option<DragData>,
}
impl PlayspaceMover {
pub fn new() -> Self {
Self {
universe: ETrackingUniverseOrigin::TrackingUniverseRawAndUncalibrated,
last: None,
}
}
pub fn update(
&mut self,
chaperone_mgr: &mut ChaperoneSetupManager,
overlays: &mut OverlayContainer<OpenVrOverlayData>,
state: &AppState,
) {
let universe = self.universe.clone();
if let Some(data) = self.last.as_mut() {
let pointer = &state.input_state.pointers[data.hand];
if !pointer.now.space_drag {
self.last = None;
log::info!("End space drag");
return;
}
let new_hand =
state.input_state.pointers[data.hand].raw_pose.translation + data.pose.translation;
let relative_pos = data.pose.transform_vector3a(new_hand - data.hand_pos);
if relative_pos.length_squared() > 1000.0 {
log::warn!("Space drag too fast, ignoring");
return;
}
overlays.iter_mut().for_each(|overlay| {
if overlay.state.grabbable {
overlay.state.dirty = true;
overlay.state.transform.translation -= relative_pos;
}
});
data.pose.translation += relative_pos;
data.hand_pos = new_hand;
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_drag {
let Some(mat) = get_working_copy(&universe, chaperone_mgr) else {
log::warn!("Can't space drag - failed to get zero pose");
return;
};
let hand_pos = pointer.raw_pose.translation + mat.translation;
self.last = Some(DragData {
pose: mat,
hand: i,
hand_pos,
});
log::info!("Start space drag");
break;
}
}
}
}
pub fn reset_offset(&mut self, chaperone_mgr: &mut ChaperoneSetupManager) {
set_working_copy(&self.universe, chaperone_mgr, &Affine3A::IDENTITY);
chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live);
if self.last.is_some() {
log::info!("Space drag interrupted by manual reset");
self.last = None;
}
}
pub fn fix_floor(&mut self, chaperone_mgr: &mut ChaperoneSetupManager, input: &InputState) {
let y1 = input.pointers[0].pose.translation.y;
let y2 = input.pointers[1].pose.translation.y;
let Some(mut mat) = get_working_copy(&self.universe, chaperone_mgr) else {
log::warn!("Can't fix floor - failed to get zero pose");
return;
};
mat.translation.y += y1.min(y2) - 0.03;
set_working_copy(&self.universe, chaperone_mgr, &mat);
chaperone_mgr.commit_working_copy(EChaperoneConfigFile::EChaperoneConfigFile_Live);
}
pub fn playspace_changed(
&mut self,
compositor_mgr: &mut CompositorManager,
_chaperone_mgr: &mut ChaperoneSetupManager,
) {
let new_universe = compositor_mgr.get_tracking_space();
if new_universe != self.universe {
log::info!(
"Playspace changed: {} -> {}",
universe_str(&self.universe),
universe_str(&new_universe)
);
self.universe = new_universe;
}
if self.last.is_some() {
log::info!("Space drag interrupted by external change");
self.last = None;
}
}
pub fn get_universe(&self) -> ETrackingUniverseOrigin {
self.universe.clone()
}
}
fn universe_str(universe: &ETrackingUniverseOrigin) -> &'static str {
match universe {
ETrackingUniverseOrigin::TrackingUniverseSeated => "Seated",
ETrackingUniverseOrigin::TrackingUniverseStanding => "Standing",
ETrackingUniverseOrigin::TrackingUniverseRawAndUncalibrated => "Raw",
}
}
fn get_working_copy(
universe: &ETrackingUniverseOrigin,
chaperone_mgr: &mut ChaperoneSetupManager,
) -> Option<Affine3A> {
chaperone_mgr.revert_working_copy();
let mat = match universe {
ETrackingUniverseOrigin::TrackingUniverseStanding => {
chaperone_mgr.get_working_standing_zero_pose_to_raw_tracking_pose()
}
_ => chaperone_mgr.get_working_seated_zero_pose_to_raw_tracking_pose(),
};
mat.map(|m| m.to_affine())
}
fn set_working_copy(
universe: &ETrackingUniverseOrigin,
chaperone_mgr: &mut ChaperoneSetupManager,
mat: &Affine3A,
) {
let mat = HmdMatrix34_t::from_affine(mat);
match universe {
ETrackingUniverseOrigin::TrackingUniverseStanding => {
chaperone_mgr.set_working_standing_zero_pose_to_raw_tracking_pose(&mat)
}
_ => chaperone_mgr.set_working_seated_zero_pose_to_raw_tracking_pose(&mat),
};
}