diff options
Diffstat (limited to 'components/script')
-rw-r--r-- | components/script/dom/webidls/XRFrame.webidl | 3 | ||||
-rw-r--r-- | components/script/dom/webidls/XRSession.webidl | 1 | ||||
-rw-r--r-- | components/script/dom/xrframe.rs | 31 | ||||
-rw-r--r-- | components/script/dom/xrreferencespace.rs | 43 | ||||
-rw-r--r-- | components/script/dom/xrsession.rs | 6 | ||||
-rw-r--r-- | components/script/dom/xrspace.rs | 51 | ||||
-rw-r--r-- | components/script/dom/xrstationaryreferencespace.rs | 29 |
7 files changed, 125 insertions, 39 deletions
diff --git a/components/script/dom/webidls/XRFrame.webidl b/components/script/dom/webidls/XRFrame.webidl index 24f714fcb76..a393acbc588 100644 --- a/components/script/dom/webidls/XRFrame.webidl +++ b/components/script/dom/webidls/XRFrame.webidl @@ -8,6 +8,7 @@ interface XRFrame { readonly attribute XRSession session; - XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace); + [Throws] XRViewerPose? getViewerPose(XRReferenceSpace referenceSpace); + [Throws] XRPose? getPose(XRSpace space, XRSpace relativeTo); // XRInputPose? getInputPose(XRInputSource inputSource, optional XRReferenceSpace referenceSpace); }; diff --git a/components/script/dom/webidls/XRSession.webidl b/components/script/dom/webidls/XRSession.webidl index 5f2cfb23929..f22918d469d 100644 --- a/components/script/dom/webidls/XRSession.webidl +++ b/components/script/dom/webidls/XRSession.webidl @@ -20,6 +20,7 @@ interface XRSession : EventTarget { readonly attribute XREnvironmentBlendMode environmentBlendMode; readonly attribute XRRenderState renderState; + readonly attribute XRSpace viewerSpace; // // Methods Promise<XRReferenceSpace> requestReferenceSpace(XRReferenceSpaceOptions options); diff --git a/components/script/dom/xrframe.rs b/components/script/dom/xrframe.rs index c9bb240a3bf..67602709d9b 100644 --- a/components/script/dom/xrframe.rs +++ b/components/script/dom/xrframe.rs @@ -4,11 +4,15 @@ use crate::dom::bindings::codegen::Bindings::XRFrameBinding; use crate::dom::bindings::codegen::Bindings::XRFrameBinding::XRFrameMethods; +use crate::dom::bindings::error::Error; +use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::root::{Dom, DomRoot}; use crate::dom::globalscope::GlobalScope; +use crate::dom::xrpose::XRPose; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrsession::XRSession; +use crate::dom::xrspace::XRSpace; use crate::dom::xrviewerpose::XRViewerPose; use dom_struct::dom_struct; use webvr_traits::WebVRFrameData; @@ -50,13 +54,34 @@ impl XRFrameMethods for XRFrame { } /// https://immersive-web.github.io/webxr/#dom-xrframe-getviewerpose - fn GetViewerPose(&self, reference: &XRReferenceSpace) -> Option<DomRoot<XRViewerPose>> { + fn GetViewerPose( + &self, + reference: &XRReferenceSpace, + ) -> Result<Option<DomRoot<XRViewerPose>>, Error> { + if self.session != reference.upcast::<XRSpace>().session() { + return Err(Error::InvalidState); + } let pose = reference.get_viewer_pose(&self.data); - Some(XRViewerPose::new( + Ok(Some(XRViewerPose::new( &self.global(), &self.session, pose, &self.data, - )) + ))) + } + + /// https://immersive-web.github.io/webxr/#dom-xrframe-getpose + fn GetPose( + &self, + space: &XRSpace, + relative_to: &XRSpace, + ) -> Result<Option<DomRoot<XRPose>>, Error> { + if self.session != space.session() || self.session != relative_to.session() { + return Err(Error::InvalidState); + } + let space = space.get_pose(&self.data); + let relative_to = relative_to.get_pose(&self.data); + let pose = relative_to.inverse().pre_mul(&space); + Ok(Some(XRPose::new(&self.global(), pose))) } } diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs index ed42d63b4be..804768eee69 100644 --- a/components/script/dom/xrreferencespace.rs +++ b/components/script/dom/xrreferencespace.rs @@ -54,9 +54,12 @@ impl XRReferenceSpaceMethods for XRReferenceSpace { } impl XRReferenceSpace { - /// Gets viewer pose represented by this space + /// Gets pose of the viewer with respect to this space + /// + /// This is equivalent to `get_pose(self).inverse() * get_pose(viewerSpace)`, however + /// we specialize it to be efficient pub fn get_viewer_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> { - let pose = self.get_pose(base_pose); + let pose = self.get_unoffset_viewer_pose(base_pose); // This may change, see https://github.com/immersive-web/webxr/issues/567 let offset = self.transform.get().transform(); @@ -64,16 +67,44 @@ impl XRReferenceSpace { inverse.pre_mul(&pose) } - /// Gets pose represented by this space + /// Gets pose of the viewer with respect to this space /// /// Does not apply originOffset, use get_viewer_pose instead if you need it - pub fn get_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> { + pub fn get_unoffset_viewer_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> { if let Some(stationary) = self.downcast::<XRStationaryReferenceSpace>() { - stationary.get_pose(base_pose) + stationary.get_unoffset_viewer_pose(base_pose) } else { // non-subclassed XRReferenceSpaces exist, obtained via the "identity" - // type. The pose does not depend on the base pose. + // type. These poses are equivalent to the viewer pose and follow the headset + // around, so the viewer is always at an identity transform with respect to them RigidTransform3D::identity() } } + + /// Gets pose represented by this space + /// + /// The reference origin used is common between all + /// get_pose calls for spaces from the same device, so this can be used to compare + /// with other spaces + pub fn get_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> { + let pose = self.get_unoffset_pose(base_pose); + + // This may change, see https://github.com/immersive-web/webxr/issues/567 + let offset = self.transform.get().transform(); + offset.post_mul(&pose) + } + + /// Gets pose represented by this space + /// + /// Does not apply originOffset, use get_viewer_pose instead if you need it + pub fn get_unoffset_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> { + if let Some(stationary) = self.downcast::<XRStationaryReferenceSpace>() { + stationary.get_unoffset_pose(base_pose) + } else { + // non-subclassed XRReferenceSpaces exist, obtained via the "identity" + // type. These are equivalent to the viewer pose and follow the headset + // around + XRSpace::viewer_pose_from_frame_data(base_pose) + } + } } diff --git a/components/script/dom/xrsession.rs b/components/script/dom/xrsession.rs index bf7dcb92258..c8394be5230 100644 --- a/components/script/dom/xrsession.rs +++ b/components/script/dom/xrsession.rs @@ -21,6 +21,7 @@ use crate::dom::vrdisplay::VRDisplay; use crate::dom::xrlayer::XRLayer; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrrenderstate::XRRenderState; +use crate::dom::xrspace::XRSpace; use crate::dom::xrstationaryreferencespace::XRStationaryReferenceSpace; use dom_struct::dom_struct; use std::rc::Rc; @@ -82,6 +83,11 @@ impl XRSessionMethods for XRSession { ) } + // https://immersive-web.github.io/webxr/#dom-xrsession-viewerspace + fn ViewerSpace(&self) -> DomRoot<XRSpace> { + XRSpace::new_viewerspace(&self.global(), &self) + } + /// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe fn UpdateRenderState(&self, init: &XRRenderStateInit) -> Rc<Promise> { let p = Promise::new(&self.global()); diff --git a/components/script/dom/xrspace.rs b/components/script/dom/xrspace.rs index 60589be4054..8948ac03c8e 100644 --- a/components/script/dom/xrspace.rs +++ b/components/script/dom/xrspace.rs @@ -11,13 +11,14 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrsession::XRSession; use dom_struct::dom_struct; -use euclid::RigidTransform3D; +use euclid::{RigidTransform3D, Rotation3D, Vector3D}; use webvr_traits::WebVRFrameData; #[dom_struct] pub struct XRSpace { eventtarget: EventTarget, session: Dom<XRSession>, + is_viewerspace: bool, } impl XRSpace { @@ -25,13 +26,21 @@ impl XRSpace { XRSpace { eventtarget: EventTarget::new_inherited(), session: Dom::from_ref(session), + is_viewerspace: false, } } - #[allow(unused)] - pub fn new(global: &GlobalScope, session: &XRSession) -> DomRoot<XRSpace> { + fn new_viewerspace_inner(session: &XRSession) -> XRSpace { + XRSpace { + eventtarget: EventTarget::new_inherited(), + session: Dom::from_ref(session), + is_viewerspace: true, + } + } + + pub fn new_viewerspace(global: &GlobalScope, session: &XRSession) -> DomRoot<XRSpace> { reflect_dom_object( - Box::new(XRSpace::new_inherited(session)), + Box::new(XRSpace::new_viewerspace_inner(session)), global, XRSpaceBinding::Wrap, ) @@ -39,25 +48,35 @@ impl XRSpace { } impl XRSpace { - /// Gets viewer pose represented by this space - #[allow(unused)] - pub fn get_viewer_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> { - if let Some(reference) = self.downcast::<XRReferenceSpace>() { - reference.get_viewer_pose(base_pose) - } else { - unreachable!() - } - } - /// Gets pose represented by this space /// - /// Does not apply originOffset, use get_viewer_pose instead if you need it - #[allow(unused)] + /// The reference origin used is common between all + /// get_pose calls for spaces from the same device, so this can be used to compare + /// with other spaces pub fn get_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> { if let Some(reference) = self.downcast::<XRReferenceSpace>() { reference.get_pose(base_pose) + } else if self.is_viewerspace { + XRSpace::viewer_pose_from_frame_data(base_pose) } else { unreachable!() } } + + pub fn viewer_pose_from_frame_data(data: &WebVRFrameData) -> RigidTransform3D<f64> { + let pos = data.pose.position.unwrap_or([0., 0., 0.]); + let translation = Vector3D::new(pos[0] as f64, pos[1] as f64, pos[2] as f64); + let orient = data.pose.orientation.unwrap_or([0., 0., 0., 0.]); + let rotation = Rotation3D::quaternion( + orient[0] as f64, + orient[1] as f64, + orient[2] as f64, + orient[3] as f64, + ); + RigidTransform3D::new(rotation, translation) + } + + pub fn session(&self) -> &XRSession { + &self.session + } } diff --git a/components/script/dom/xrstationaryreferencespace.rs b/components/script/dom/xrstationaryreferencespace.rs index ddba9aaa20b..6c5d53f9457 100644 --- a/components/script/dom/xrstationaryreferencespace.rs +++ b/components/script/dom/xrstationaryreferencespace.rs @@ -10,8 +10,9 @@ use crate::dom::globalscope::GlobalScope; use crate::dom::xrreferencespace::XRReferenceSpace; use crate::dom::xrrigidtransform::XRRigidTransform; use crate::dom::xrsession::XRSession; +use crate::dom::xrspace::XRSpace; use dom_struct::dom_struct; -use euclid::{RigidTransform3D, Rotation3D, Vector3D}; +use euclid::RigidTransform3D; use webvr_traits::WebVRFrameData; #[dom_struct] @@ -50,20 +51,22 @@ impl XRStationaryReferenceSpace { } impl XRStationaryReferenceSpace { + /// Gets pose of the viewer with respect to this space + /// + /// Does not apply originOffset, use get_viewer_pose on XRReferenceSpace instead + pub fn get_unoffset_viewer_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> { + // XXXManishearth add floor-level transform for floor-level and disable position in position-disabled + XRSpace::viewer_pose_from_frame_data(base_pose) + } + /// Gets pose represented by this space /// - /// Does not apply originOffset, use get_viewer_pose instead - pub fn get_pose(&self, base_pose: &WebVRFrameData) -> RigidTransform3D<f64> { + /// Does not apply originOffset, use get_pose on XRReferenceSpace instead + pub fn get_unoffset_pose(&self, _: &WebVRFrameData) -> RigidTransform3D<f64> { // XXXManishearth add floor-level transform for floor-level and disable position in position-disabled - let pos = base_pose.pose.position.unwrap_or([0., 0., 0.]); - let translation = Vector3D::new(pos[0] as f64, pos[1] as f64, pos[2] as f64); - let orient = base_pose.pose.orientation.unwrap_or([0., 0., 0., 0.]); - let rotation = Rotation3D::quaternion( - orient[0] as f64, - orient[1] as f64, - orient[2] as f64, - orient[3] as f64, - ); - RigidTransform3D::new(rotation, translation) + + // The eye-level pose is basically whatever the headset pose was at t=0, which + // for most devices is (0, 0, 0) + RigidTransform3D::identity() } } |