makepad_platform/event/
xr.rs

1use {
2    crate::{
3        cx::Cx,
4        Margin,
5        Area,
6        HitOptions,
7        Hit,
8        SmallVec,
9        FingerDownEvent,
10        CxWindowPool,
11        DigitDevice,
12        KeyModifiers,
13        makepad_micro_serde::*,
14        makepad_math::*,
15        LiveId,
16        makepad_live_id::{live_id_num},
17    },
18    std::rc::Rc,
19};
20
21#[derive(Clone, Debug, Default, SerBin, DeBin)]
22pub struct XrController {
23    pub grip_pose: Pose,
24    pub aim_pose: Pose,
25    pub trigger: f32,
26    pub grip: f32,
27    pub buttons: u16,
28    pub stick: Vec2,
29}
30
31impl XrController{
32    pub const CLICK_X: u16 = 1<<0;
33    pub const CLICK_Y: u16 = 1<<1;
34    pub const CLICK_A: u16 = 1<<2;
35    pub const CLICK_B: u16 = 1<<3;
36    pub const CLICK_MENU: u16 = 1<<4;
37    
38    pub const ACTIVE: u16 = 1<<5;
39    pub const CLICK_THUMBSTICK: u16 = 1<<6;
40        
41    pub const TOUCH_X: u16 = 1<<7;
42    pub const TOUCH_Y: u16 = 1<<8;
43    pub const TOUCH_A: u16 = 1<<9;
44    pub const TOUCH_B: u16 = 1<<10;
45    pub const TOUCH_THUMBSTICK: u16 = 1<<11;
46    pub const TOUCH_TRIGGER: u16 = 1<<12;
47    pub const TOUCH_THUMBREST: u16 = 1<<13;
48    pub fn triggered(&self)->bool{ self.trigger>0.8}
49    pub fn active(&self)->bool{self.buttons & Self::ACTIVE != 0}
50
51    pub fn click_x(&self)->bool{self.buttons & Self::CLICK_X != 0}
52    pub fn click_y(&self)->bool{self.buttons & Self::CLICK_Y != 0}
53    pub fn click_a(&self)->bool{self.buttons & Self::CLICK_A != 0}
54    pub fn click_b(&self)->bool{self.buttons & Self::CLICK_B != 0}
55    pub fn click_thumbstick(&self)->bool{self.buttons & Self::CLICK_THUMBSTICK != 0}
56    pub fn click_menu(&self)->bool{self.buttons & Self::CLICK_MENU != 0}
57        
58    pub fn touch_x(&self)->bool{self.buttons & Self::TOUCH_X != 0}
59    pub fn touch_y(&self)->bool{self.buttons & Self::TOUCH_Y != 0}
60    pub fn touch_a(&self)->bool{self.buttons & Self::TOUCH_A != 0}
61    pub fn touch_b(&self)->bool{self.buttons & Self::TOUCH_B != 0}
62    pub fn touch_thumbstick(&self)->bool{self.buttons & Self::TOUCH_THUMBSTICK != 0}
63    pub fn touch_trigger(&self)->bool{self.buttons & Self::TOUCH_TRIGGER != 0}
64    pub fn touch_thumbrest(&self)->bool{self.buttons & Self::TOUCH_THUMBREST != 0}
65}
66
67#[derive(Clone, Debug, Default, SerBin, DeBin)]
68pub struct XrHand{
69    pub flags: u8,
70    pub joints: [Pose;Self::JOINT_COUNT],
71    pub tips: [f32;5],
72    pub tips_active: u8,
73    pub aim_pose: Pose,
74    pub pinch: [u8;4]
75}
76
77impl XrHand{
78    
79    pub fn in_view(&self)->bool{self.flags & Self::IN_VIEW != 0}
80    pub fn aim_valid(&self)->bool{self.flags & Self::AIM_VALID != 0}
81    pub fn menu_pressed(&self)->bool{self.flags & Self::MENU_PRESSED != 0}
82    //pub fn system_gesture(&self)->bool{self.flags & Self::SYSTEM_GESTURE != 0}
83    pub fn dominant_hand(&self)->bool{self.flags & Self::DOMINANT_HAND != 0}
84    
85    pub fn pinch_index(&self)->bool{self.flags & Self::PINCH_INDEX != 0}
86    pub fn pinch_middle(&self)->bool{self.flags & Self::PINCH_MIDDLE != 0}
87    pub fn pinch_ring(&self)->bool{self.flags & Self::PINCH_RING != 0}
88    pub fn pinch_little(&self)->bool{self.flags & Self::PINCH_LITTLE != 0}
89    
90    pub fn pinch_only_little(&self)->bool{
91        self.pinch[Self::PINCH_STRENGTH_INDEX]<100 && 
92        self.pinch[Self::PINCH_STRENGTH_MIDDLE]<100 && 
93        self.pinch[Self::PINCH_STRENGTH_RING]<100 && 
94        self.pinch[Self::PINCH_STRENGTH_LITTLE]>160
95    }
96    pub fn pinch_only_index(&self)->bool{
97        self.pinch[Self::PINCH_STRENGTH_INDEX]>160 && 
98        self.pinch[Self::PINCH_STRENGTH_MIDDLE]<100 && 
99        self.pinch[Self::PINCH_STRENGTH_RING]<100 && 
100        self.pinch[Self::PINCH_STRENGTH_LITTLE]<100
101    }
102    
103    pub fn pinch_not_index(&self)->bool{
104        self.pinch[Self::PINCH_STRENGTH_INDEX]<100 && (
105        self.pinch[Self::PINCH_STRENGTH_MIDDLE]>160 || 
106        self.pinch[Self::PINCH_STRENGTH_RING]>160 || 
107        self.pinch[Self::PINCH_STRENGTH_LITTLE]>160) 
108    }
109            
110    pub fn pinch_strength_index(&self)->f32{self.pinch[Self::PINCH_STRENGTH_INDEX] as f32 / u8::MAX as f32}
111    pub fn pinch_strength_middle(&self)->f32{self.pinch[Self::PINCH_STRENGTH_MIDDLE] as f32 / u8::MAX as f32}
112    pub fn pinch_strength_ring(&self)->f32{self.pinch[Self::PINCH_STRENGTH_RING] as f32 / u8::MAX as f32}
113    pub fn pinch_strength_pinky(&self)->f32{self.pinch[Self::PINCH_STRENGTH_LITTLE] as f32 / u8::MAX as f32}
114        
115    pub const IN_VIEW: u8 = 1<<0;
116    pub const AIM_VALID: u8 = 1<<1;
117    pub const PINCH_INDEX: u8 = 1<<2;
118    pub const PINCH_MIDDLE: u8 = 1<<3;
119    pub const PINCH_RING: u8 = 1<<4;
120    pub const PINCH_LITTLE: u8 = 1<<5;
121    pub const DOMINANT_HAND: u8 = 1<<6;
122    pub const MENU_PRESSED : u8 = 1<<7;
123    
124    pub const PINCH_STRENGTH_INDEX: usize = 0;
125    pub const PINCH_STRENGTH_MIDDLE: usize = 1;
126    pub const PINCH_STRENGTH_RING: usize = 2;
127    pub const PINCH_STRENGTH_LITTLE: usize = 3;
128    
129    pub const JOINT_COUNT: usize = 21;
130    pub const CENTER: usize = 0;
131    pub const WRIST: usize = 1;
132    pub const THUMB_BASE: usize = 2;
133    pub const THUMB_KNUCKLE1: usize = 3;
134    pub const THUMB_KNUCKLE2: usize = 4;
135    pub const INDEX_BASE: usize = 5;
136    pub const INDEX_KNUCKLE1: usize = 6;
137    pub const INDEX_KNUCKLE2: usize = 7;
138    pub const INDEX_KNUCKLE3: usize = 8;
139    pub const MIDDLE_BASE: usize = 9;
140    pub const MIDDLE_KNUCKLE1: usize = 10;
141    pub const MIDDLE_KNUCKLE2: usize = 11;
142    pub const MIDDLE_KNUCKLE3: usize = 12;
143    pub const RING_BASE: usize = 13;
144    pub const RING_KNUCKLE1: usize = 14;
145    pub const RING_KNUCKLE2: usize = 15;
146    pub const RING_KNUCKLE3: usize = 16;
147    pub const LITTLE_BASE: usize = 17;
148    pub const LITTLE_KNUCKLE1: usize = 18;
149    pub const LITTLE_KNUCKLE2: usize = 19;
150    pub const LITTLE_KNUCKLE3: usize = 20;
151    
152    pub const END_KNUCKLES: [usize;5] = [
153        Self::THUMB_KNUCKLE2, 
154        Self::INDEX_KNUCKLE3, 
155        Self::MIDDLE_KNUCKLE3, 
156        Self::RING_KNUCKLE3, 
157        Self::LITTLE_KNUCKLE3
158    ];
159
160    pub fn end_knuckles(&self)->[&Pose;5]{
161        [
162            &self.joints[XrHand::THUMB_KNUCKLE2],
163            &self.joints[XrHand::INDEX_KNUCKLE3],
164            &self.joints[XrHand::MIDDLE_KNUCKLE3],
165            &self.joints[XrHand::RING_KNUCKLE3],
166            &self.joints[XrHand::LITTLE_KNUCKLE3],
167        ]
168    }
169            
170    pub const THUMB_TIP: usize = 0;
171    pub const INDEX_TIP: usize = 1;
172    pub const MIDDLE_TIP: usize = 2;
173    pub const RING_TIP: usize = 3;
174    pub const LITTLE_TIP: usize = 4;
175            
176    pub fn tip_active(&self,tip:usize)->bool{
177        self.tips_active & (1<<tip) != 0
178    }
179    
180    fn tip_pos(&self,tip:usize, knuckle:usize)->Vec3{
181        let pos = vec4(0.0,0.0,-self.tips[tip],1.0);
182        self.joints[knuckle].to_mat4().transform_vec4(pos).to_vec3()
183    }
184    
185    pub fn tip_pos_thumb(&self)->Vec3{self.tip_pos(0, XrHand::THUMB_KNUCKLE2)}
186    pub fn tip_pos_index(&self)->Vec3{self.tip_pos(0, XrHand::INDEX_KNUCKLE3)}
187    pub fn tip_pos_middle(&self)->Vec3{self.tip_pos(0, XrHand::MIDDLE_KNUCKLE3)}
188    pub fn tip_pos_ring(&self)->Vec3{self.tip_pos(0, XrHand::RING_KNUCKLE3)}
189    pub fn tip_pos_little(&self)->Vec3{self.tip_pos(0, XrHand::LITTLE_KNUCKLE3)}
190        
191}
192
193#[derive(Clone, Debug)]
194pub struct XrFingerTip{
195    pub index: usize,
196    pub is_left: bool,
197    pub pos: Vec3,
198}
199
200#[derive(Clone, Debug)]
201pub struct XrLocalEvent{
202    pub finger_tips: SmallVec<[XrFingerTip;10]>,
203    pub update: XrUpdateEvent,
204    pub modifiers: KeyModifiers,
205    pub time: f64,
206}
207
208#[derive(Clone, Copy, Debug, Default, SerBin, DeBin, PartialEq)]
209pub struct XrAnchor{
210    pub left: Vec3,
211    pub right: Vec3,
212}
213
214impl XrAnchor{
215    pub fn to_quat(&self)->Quat{
216        let mut forward = self.right - self.left;
217        forward.y = 0.0;
218        Quat::look_rotation(forward, vec3(0.0,1.0,0.0))
219    }
220    
221    pub fn to_quat_rev(&self)->Quat{
222        let mut forward = self.left - self.right;
223        forward.y = 0.0;
224        Quat::look_rotation(forward, vec3(0.0,1.0,0.0))
225    }
226    
227    pub fn to_mat4(&self)->Mat4{
228        self.to_pose().to_mat4()
229    }
230        
231    pub fn to_pose(&self)->Pose{
232        Pose{position: (self.left+self.right)/2.0, orientation:self.to_quat()}
233    }
234    
235    pub fn mapping_to(&self, other:&XrAnchor)->Mat4{
236        Mat4::mul(&self.to_pose().to_mat4().invert(), &other.to_pose().to_mat4())
237    }
238}
239
240#[derive(Clone, Debug, Default, SerBin, DeBin)]
241pub struct XrState{
242    pub time: f64,
243    pub head_pose: Pose,
244    pub order_counter: u8,
245    pub anchor: Option<XrAnchor>,
246    pub left_controller: XrController,
247    pub right_controller: XrController,
248    pub left_hand: XrHand,
249    pub right_hand: XrHand,
250}
251impl XrState{
252    pub fn from_lerp(a:&XrState, b:&XrState, f:f32)->Self{
253        Self{
254            order_counter: b.order_counter,
255            time: (b.time - a.time)*f as f64 + a.time,
256            head_pose: Pose::from_lerp(a.head_pose, b.head_pose, f),
257            anchor: b.anchor,
258            left_controller: b.left_controller.clone(),
259            right_controller: b.right_controller.clone(),
260            left_hand: b.left_hand.clone(),
261            right_hand: b.right_hand.clone(),
262        }
263    }
264    
265    pub fn vec_in_head_space(&self,pos:Vec3)->Vec3{
266        self.head_pose.to_mat4().transform_vec4(pos.to_vec4()).to_vec3()
267    }
268    
269    pub fn scene_anchor_pose(&self)->Option<Pose>{
270        if let Some(_anchor) = &self.anchor{
271            // lets construct a pose from 2 positions
272            None
273        }
274        else{
275            None
276        }
277    }
278    
279    pub fn hands(&self)->[&XrHand;2]{
280        [&self.left_hand, &self.right_hand]
281    }
282    pub fn controllers(&self)->[&XrController;2]{
283        [&self.left_controller, &self.right_controller]
284    }
285}
286
287 
288#[derive(Clone, Debug)]
289pub struct XrUpdateEvent {
290    pub state: Rc<XrState>,
291    pub last: Rc<XrState>,
292}
293
294impl XrUpdateEvent{
295            
296    pub fn clicked_x(&self)->bool{self.state.left_controller.click_x() && !self.last.left_controller.click_x()}
297    pub fn clicked_y(&self)->bool{self.state.left_controller.click_y() && !self.last.left_controller.click_y()}
298    pub fn clicked_a(&self)->bool{self.state.right_controller.click_a() && !self.last.right_controller.click_a()}
299    pub fn clicked_b(&self)->bool{self.state.right_controller.click_b() && !self.last.right_controller.click_b()}
300    pub fn clicked_left_thumbstick(&self)->bool{self.state.left_controller.click_thumbstick() && !self.last.left_controller.click_thumbstick()}
301    pub fn clicked_right_thumbstick(&self)->bool{self.state.right_controller.click_thumbstick() && !self.last.right_controller.click_thumbstick()}
302    pub fn clicked_menu(&self)->bool{self.state.left_controller.click_menu() && !self.last.left_controller.click_menu()}
303    pub fn menu_pressed(&self)->bool{self.state.left_hand.menu_pressed() && !self.last.left_hand.menu_pressed()}
304            
305}
306
307impl XrLocalEvent{
308    
309    
310    pub fn from_update_event(e:&XrUpdateEvent, mat:&Mat4)->XrLocalEvent{
311        // alright we have a matrix, take the inverse
312        // then mul all the fingertips and store them in fingertips
313        // then use that
314        let _inv = mat.invert();
315        // lets collect all fingertips
316        let finger_tips = SmallVec::new();
317        for (_hindex, hand) in [&e.state.left_hand, &e.state.right_hand].iter().enumerate(){
318            if hand.in_view(){
319                for (_index,_joint) in hand.joints.iter().enumerate(){
320                    /*if XrHand::is_tip(index){
321                        let pos = inv.transform_vec4(joint.pose.position.to_vec4()).to_vec3();
322                        // todo, ignore all non-push orientations (probably a halfdome)
323                        finger_tips.push(XrFingerTip{
324                            index: index,
325                            is_left: hindex == 0,
326                            pos
327                        })
328                    }*/
329                }
330            }
331        }
332        
333        XrLocalEvent{
334            finger_tips,
335            modifiers: Default::default(),
336            time: e.state.time,
337            update: e.clone(),        
338        }
339    }
340    
341    pub fn hits_with_options_and_test<F>(&self, cx: &mut Cx, area: Area, options: HitOptions, hit_test:F) -> Hit 
342    where F: Fn(DVec2, &Rect, &Option<Margin>)->bool
343    {
344        let rect = area.clipped_rect(cx);
345        for tip in &self.finger_tips{
346            let abs = tip.pos.to_vec2().into();
347            // alright so. how do we clean this up
348            
349            if hit_test(abs, &rect, &options.margin) {
350                if tip.pos.z <20.0 && tip.pos.z > -30.0{
351                    let device = DigitDevice::XrHand { is_left: tip.is_left, index: tip.index };
352                    let digit_id = live_id_num!(xrfinger, tip.index as u64 + if tip.is_left{10} else{0}).into();
353                    cx.fingers.capture_digit(digit_id, area, options.sweep_area, self.time, abs);
354                    return Hit::FingerDown(FingerDownEvent {
355                        window_id: CxWindowPool::id_zero(),
356                        abs,
357                        digit_id,
358                        device,
359                        tap_count: cx.fingers.tap_count(),
360                        modifiers: self.modifiers,
361                        time: self.time,
362                        rect,
363                    });
364                }
365            }
366        }
367        /*
368        if let Some(capture) = cx.fingers.find_area_capture(area) {
369            let digit_id = live_id_num!(xrfinger, 0).into();
370            let device = DigitDevice::XrHand { is_left: false, index: 0 };
371            return Hit::FingerUp(FingerUpEvent {
372                abs_start: capture.abs_start,
373                rect,
374                window_id: CxWindowPool::id_zero(),
375                abs: dvec2(0.0,0.0),
376                digit_id,
377                device,
378                has_long_press_occurred: false,
379                capture_time: capture.time,
380                modifiers: self.modifiers,
381                time: self.time,
382                tap_count: 0,
383                is_over: false,
384                is_sweep: false,
385            })
386        }
387        */
388        // alright lets implement hits for XrUpdateEvent and our area.
389        // our area is a rect in space and our finger tip is a point
390        // we should multiply our orientation with the inverse of the window matrix
391        // and then we should be in the UI space
392        // then its just xy and z
393        
394        return Hit::Nothing
395    }
396}