diff --git a/webxr/openxr/mod.rs b/webxr/openxr/mod.rs index 594f2e95..a0209d30 100644 --- a/webxr/openxr/mod.rs +++ b/webxr/openxr/mod.rs @@ -15,8 +15,8 @@ use openxr::{ self, ActionSet, ActiveActionSet, ApplicationInfo, CompositionLayerFlags, CompositionLayerProjection, Entry, EnvironmentBlendMode, ExtensionSet, Extent2Di, FormFactor, Fovf, FrameState, FrameStream, FrameWaiter, Instance, Posef, Quaternionf, ReferenceSpaceType, - Session, Space, Swapchain, SwapchainCreateFlags, SwapchainCreateInfo, SwapchainUsageFlags, - Vector3f, ViewConfigurationType, + Session, Space, SpaceLocationFlags, Swapchain, SwapchainCreateFlags, SwapchainCreateInfo, + SwapchainUsageFlags, Time, Vector3f, ViewConfigurationType, }; use std::sync::{Arc, Mutex}; use surfman::platform::generic::universal::device::Device as SurfmanDevice; @@ -51,8 +51,6 @@ use winapi::shared::dxgiformat; mod input; use input::OpenXRInput; -const HEIGHT: f32 = 1.4; - pub trait GlThread: Send { fn execute(&self, runnable: Box); fn clone(&self) -> Box; @@ -156,6 +154,8 @@ struct OpenXrDevice { frame_waiter: FrameWaiter, shared_data: Arc>, viewer_space: Space, + floor_space: Space, + floor_dirty: bool, blend_mode: EnvironmentBlendMode, clip_planes: ClipPlanes, view_configurations: Vec, @@ -435,6 +435,10 @@ impl OpenXrDevice { .create_reference_space(ReferenceSpaceType::VIEW, pose) .map_err(|e| Error::BackendSpecific(format!("{:?}", e)))?; + let floor_space = session + .create_reference_space(ReferenceSpaceType::STAGE, pose) + .map_err(|e| Error::BackendSpecific(format!("{:?}", e)))?; + let view_configuration_type = ViewConfigurationType::PRIMARY_STEREO; let view_configurations = instance .enumerate_view_configuration_views(system, view_configuration_type) @@ -538,6 +542,8 @@ impl OpenXrDevice { session, frame_waiter, viewer_space, + floor_space, + floor_dirty: true, clip_planes: Default::default(), blend_mode, view_configurations, @@ -567,6 +573,12 @@ impl OpenXrDevice { Some(InstanceLossPending(_)) => { break; } + Some(ReferenceSpaceChangePending(r)) => { + if r.reference_space_type() == ReferenceSpaceType::STAGE { + self.floor_dirty = true; + } + // FIXME: Trigger reset events for all other cases + } Some(_) => { // FIXME: Handle other events } @@ -578,12 +590,29 @@ impl OpenXrDevice { } true } + + fn floor_transform_inner( + &self, + space: &Space, + time: Time, + ) -> Option> { + let pose = space.locate(&self.floor_space, time).unwrap(); + + let pose_valid = pose + .location_flags + .intersects(SpaceLocationFlags::POSITION_VALID | SpaceLocationFlags::ORIENTATION_VALID); + + if pose_valid { + Some(transform(&pose.pose)) + } else { + None + } + } } impl DeviceAPI for OpenXrDevice { fn floor_transform(&self) -> Option> { - let translation = Vector3D::new(0.0, HEIGHT, 0.0); - Some(RigidTransform3D::from_translation(translation)) + None } fn views(&self) -> Views { @@ -672,15 +701,21 @@ impl DeviceAPI for OpenXrDevice { self.left_hand .frame(&self.session, &data.frame_state, &data.space); - // views() needs to reacquire the lock. - drop(data); - - let events = if self.clip_planes.recently_updated() { - vec![FrameUpdateEvent::UpdateViews(self.views())] + let mut events = if self.floor_dirty { + vec![FrameUpdateEvent::UpdateFloorTransform( + self.floor_transform_inner(&data.space, data.frame_state.predicted_display_time), + )] } else { vec![] }; + // views() needs to reacquire the lock. + drop(data); + + if self.clip_planes.recently_updated() { + events.push(FrameUpdateEvent::UpdateViews(self.views())); + } + let frame = Frame { transform, inputs: vec![right_input_frame, left_input_frame],