1use 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 fn Size(&self) -> u32 {
144 XRHandJoint::Pinky_finger_tip as u32 + 1
145 }
146
147 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}