script/dom/webxr/
xrrigidtransform.rs1use dom_struct::dom_struct;
6use euclid::{RigidTransform3D, Rotation3D, Vector3D};
7use js::rust::HandleObject;
8use js::typedarray::{Float32, HeapFloat32Array};
9use script_bindings::trace::RootedTraceableBox;
10
11use crate::dom::bindings::buffer_source::HeapBufferSource;
12use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
13use crate::dom::bindings::codegen::Bindings::XRRigidTransformBinding::XRRigidTransformMethods;
14use crate::dom::bindings::error::{Error, Fallible};
15use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
16use crate::dom::bindings::root::{DomRoot, MutNullableDom};
17use crate::dom::dompointreadonly::DOMPointReadOnly;
18use crate::dom::window::Window;
19use crate::dom::xrsession::ApiRigidTransform;
20use crate::script_runtime::{CanGc, JSContext};
21
22#[dom_struct]
23pub(crate) struct XRRigidTransform {
24 reflector_: Reflector,
25 position: MutNullableDom<DOMPointReadOnly>,
26 orientation: MutNullableDom<DOMPointReadOnly>,
27 #[ignore_malloc_size_of = "defined in euclid"]
28 #[no_trace]
29 transform: ApiRigidTransform,
30 inverse: MutNullableDom<XRRigidTransform>,
31 #[ignore_malloc_size_of = "defined in mozjs"]
32 matrix: HeapBufferSource<Float32>,
33}
34
35impl XRRigidTransform {
36 fn new_inherited(transform: ApiRigidTransform) -> XRRigidTransform {
37 XRRigidTransform {
38 reflector_: Reflector::new(),
39 position: MutNullableDom::default(),
40 orientation: MutNullableDom::default(),
41 transform,
42 inverse: MutNullableDom::default(),
43 matrix: HeapBufferSource::default(),
44 }
45 }
46
47 pub(crate) fn new(
48 window: &Window,
49 transform: ApiRigidTransform,
50 can_gc: CanGc,
51 ) -> DomRoot<XRRigidTransform> {
52 Self::new_with_proto(window, None, transform, can_gc)
53 }
54
55 fn new_with_proto(
56 window: &Window,
57 proto: Option<HandleObject>,
58 transform: ApiRigidTransform,
59 can_gc: CanGc,
60 ) -> DomRoot<XRRigidTransform> {
61 reflect_dom_object_with_proto(
62 Box::new(XRRigidTransform::new_inherited(transform)),
63 window,
64 proto,
65 can_gc,
66 )
67 }
68
69 pub(crate) fn identity(window: &Window, can_gc: CanGc) -> DomRoot<XRRigidTransform> {
70 let transform = RigidTransform3D::identity();
71 XRRigidTransform::new(window, transform, can_gc)
72 }
73}
74
75impl XRRigidTransformMethods<crate::DomTypeHolder> for XRRigidTransform {
76 fn Constructor(
78 window: &Window,
79 proto: Option<HandleObject>,
80 can_gc: CanGc,
81 position: &DOMPointInit,
82 orientation: &DOMPointInit,
83 ) -> Fallible<DomRoot<Self>> {
84 if position.w != 1.0 {
85 return Err(Error::Type(format!(
86 "XRRigidTransform must be constructed with a position that has a w value of of 1.0, not {}",
87 position.w
88 )));
89 }
90
91 if !position.x.is_finite() ||
92 !position.y.is_finite() ||
93 !position.z.is_finite() ||
94 !position.w.is_finite()
95 {
96 return Err(Error::Type(
97 "Position must not contain non-finite values".into(),
98 ));
99 }
100
101 if !orientation.x.is_finite() ||
102 !orientation.y.is_finite() ||
103 !orientation.z.is_finite() ||
104 !orientation.w.is_finite()
105 {
106 return Err(Error::Type(
107 "Orientation must not contain non-finite values".into(),
108 ));
109 }
110
111 let translate = Vector3D::new(position.x as f32, position.y as f32, position.z as f32);
112 let rotate = Rotation3D::unit_quaternion(
113 orientation.x as f32,
114 orientation.y as f32,
115 orientation.z as f32,
116 orientation.w as f32,
117 );
118
119 if !rotate.i.is_finite() {
120 return Err(Error::InvalidState(None));
123 }
124 let transform = RigidTransform3D::new(rotate, translate);
125 Ok(XRRigidTransform::new_with_proto(
126 window, proto, transform, can_gc,
127 ))
128 }
129
130 fn Position(&self, can_gc: CanGc) -> DomRoot<DOMPointReadOnly> {
132 self.position.or_init(|| {
133 let t = &self.transform.translation;
134 DOMPointReadOnly::new(
135 &self.global(),
136 t.x.into(),
137 t.y.into(),
138 t.z.into(),
139 1.0,
140 can_gc,
141 )
142 })
143 }
144 fn Orientation(&self, can_gc: CanGc) -> DomRoot<DOMPointReadOnly> {
146 self.orientation.or_init(|| {
147 let r = &self.transform.rotation;
148 DOMPointReadOnly::new(
149 &self.global(),
150 r.i.into(),
151 r.j.into(),
152 r.k.into(),
153 r.r.into(),
154 can_gc,
155 )
156 })
157 }
158 fn Inverse(&self, can_gc: CanGc) -> DomRoot<XRRigidTransform> {
160 self.inverse.or_init(|| {
161 let transform =
162 XRRigidTransform::new(self.global().as_window(), self.transform.inverse(), can_gc);
163 transform.inverse.set(Some(self));
164 transform
165 })
166 }
167 fn Matrix(&self, _cx: JSContext, can_gc: CanGc) -> RootedTraceableBox<HeapFloat32Array> {
169 if !self.matrix.is_initialized() {
170 self.matrix
171 .set_data(_cx, &self.transform.to_transform().to_array(), can_gc)
172 .expect("Failed to set on data on transform's internal matrix.")
173 }
174
175 self.matrix
176 .get_typed_array()
177 .expect("Failed to get transform's internal matrix.")
178 }
179}
180
181impl XRRigidTransform {
182 pub(crate) fn transform(&self) -> ApiRigidTransform {
184 self.transform
185 }
186}