diff --git a/dash-frontend/src/frontend.rs b/dash-frontend/src/frontend.rs index a2f9c4d3..7a3fd543 100644 --- a/dash-frontend/src/frontend.rs +++ b/dash-frontend/src/frontend.rs @@ -22,7 +22,7 @@ use wgui::{ use wlx_common::{ async_executor::AsyncExecutor, audio, - dash_interface::{BoxDashInterface, ConfigChangeKind, RecenterMode}, + dash_interface::{BoxDashInterface, ConfigChangeKind, DashPlayspaceTask}, locale::WayVRLangProvider, palette::load_palette, timestep::{self, Timestep}, @@ -31,8 +31,8 @@ use wlx_common::{ use crate::{ assets, tab::{ - Tab, TabType, apps::TabApps, donate::TabDonate, games::TabGames, home::TabHome, monado::TabMonado, - settings::TabSettings, welcome::TabWelcome, + apps::TabApps, donate::TabDonate, games::TabGames, home::TabHome, monado::TabMonado, settings::TabSettings, + welcome::TabWelcome, Tab, TabType, }, util::{ popup_manager::{MountPopupOnceParams, PopupManager, PopupManagerParams}, @@ -553,7 +553,7 @@ impl Frontend { } fn action_recenter_playspace(&mut self, data: &mut T) -> anyhow::Result<()> { - self.interface.recenter_playspace(data, RecenterMode::Recenter)?; + self.interface.playspace(data, DashPlayspaceTask::Recenter)?; Ok(()) } diff --git a/dash-frontend/src/tab/settings/mod.rs b/dash-frontend/src/tab/settings/mod.rs index 36472a7b..a88b5bd8 100644 --- a/dash-frontend/src/tab/settings/mod.rs +++ b/dash-frontend/src/tab/settings/mod.rs @@ -23,7 +23,7 @@ use wgui::{ use wlx_common::{ config::GeneralConfig, config_io::ConfigRoot, - dash_interface::{ConfigChangeKind, InterfaceFeats, RecenterMode}, + dash_interface::{ConfigChangeKind, InterfaceFeats, DashPlayspaceTask}, }; use crate::{ @@ -201,7 +201,7 @@ impl Tab for TabSettings { std::fs::create_dir(&path)?; } Task::ResetPlayspace => { - frontend.interface.recenter_playspace(data, RecenterMode::Reset)?; + frontend.interface.playspace(data, DashPlayspaceTask::Reset)?; return Ok(()); } Task::RestartSoftware => { diff --git a/wayvr/src/backend/openvr/playspace.rs b/wayvr/src/backend/openvr/playspace.rs index 54ce0ae6..3c388a52 100644 --- a/wayvr/src/backend/openvr/playspace.rs +++ b/wayvr/src/backend/openvr/playspace.rs @@ -4,10 +4,12 @@ use ovr_overlay::{ compositor::CompositorManager, sys::{EChaperoneConfigFile, ETrackingUniverseOrigin, HmdMatrix34_t}, }; +use wgui::log::LogErr; +use wlx_common::config::GeneralConfig; use crate::{ backend::{input::InputState, playspace_common, task::PlayspaceTask}, - state::AppState, + state::{AppState, PlayspaceState, load_playspace_state, save_playspace_state}, windowing::manager::OverlayWindowManager, }; @@ -24,6 +26,7 @@ pub(super) struct PlayspaceMover { drag: Option>, rotate: Option>, floor_y: Option, + playspace_state: PlayspaceState, } impl PlayspaceMover { @@ -33,6 +36,7 @@ impl PlayspaceMover { drag: None, rotate: None, floor_y: None, + playspace_state: load_playspace_state().unwrap_or_default(), } } @@ -52,6 +56,9 @@ impl PlayspaceMover { PlayspaceTask::Recenter => { self.recenter(chaperone_mgr, &app.input_state); } + PlayspaceTask::SaveCenter => { + self.save_center(chaperone_mgr); + } } } @@ -305,6 +312,26 @@ impl PlayspaceMover { pub fn get_universe(&self) -> ETrackingUniverseOrigin { self.universe.clone() } + + pub fn save_center(&mut self, chaperone_mgr: &mut ChaperoneSetupManager) { + if self.drag.is_some() { + log::info!("Space drag interrupted by save center"); + self.drag = None; + } + if self.rotate.is_some() { + log::info!("Space rotate interrupted by save center"); + self.rotate = None; + } + + let Some(mat) = get_working_copy(&self.universe, chaperone_mgr) else { + log::warn!("Can't save center - failed to get zero pose"); + return; + }; + + self.playspace_state.openvr_space_center = mat; + let _ = + save_playspace_state(&self.playspace_state).log_err("Could not save playspace state"); + } } const fn universe_str(universe: &ETrackingUniverseOrigin) -> &'static str { diff --git a/wayvr/src/backend/openxr/playspace.rs b/wayvr/src/backend/openxr/playspace.rs index 4dd79faf..350c9d22 100644 --- a/wayvr/src/backend/openxr/playspace.rs +++ b/wayvr/src/backend/openxr/playspace.rs @@ -8,7 +8,7 @@ use crate::{ playspace_common::{self, SpaceGravity, SpaceGravityUpdateParams}, task::PlayspaceTask, }, - state::AppState, + state::{AppState, PlayspaceState, load_playspace_state}, windowing::manager::OverlayWindowManager, }; @@ -25,6 +25,7 @@ pub(super) struct PlayspaceMover { rotate: Option>, gravity: SpaceGravity, floor_y: f32, + playspace_state: PlayspaceState, } impl PlayspaceMover { @@ -42,6 +43,7 @@ impl PlayspaceMover { rotate: None, gravity: SpaceGravity::new(), floor_y: pose.position.y, + playspace_state: load_playspace_state().unwrap_or_default(), }) } @@ -60,6 +62,7 @@ impl PlayspaceMover { PlayspaceTask::Recenter => { self.recenter(&app.input_state, &mut monado.ipc); } + PlayspaceTask::SaveCenter => { /* OpenVR only */ } } } @@ -325,6 +328,28 @@ impl PlayspaceMover { .set_reference_space_offset(ReferenceSpaceType::Stage, pose) .inspect_err(|e| log::warn!("Could not fix floor due to libmonado error: {e:?}")); } + + pub fn save_center(&mut self, monado: &mut Monado) { + if self.drag.is_some() { + log::info!("Space drag interrupted by save center"); + self.drag = None; + } + if self.rotate.is_some() { + log::info!("Space rotate interrupted by save center"); + self.rotate = None; + } + + let Ok(mut pose) = monado + .get_reference_space_offset(ReferenceSpaceType::Stage) + .inspect_err(|e| log::warn!("Could not fix floor due to libmonado error: {e:?}")) + else { + return; + }; + + self.playspace_state.openxr_space_center = mat; + let _ = + save_playspace_state(&self.playspace_state).log_err("Could not save playspace state"); + } } fn apply_offset(transform: Affine3A, monado: &mut Monado) { diff --git a/wayvr/src/backend/task.rs b/wayvr/src/backend/task.rs index 1d710256..d86dca22 100644 --- a/wayvr/src/backend/task.rs +++ b/wayvr/src/backend/task.rs @@ -63,6 +63,8 @@ pub enum PlayspaceTask { Recenter, Reset, FixFloor, + #[cfg(feature = "openvr")] + SaveCenter, } #[derive(Debug, Clone)] diff --git a/wayvr/src/overlays/dashboard.rs b/wayvr/src/overlays/dashboard.rs index d8518522..a1084294 100644 --- a/wayvr/src/overlays/dashboard.rs +++ b/wayvr/src/overlays/dashboard.rs @@ -20,7 +20,7 @@ use wgui::{ widget::EventResult, }; use wlx_common::{ - dash_interface::{self, ConfigChangeKind, DashInterface, RecenterMode}, + dash_interface::{self, ConfigChangeKind, DashInterface, DashPlayspaceTask}, locale::WayVRLangProvider, overlays::{BackendAttrib, BackendAttribValue}, }; @@ -504,11 +504,17 @@ impl DashInterface for DashInterfaceLive { Ok(()) } - fn recenter_playspace(&mut self, app: &mut AppState, mode: RecenterMode) -> anyhow::Result<()> { + fn playspace_task( + &mut self, + app: &mut AppState, + mode: DashPlayspaceTask, + ) -> anyhow::Result<()> { let task = match mode { - RecenterMode::FixFloor => PlayspaceTask::FixFloor, - RecenterMode::Recenter => PlayspaceTask::Recenter, - RecenterMode::Reset => PlayspaceTask::Reset, + DashPlayspaceTask::FixFloor => PlayspaceTask::FixFloor, + DashPlayspaceTask::Recenter => PlayspaceTask::Recenter, + DashPlayspaceTask::Reset => PlayspaceTask::Reset, + #[cfg(feature = "openvr")] + DashPlayspaceTask::SaveCenter => PlayspaceTask::SaveCenter, }; app.tasks.enqueue(TaskType::Playspace(task)); Ok(()) diff --git a/wayvr/src/state.rs b/wayvr/src/state.rs index 91a6b8fc..20d61d95 100644 --- a/wayvr/src/state.rs +++ b/wayvr/src/state.rs @@ -336,3 +336,22 @@ pub fn load_pw_token_config() -> anyhow::Result { let conf: TokenConf = serde_yaml::from_str(yaml.as_str())?; Ok(conf.pw_tokens) } + +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[allow(dead_code)] +pub struct PlayspaceState { + pub openvr_space_center: Affine3A, + pub openxr_space_center: Affine3A, +} + +pub fn load_playspace_state() -> anyhow::Result { + let json = std::fs::read_to_string(config_io::get_config_file_path("playspace.json5"))?; + let state: PlayspaceState = serde_json5::from_str(json.as_str())?; + Ok(state) +} + +pub fn save_playspace_state(state: &PlayspaceState) -> anyhow::Result<()> { + let json = serde_json5::to_string(state)?; + std::fs::write(config_io::get_config_file_path("playspace.json5"), json)?; + Ok(()) +} diff --git a/wlx-common/src/dash_interface.rs b/wlx-common/src/dash_interface.rs index 5741e78c..f960fc06 100644 --- a/wlx-common/src/dash_interface.rs +++ b/wlx-common/src/dash_interface.rs @@ -37,10 +37,11 @@ pub struct MonadoDumpSessionFrame { } #[derive(Clone, Copy)] -pub enum RecenterMode { +pub enum DashPlayspaceTask { FixFloor, Recenter, Reset, + SaveCenter, } #[derive(Clone, Copy)] @@ -69,7 +70,7 @@ pub trait DashInterface { fn monado_brightness_set(&mut self, data: &mut T, brightness: f32) -> Option<()>; fn monado_metrics_set_enabled(&mut self, data: &mut T, enabled: bool) -> bool; fn monado_metrics_dump_session_frames(&mut self, data: &mut T) -> Vec; - fn recenter_playspace(&mut self, data: &mut T, mode: RecenterMode) -> anyhow::Result<()>; + fn playspace_task(&mut self, data: &mut T, mode: DashPlayspaceTask) -> anyhow::Result<()>; fn desktop_finder<'a>(&'a mut self, data: &'a mut T) -> &'a mut DesktopFinder; fn general_config<'a>(&'a mut self, data: &'a mut T) -> &'a mut GeneralConfig; fn config_changed(&mut self, data: &mut T, kind: ConfigChangeKind); diff --git a/wlx-common/src/dash_interface_emulated.rs b/wlx-common/src/dash_interface_emulated.rs index 376513d4..cca1c9da 100644 --- a/wlx-common/src/dash_interface_emulated.rs +++ b/wlx-common/src/dash_interface_emulated.rs @@ -5,7 +5,7 @@ use wayvr_ipc::{ use crate::{ config::GeneralConfig, - dash_interface::{self, ConfigChangeKind, DashInterface, RecenterMode}, + dash_interface::{self, ConfigChangeKind, DashInterface, DashPlayspaceTask}, desktop_finder::DesktopFinder, gen_id, }; @@ -217,7 +217,7 @@ impl DashInterface<()> for DashInterfaceEmulated { } } - fn recenter_playspace(&mut self, _: &mut (), _: RecenterMode) -> anyhow::Result<()> { + fn playspace(&mut self, _: &mut (), _: DashPlayspaceTask) -> anyhow::Result<()> { // stub! Ok(()) }