use dom_struct::dom_struct;
use euclid::{Point2D, RigidTransform3D};
use webxr_api::{self, Floor, Frame, Space};
use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::{
XRReferenceSpaceMethods, 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 crate::script_runtime::CanGc;
#[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,
can_gc: CanGc,
) -> DomRoot<XRReferenceSpace> {
let offset = XRRigidTransform::identity(global, can_gc);
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,
XRReferenceSpaceType::Bounded_floor => webxr_api::BaseSpace::BoundedFloor,
_ => panic!("unsupported reference space found"),
};
let offset = self.offset.transform();
Space { base, offset }
}
pub fn ty(&self) -> XRReferenceSpaceType {
self.ty
}
}
impl XRReferenceSpaceMethods for XRReferenceSpace {
fn GetOffsetReferenceSpace(&self, new: &XRRigidTransform, can_gc: CanGc) -> DomRoot<Self> {
let offset = new.transform().then(&self.offset.transform());
let offset = XRRigidTransform::new(&self.global(), offset, can_gc);
Self::new_offset(
&self.global(),
self.upcast::<XRSpace>().session(),
self.ty,
&offset,
)
}
event_handler!(reset, GetOnreset, SetOnreset);
}
impl XRReferenceSpace {
pub fn get_base_transform(&self, base_pose: &Frame) -> Option<BaseTransform> {
let pose = self.get_pose(base_pose)?;
Some(pose.inverse().cast_unit())
}
pub fn get_pose(&self, base_pose: &Frame) -> Option<ApiPose> {
let pose = self.get_unoffset_pose(base_pose)?;
let offset = self.offset.transform();
Some(offset.then(&pose))
}
pub fn get_unoffset_pose(&self, base_pose: &Frame) -> Option<ApiPose> {
match self.ty {
XRReferenceSpaceType::Local => {
Some(RigidTransform3D::identity())
},
XRReferenceSpaceType::Local_floor | XRReferenceSpaceType::Bounded_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!(),
}
}
pub fn get_bounds(&self) -> Option<Vec<Point2D<f32, Floor>>> {
self.upcast::<XRSpace>()
.session()
.with_session(|s| s.reference_space_bounds())
}
}