diff options
Diffstat (limited to 'components/script/dom/xrreferencespace.rs')
-rw-r--r-- | components/script/dom/xrreferencespace.rs | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/components/script/dom/xrreferencespace.rs b/components/script/dom/xrreferencespace.rs new file mode 100644 index 00000000000..fb4f890e766 --- /dev/null +++ b/components/script/dom/xrreferencespace.rs @@ -0,0 +1,135 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ + +use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceMethods; +use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType; +use crate::dom::bindings::inheritance::Castable; +use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; +use crate::dom::bindings::root::{Dom, DomRoot}; +use crate::dom::globalscope::GlobalScope; +use crate::dom::xrrigidtransform::XRRigidTransform; +use crate::dom::xrsession::{cast_transform, ApiPose, BaseTransform, XRSession}; +use crate::dom::xrspace::XRSpace; +use dom_struct::dom_struct; +use euclid::RigidTransform3D; +use webxr_api::{self, Frame, Space}; + +#[dom_struct] +pub struct XRReferenceSpace { + xrspace: XRSpace, + offset: Dom<XRRigidTransform>, + ty: XRReferenceSpaceType, +} + +impl XRReferenceSpace { + pub fn new_inherited( + session: &XRSession, + offset: &XRRigidTransform, + ty: XRReferenceSpaceType, + ) -> XRReferenceSpace { + XRReferenceSpace { + xrspace: XRSpace::new_inherited(session), + offset: Dom::from_ref(offset), + ty, + } + } + + #[allow(unused)] + pub fn new( + global: &GlobalScope, + session: &XRSession, + ty: XRReferenceSpaceType, + ) -> DomRoot<XRReferenceSpace> { + let offset = XRRigidTransform::identity(global); + Self::new_offset(global, session, ty, &offset) + } + + #[allow(unused)] + pub fn new_offset( + global: &GlobalScope, + session: &XRSession, + ty: XRReferenceSpaceType, + offset: &XRRigidTransform, + ) -> DomRoot<XRReferenceSpace> { + reflect_dom_object( + Box::new(XRReferenceSpace::new_inherited(session, &offset, ty)), + global, + ) + } + + pub fn space(&self) -> Space { + let base = match self.ty { + XRReferenceSpaceType::Local => webxr_api::BaseSpace::Local, + XRReferenceSpaceType::Viewer => webxr_api::BaseSpace::Viewer, + XRReferenceSpaceType::Local_floor => webxr_api::BaseSpace::Floor, + _ => panic!("unsupported reference space found"), + }; + let offset = self.offset.transform(); + Space { base, offset } + } +} + +impl XRReferenceSpaceMethods for XRReferenceSpace { + /// https://immersive-web.github.io/webxr/#dom-xrreferencespace-getoffsetreferencespace + fn GetOffsetReferenceSpace(&self, new: &XRRigidTransform) -> DomRoot<Self> { + let offset = self.offset.transform().pre_transform(&new.transform()); + let offset = XRRigidTransform::new(&self.global(), offset); + Self::new_offset( + &self.global(), + self.upcast::<XRSpace>().session(), + self.ty, + &offset, + ) + } +} + +impl XRReferenceSpace { + /// Get a transform that can be used to locate the base space + /// + /// This is equivalent to `get_pose(self).inverse()` (in column vector notation), + /// but with better types + pub fn get_base_transform(&self, base_pose: &Frame) -> Option<BaseTransform> { + let pose = self.get_pose(base_pose)?; + Some(pose.inverse().cast_unit()) + } + + /// 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: &Frame) -> Option<ApiPose> { + let pose = self.get_unoffset_pose(base_pose)?; + let offset = self.offset.transform(); + // pose is a transform from the unoffset space to native space, + // offset is a transform from offset space to unoffset space, + // we want a transform from unoffset space to native space, + // which is pose * offset in column vector notation + Some(pose.pre_transform(&offset)) + } + + /// 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: &Frame) -> Option<ApiPose> { + match self.ty { + XRReferenceSpaceType::Local => { + // The eye-level pose is basically whatever the headset pose was at t=0, which + // for most devices is (0, 0, 0) + Some(RigidTransform3D::identity()) + }, + XRReferenceSpaceType::Local_floor => { + let native_to_floor = self + .upcast::<XRSpace>() + .session() + .with_session(|s| s.floor_transform())?; + Some(cast_transform(native_to_floor.inverse())) + }, + XRReferenceSpaceType::Viewer => { + Some(cast_transform(base_pose.pose.as_ref()?.transform)) + }, + _ => unimplemented!(), + } + } +} |