Skip to main content

script/dom/webxr/
xrhand.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use dom_struct::dom_struct;
6use js::context::JSContext;
7use script_bindings::reflector::{Reflector, reflect_dom_object_with_cx};
8use webxr_api::{FingerJoint, Hand, Joint};
9
10use crate::dom::bindings::codegen::Bindings::XRHandBinding::{XRHandJoint, XRHandMethods};
11use crate::dom::bindings::iterable::Iterable;
12use crate::dom::bindings::root::{Dom, DomRoot};
13use crate::dom::globalscope::GlobalScope;
14use crate::dom::xrinputsource::XRInputSource;
15use crate::dom::xrjointspace::XRJointSpace;
16
17const JOINT_SPACE_MAP: [(XRHandJoint, Joint); 25] = [
18    (XRHandJoint::Wrist, Joint::Wrist),
19    (XRHandJoint::Thumb_metacarpal, Joint::ThumbMetacarpal),
20    (
21        XRHandJoint::Thumb_phalanx_proximal,
22        Joint::ThumbPhalanxProximal,
23    ),
24    (XRHandJoint::Thumb_phalanx_distal, Joint::ThumbPhalanxDistal),
25    (XRHandJoint::Thumb_tip, Joint::ThumbPhalanxTip),
26    (
27        XRHandJoint::Index_finger_metacarpal,
28        Joint::Index(FingerJoint::Metacarpal),
29    ),
30    (
31        XRHandJoint::Index_finger_phalanx_proximal,
32        Joint::Index(FingerJoint::PhalanxProximal),
33    ),
34    (XRHandJoint::Index_finger_phalanx_intermediate, {
35        Joint::Index(FingerJoint::PhalanxIntermediate)
36    }),
37    (
38        XRHandJoint::Index_finger_phalanx_distal,
39        Joint::Index(FingerJoint::PhalanxDistal),
40    ),
41    (
42        XRHandJoint::Index_finger_tip,
43        Joint::Index(FingerJoint::PhalanxTip),
44    ),
45    (
46        XRHandJoint::Middle_finger_metacarpal,
47        Joint::Middle(FingerJoint::Metacarpal),
48    ),
49    (
50        XRHandJoint::Middle_finger_phalanx_proximal,
51        Joint::Middle(FingerJoint::PhalanxProximal),
52    ),
53    (XRHandJoint::Middle_finger_phalanx_intermediate, {
54        Joint::Middle(FingerJoint::PhalanxIntermediate)
55    }),
56    (
57        XRHandJoint::Middle_finger_phalanx_distal,
58        Joint::Middle(FingerJoint::PhalanxDistal),
59    ),
60    (
61        XRHandJoint::Middle_finger_tip,
62        Joint::Middle(FingerJoint::PhalanxTip),
63    ),
64    (
65        XRHandJoint::Ring_finger_metacarpal,
66        Joint::Ring(FingerJoint::Metacarpal),
67    ),
68    (
69        XRHandJoint::Ring_finger_phalanx_proximal,
70        Joint::Ring(FingerJoint::PhalanxProximal),
71    ),
72    (XRHandJoint::Ring_finger_phalanx_intermediate, {
73        Joint::Ring(FingerJoint::PhalanxIntermediate)
74    }),
75    (
76        XRHandJoint::Ring_finger_phalanx_distal,
77        Joint::Ring(FingerJoint::PhalanxDistal),
78    ),
79    (
80        XRHandJoint::Ring_finger_tip,
81        Joint::Ring(FingerJoint::PhalanxTip),
82    ),
83    (
84        XRHandJoint::Pinky_finger_metacarpal,
85        Joint::Little(FingerJoint::Metacarpal),
86    ),
87    (
88        XRHandJoint::Pinky_finger_phalanx_proximal,
89        Joint::Little(FingerJoint::PhalanxProximal),
90    ),
91    (XRHandJoint::Pinky_finger_phalanx_intermediate, {
92        Joint::Little(FingerJoint::PhalanxIntermediate)
93    }),
94    (
95        XRHandJoint::Pinky_finger_phalanx_distal,
96        Joint::Little(FingerJoint::PhalanxDistal),
97    ),
98    (
99        XRHandJoint::Pinky_finger_tip,
100        Joint::Little(FingerJoint::PhalanxTip),
101    ),
102];
103
104#[dom_struct]
105pub(crate) struct XRHand {
106    reflector_: Reflector,
107    source: Dom<XRInputSource>,
108    #[custom_trace]
109    spaces: Hand<Dom<XRJointSpace>>,
110}
111
112impl XRHand {
113    fn new_inherited(source: &XRInputSource, spaces: &Hand<DomRoot<XRJointSpace>>) -> XRHand {
114        XRHand {
115            reflector_: Reflector::new(),
116            source: Dom::from_ref(source),
117            spaces: spaces.map(&mut (), |_, j, _| j.as_ref().map(|j| Dom::from_ref(&**j))),
118        }
119    }
120
121    pub(crate) fn new(
122        cx: &mut JSContext,
123        global: &GlobalScope,
124        source: &XRInputSource,
125        support: Hand<()>,
126    ) -> DomRoot<XRHand> {
127        let id = source.id();
128        let session = source.session();
129        let spaces = support.map(cx, |cx, field, joint| {
130            let hand_joint = JOINT_SPACE_MAP
131                .iter()
132                .find(|&&(_, value)| value == joint)
133                .map(|&(hand_joint, _)| hand_joint)
134                .expect("Invalid joint name");
135            field.map(|_| XRJointSpace::new(cx, global, session, id, joint, hand_joint))
136        });
137        reflect_dom_object_with_cx(Box::new(XRHand::new_inherited(source, &spaces)), global, cx)
138    }
139}
140
141impl XRHandMethods<crate::DomTypeHolder> for XRHand {
142    /// <https://github.com/immersive-web/webxr-hands-input/blob/master/explainer.md>
143    fn Size(&self) -> u32 {
144        XRHandJoint::Pinky_finger_tip as u32 + 1
145    }
146
147    /// <https://github.com/immersive-web/webxr-hands-input/blob/master/explainer.md>
148    fn Get(&self, joint_name: XRHandJoint) -> DomRoot<XRJointSpace> {
149        let joint = JOINT_SPACE_MAP
150            .iter()
151            .find(|&&(key, _)| key == joint_name)
152            .map(|&(_, joint)| joint)
153            .expect("Invalid joint name");
154        self.spaces
155            .get(joint)
156            .map(|j| DomRoot::from_ref(&**j))
157            .expect("Failed to get joint pose")
158    }
159}
160
161impl Iterable for XRHand {
162    type Key = XRHandJoint;
163    type Value = DomRoot<XRJointSpace>;
164
165    fn get_iterable_length(&self, _cx: &mut JSContext) -> u32 {
166        JOINT_SPACE_MAP.len() as u32
167    }
168
169    fn get_value_at_index(&self, _cx: &mut JSContext, n: u32) -> DomRoot<XRJointSpace> {
170        let joint = JOINT_SPACE_MAP[n as usize].1;
171        self.spaces
172            .get(joint)
173            .map(|j| DomRoot::from_ref(&**j))
174            .expect("Failed to get joint pose")
175    }
176
177    fn get_key_at_index(&self, _cx: &mut JSContext, n: u32) -> XRHandJoint {
178        JOINT_SPACE_MAP[n as usize].0
179    }
180}