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