diff --git a/Cargo.lock b/Cargo.lock index 5c63388c..4512782d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -761,6 +761,27 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enumset" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19be8061a06ab6f3a6cf21106c873578bf01bd42ad15e0311a9c76161cb1c753" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e7b551eba279bf0fa88b83a46330168c1560a52a94f5126f892f0b364ab3e0" +dependencies = [ + "darling 0.14.2", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "env_logger" version = "0.9.3" @@ -1500,6 +1521,7 @@ dependencies = [ "num-complex", "num-rational", "num-traits", + "serde", "simba 0.7.3", "typenum", ] @@ -1657,6 +1679,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ae39348c8bc5fbd7f40c727a9925f03517afd2ab27d46702108b6a7e5414c19" dependencies = [ "num-traits", + "serde", ] [[package]] @@ -1812,10 +1835,10 @@ dependencies = [ [[package]] name = "ovr_overlay" version = "0.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bca515c469ad7eb699480b5dc61d1c83e1e9694e7c39435ce458a3f9fbdce14" +source = "git+https://github.com/TheButlah/ovr_overlay#ffc57149724a9efade7160a2494a882d4c7c92fd" dependencies = [ "derive_more", + "enumset", "lazy_static", "log", "nalgebra 0.30.1", @@ -1827,8 +1850,7 @@ dependencies = [ [[package]] name = "ovr_overlay_sys" version = "0.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b5e4888d82a67dd8c3d47103aa751083bfe88de063ece9846715c2a78fcbab" +source = "git+https://github.com/TheButlah/ovr_overlay#ffc57149724a9efade7160a2494a882d4c7c92fd" dependencies = [ "autocxx", "autocxx-build", @@ -2414,6 +2436,8 @@ dependencies = [ "num-derive", "num-traits", "ovr_overlay", + "serde", + "serde_json", "solarxr", "stackvec", "tokio", diff --git a/overlay/Cargo.toml b/overlay/Cargo.toml index 76ce701a..09722d00 100644 --- a/overlay/Cargo.toml +++ b/overlay/Cargo.toml @@ -13,10 +13,13 @@ rust-version.workspace = true clap = { version = "4", features = ["derive"] } color-eyre = "0.6" lazy_static = "1" -nalgebra = "0.30" +nalgebra = { version = "0.30", features = ["serde-serialize"] } num-derive = "0.3" num-traits = "0.2" -ovr_overlay = { version = "=0.0.0", features = ["nalgebra"] } +#ovr_overlay = { version = "=0.0.0", features = ["nalgebra"] } +ovr_overlay = { git = "https://github.com/TheButlah/ovr_overlay", features = ["nalgebra", "ovr_system", "ovr_chaperone_setup"]} +serde = "1.0" +serde_json = "1.0" stackvec = "0.2" tokio = { version = "1", features = ["full"] } solarxr = { path = "../networking/solarxr" } diff --git a/overlay/src/main.rs b/overlay/src/main.rs index 7dfc2c71..f409b7ca 100644 --- a/overlay/src/main.rs +++ b/overlay/src/main.rs @@ -1,5 +1,6 @@ mod color; mod model; +mod universe; pub use self::color::RGBA; @@ -151,6 +152,23 @@ async fn overlay( .build(mngr) .wrap_err("Could not create skeleton")?; + let system_mngr = &mut context.system_mngr(); + log::info!("Acquiring universe"); + let universe = loop { + let id: Result = system_mngr.get_tracked_device_property( + ovr::TrackedDeviceIndex::HMD, + ovr::sys::ETrackedDeviceProperty::Prop_CurrentUniverseId_Uint64, + ); + match id { + Ok(id) => match universe::search_universe(&context, id) { + Some(d) => break d, + None => {} // TODO: fallback to 0 translation, or maybe standing universe? + }, + Err(e) => log::error!("Error: {}", e), // TODO: log error, but only once? + } + tokio::time::sleep(Duration::from_secs(1)).await; + }; + log::info!("Overlay Loop"); let loop_ = async { @@ -243,10 +261,17 @@ async fn overlay( length, } in bones { - let iso = Isometry { + let mut iso = Isometry { rotation: rot, translation: pos, }; + // TODO: this isn't correct yet. + iso *= universe.translation.inverse(); + iso *= UnitQuaternion::from_axis_angle( + &nalgebra::Vector3::y_axis(), + universe.yaw, + ) + .inverse(); skeleton.set_isometry(kind, iso); skeleton.set_length(kind, length); } diff --git a/overlay/src/model/bone.rs b/overlay/src/model/bone.rs index e253e2e9..8286db0d 100644 --- a/overlay/src/model/bone.rs +++ b/overlay/src/model/bone.rs @@ -136,7 +136,7 @@ impl Bone { let col_major_3x4 = Matrix3x4::from(&transform); mngr.set_transform_absolute( overlay, - TrackingUniverseOrigin::TrackingUniverseStanding, + TrackingUniverseOrigin::TrackingUniverseRawAndUncalibrated, &col_major_3x4, ) .wrap_err("Failed to set transform")?; diff --git a/overlay/src/universe.rs b/overlay/src/universe.rs new file mode 100644 index 00000000..7827b2b6 --- /dev/null +++ b/overlay/src/universe.rs @@ -0,0 +1,87 @@ +use ovr_overlay as ovr; +use serde::{ + de::{self, Deserializer, Visitor}, + Deserialize, +}; +use serde_json::from_slice; +use std::fmt; + +// From https://github.com/serde-rs/json/issues/412#issuecomment-365856864 +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct UniverseId(u64); + +impl<'de> Deserialize<'de> for UniverseId { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + struct IdVisitor; + + impl<'de> Visitor<'de> for IdVisitor { + type Value = UniverseId; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("universe ID as a number or string") + } + + fn visit_u64(self, id: u64) -> Result + where + E: de::Error, + { + Ok(UniverseId(id)) + } + + fn visit_str(self, id: &str) -> Result + where + E: de::Error, + { + id.parse().map(UniverseId).map_err(de::Error::custom) + } + } + + deserializer.deserialize_any(IdVisitor) + } +} + +#[derive(Debug, Deserialize)] +pub(crate) struct UniverseTranslation { + pub translation: nalgebra::Translation3, + pub yaw: f32, +} + +#[derive(Debug, Deserialize)] +struct Universe { + #[serde(rename = "universeID")] + universe_id: UniverseId, + standing: UniverseTranslation, +} + +#[derive(Debug, Deserialize)] +struct Document { + universes: Vec, +} + +pub(crate) fn search_universe( + context: &ovr::Context, + universe_id: u64, +) -> Option { + let chaperone_setup = context.chaperone_setup_mngr().export_live_to_buffer()?; + + // note: in theory we could parse in a streaming fashion using an appropriate json library + // instead of reading in everything all at once and then filtering. + // in practice this will probably never matter. + let document: Document = match from_slice(chaperone_setup.as_bytes()) { + Ok(res) => res, + Err(err) => { + // TODO: only log this once? + log::error!("Error parsing universe json: {}", err); + return None; + } + }; + + document + .universes + .into_iter() + .find(|u| u.universe_id.0 == universe_id) + .map(|u| u.standing) +}