script/dom/webxr/
xrview.rs1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use euclid::RigidTransform3D;
9use js::typedarray::{Float32, HeapFloat32Array};
10use script_bindings::trace::RootedTraceableBox;
11use webxr_api::{ApiSpace, View};
12
13use crate::dom::bindings::buffer_source::HeapBufferSource;
14use crate::dom::bindings::codegen::Bindings::XRViewBinding::{XREye, XRViewMethods};
15use crate::dom::bindings::num::Finite;
16use crate::dom::bindings::reflector::{Reflector, reflect_dom_object};
17use crate::dom::bindings::root::{Dom, DomRoot};
18use crate::dom::globalscope::GlobalScope;
19use crate::dom::window::Window;
20use crate::dom::xrrigidtransform::XRRigidTransform;
21use crate::dom::xrsession::{BaseSpace, BaseTransform, XRSession, cast_transform};
22use crate::script_runtime::{CanGc, JSContext};
23
24#[dom_struct]
25pub(crate) struct XRView {
26 reflector_: Reflector,
27 session: Dom<XRSession>,
28 eye: XREye,
29 viewport_index: usize,
30 #[ignore_malloc_size_of = "mozjs"]
31 proj: HeapBufferSource<Float32>,
32 #[no_trace]
33 view: View<ApiSpace>,
34 transform: Dom<XRRigidTransform>,
35 requested_viewport_scale: Cell<f64>,
36}
37
38impl XRView {
39 fn new_inherited(
40 session: &XRSession,
41 transform: &XRRigidTransform,
42 eye: XREye,
43 viewport_index: usize,
44 view: View<ApiSpace>,
45 ) -> XRView {
46 XRView {
47 reflector_: Reflector::new(),
48 session: Dom::from_ref(session),
49 eye,
50 viewport_index,
51 proj: HeapBufferSource::default(),
52 view,
53 transform: Dom::from_ref(transform),
54 requested_viewport_scale: Cell::new(1.0),
55 }
56 }
57
58 pub(crate) fn new<V: Copy>(
59 window: &Window,
60 session: &XRSession,
61 view: &View<V>,
62 eye: XREye,
63 viewport_index: usize,
64 to_base: &BaseTransform,
65 can_gc: CanGc,
66 ) -> DomRoot<XRView> {
67 let transform: RigidTransform3D<f32, V, BaseSpace> = view.transform.then(to_base);
68 let transform = XRRigidTransform::new(window, cast_transform(transform), can_gc);
69
70 reflect_dom_object(
71 Box::new(XRView::new_inherited(
72 session,
73 &transform,
74 eye,
75 viewport_index,
76 view.cast_unit(),
77 )),
78 window,
79 can_gc,
80 )
81 }
82
83 pub(crate) fn session(&self) -> &XRSession {
84 &self.session
85 }
86
87 pub(crate) fn viewport_index(&self) -> usize {
88 self.viewport_index
89 }
90}
91
92impl XRViewMethods<crate::DomTypeHolder> for XRView {
93 fn Eye(&self) -> XREye {
95 self.eye
96 }
97
98 fn ProjectionMatrix(
100 &self,
101 _cx: JSContext,
102 can_gc: CanGc,
103 ) -> RootedTraceableBox<HeapFloat32Array> {
104 if !self.proj.is_initialized() {
105 let cx = GlobalScope::get_cx();
106 let proj = self.view.projection.to_array();
108 self.proj
109 .set_data(cx, &proj, can_gc)
110 .expect("Failed to set projection matrix.")
111 }
112 self.proj
113 .get_typed_array()
114 .expect("Failed to get projection matrix.")
115 }
116
117 fn Transform(&self) -> DomRoot<XRRigidTransform> {
119 DomRoot::from_ref(&self.transform)
120 }
121
122 fn GetRecommendedViewportScale(&self) -> Option<Finite<f64>> {
124 Finite::new(1.0)
126 }
127
128 fn RequestViewportScale(&self, scale: Option<Finite<f64>>) {
130 if let Some(scale) = scale {
131 if *scale > 0.0 {
132 let clamped_scale = scale.clamp(0.0, 1.0);
133 self.requested_viewport_scale.set(clamped_scale);
134 }
135 }
136 }
137
138 fn IsFirstPersonObserver(&self) -> bool {
140 false
142 }
143}