script/dom/webxr/
xrray.rs1use dom_struct::dom_struct;
6use euclid::{Angle, RigidTransform3D, Rotation3D, Vector3D};
7use js::rust::HandleObject;
8use js::typedarray::{Float32, HeapFloat32Array};
9use script_bindings::trace::RootedTraceableBox;
10use webxr_api::{ApiSpace, Ray};
11
12use crate::dom::bindings::buffer_source::HeapBufferSource;
13use crate::dom::bindings::codegen::Bindings::DOMPointBinding::DOMPointInit;
14use crate::dom::bindings::codegen::Bindings::XRRayBinding::{XRRayDirectionInit, XRRayMethods};
15use crate::dom::bindings::error::{Error, Fallible};
16use crate::dom::bindings::reflector::{DomGlobal, Reflector, reflect_dom_object_with_proto};
17use crate::dom::bindings::root::DomRoot;
18use crate::dom::dompointreadonly::DOMPointReadOnly;
19use crate::dom::window::Window;
20use crate::dom::xrrigidtransform::XRRigidTransform;
21use crate::script_runtime::{CanGc, JSContext};
22
23#[dom_struct]
24pub(crate) struct XRRay {
25 reflector_: Reflector,
26 #[ignore_malloc_size_of = "defined in webxr"]
27 #[no_trace]
28 ray: Ray<ApiSpace>,
29 #[ignore_malloc_size_of = "defined in mozjs"]
30 matrix: HeapBufferSource<Float32>,
31}
32
33impl XRRay {
34 fn new_inherited(ray: Ray<ApiSpace>) -> XRRay {
35 XRRay {
36 reflector_: Reflector::new(),
37 ray,
38 matrix: HeapBufferSource::default(),
39 }
40 }
41
42 fn new(
43 window: &Window,
44 proto: Option<HandleObject>,
45 ray: Ray<ApiSpace>,
46 can_gc: CanGc,
47 ) -> DomRoot<XRRay> {
48 reflect_dom_object_with_proto(Box::new(XRRay::new_inherited(ray)), window, proto, can_gc)
49 }
50
51 pub(crate) fn ray(&self) -> Ray<ApiSpace> {
52 self.ray
53 }
54}
55
56impl XRRayMethods<crate::DomTypeHolder> for XRRay {
57 fn Constructor(
59 window: &Window,
60 proto: Option<HandleObject>,
61 can_gc: CanGc,
62 origin: &DOMPointInit,
63 direction: &XRRayDirectionInit,
64 ) -> Fallible<DomRoot<Self>> {
65 if origin.w != 1.0 {
66 return Err(Error::Type("Origin w coordinate must be 1".into()));
67 }
68 if *direction.w != 0.0 {
69 return Err(Error::Type("Direction w coordinate must be 0".into()));
70 }
71 if *direction.x == 0.0 && *direction.y == 0.0 && *direction.z == 0.0 {
72 return Err(Error::Type(
73 "Direction vector cannot have zero length".into(),
74 ));
75 }
76
77 let origin = Vector3D::new(origin.x as f32, origin.y as f32, origin.z as f32);
78 let direction = Vector3D::new(
79 *direction.x as f32,
80 *direction.y as f32,
81 *direction.z as f32,
82 )
83 .normalize();
84
85 Ok(Self::new(window, proto, Ray { origin, direction }, can_gc))
86 }
87
88 fn Constructor_(
90 window: &Window,
91 proto: Option<HandleObject>,
92 can_gc: CanGc,
93 transform: &XRRigidTransform,
94 ) -> Fallible<DomRoot<Self>> {
95 let transform = transform.transform();
96 let origin = transform.translation;
97 let direction = transform
98 .rotation
99 .transform_vector3d(Vector3D::new(0., 0., -1.));
100
101 Ok(Self::new(window, proto, Ray { origin, direction }, can_gc))
102 }
103
104 fn Origin(&self, can_gc: CanGc) -> DomRoot<DOMPointReadOnly> {
106 DOMPointReadOnly::new(
107 &self.global(),
108 self.ray.origin.x as f64,
109 self.ray.origin.y as f64,
110 self.ray.origin.z as f64,
111 1.,
112 can_gc,
113 )
114 }
115
116 fn Direction(&self, can_gc: CanGc) -> DomRoot<DOMPointReadOnly> {
118 DOMPointReadOnly::new(
119 &self.global(),
120 self.ray.direction.x as f64,
121 self.ray.direction.y as f64,
122 self.ray.direction.z as f64,
123 0.,
124 can_gc,
125 )
126 }
127
128 fn Matrix(&self, _cx: JSContext, can_gc: CanGc) -> RootedTraceableBox<HeapFloat32Array> {
130 if !self.matrix.is_initialized() {
132 let z = Vector3D::new(0., 0., -1.);
134 let axis = z.cross(self.ray.direction);
136 let cos_angle = z.dot(self.ray.direction);
138 let rotation = if cos_angle > -1. && cos_angle < 1. {
140 Rotation3D::around_axis(axis, Angle::radians(cos_angle.acos()))
141 } else if cos_angle == -1. {
142 let axis = Vector3D::new(1., 0., 0.);
143 Rotation3D::around_axis(axis, Angle::radians(cos_angle.acos()))
144 } else {
145 Rotation3D::identity()
146 };
147 let translation = self.ray.origin;
149 let arr = RigidTransform3D::new(rotation, translation)
153 .to_transform()
154 .to_array();
155 self.matrix
156 .set_data(_cx, &arr, can_gc)
157 .expect("Failed to set matrix data on XRRAy.")
158 }
159
160 self.matrix
161 .get_typed_array()
162 .expect("Failed to get matrix from XRRay.")
163 }
164}