makepad_widgets/
xr_hands.rs

1use {
2    crate::{
3        makepad_derive_widget::*,
4        makepad_draw::*,
5        widget::*,
6    },
7};
8
9use crate::makepad_draw::shader::draw_cube::DrawCube; 
10
11live_design!{
12    link widgets;
13    use link::theme::*;
14    use link::shaders::*;
15    
16    pub XrHands = {{XrHands}} {
17
18        draw_bullet:{
19            color: #0 
20            
21            fn get_color(self, dp: float)->vec4{
22                let ambient = vec3(0.2,0.2,0.2) 
23                let color = self.color.xyz * dp * self.color.w + ambient;
24                return vec4(Pal::iq1(self.life-self.time+self.index*0.1)*1.0,0.0);//mix(#f00,#4440,3*self.life);
25            }
26            fn get_size(self)->vec3{
27                let size = pow(max(3.0-(self.life),0.0)/4.0,1.);
28                return self.cube_size * size*vec3(0.1,1.2*sin(self.life),(6-self.index+1)*1.0);
29            }
30            fn get_pos(self)->vec3{
31                let travel = self.life * 0.4;
32                return vec3(0.0, 0.0, -travel)
33            }
34            cube_size:vec3(0.01,0.01,0.015);
35        }
36        draw_knuckle:{
37            color: #fff;
38            cube_size:vec3(0.01,0.01,0.015);
39        }
40        draw_tip:{
41            color: #f00;
42            cube_size:vec3(0.01,0.01,0.001);
43        }
44        draw_align:{
45            color:#f00
46            cube_size: vec3(0.02,0.02,0.02)
47        }
48        draw_test:{
49            color:#f00
50            cube_size: vec3(0.02,0.02,0.02)
51        }
52        draw_head:{
53            color:#fff
54            cube_size: vec3(0.2,0.1,0.05)
55        }
56        draw_grip:{
57            color: #777,
58            cube_size: vec3(0.05,0.05,0.05)
59        }
60        draw_aim:{
61            color: #777,
62            cube_size: vec3(0.05,0.05,0.05)
63        }
64                    
65    }
66}
67
68struct Bullet{
69    shot_at: f64,
70    index: usize,
71    pose: Pose,
72}
73#[derive(Default)]
74struct Bullets{
75    last_fired: f64,
76    bullets: Vec<Bullet>,
77}
78
79pub struct XrPeer{
80    id: LiveId,
81    ahead: bool,
82    min_lag: f64,
83    states: Vec<XrState>,
84    bullets: Bullets
85}
86
87impl XrPeer{
88    fn state(&self)->&XrState{
89        self.states.last().as_ref().unwrap()        
90    }
91    fn tween(&self, _host_time:f64)->XrState{
92        // TODO do frame tweening/prediction/packet smoothing
93        if self.states.len()>=2{
94            self.states[0].clone()
95        }
96        else{
97            self.states[0].clone()
98        }
99    }
100}
101
102impl Bullets{
103    fn draw(&mut self, cx:&mut Cx3d, cube:&mut DrawCube, xr_state:&XrState, anchor_map:&Mat4){
104        if xr_state.time < self.last_fired{ // we rejoined
105            self.last_fired = xr_state.time;
106        }
107        if xr_state.time - self.last_fired > 0.005 {
108            for hand in xr_state.hands(){
109                if !hand.in_view(){
110                    continue
111                }
112                for (i,pose) in hand.end_knuckles().iter().enumerate(){
113                    if !hand.tip_active(i){continue;}
114                    
115                    self.last_fired = xr_state.time;
116                    self.bullets.push(Bullet{
117                        shot_at: xr_state.time,
118                        index: i,
119                        pose:**pose
120                    });
121                    if self.bullets.len()>4500{
122                        self.bullets.remove(0);
123                    }
124                }
125            }
126        }
127        for bullet in &self.bullets{
128            let mat = Mat4::mul(&bullet.pose.to_mat4(), anchor_map);
129            cube.index = bullet.index as f32;
130            cube.life = (xr_state.time - bullet.shot_at) as f32;
131            cube.transform = mat;
132            cube.depth_clip = 1.0;
133            cube.draw(cx);
134        }
135    }
136}
137
138const ALIGN_MODE: f64 = 0.4;
139struct AlignMode{
140    anchor: XrAnchor,
141}
142
143#[derive(Live, LiveHook, Widget)]
144pub struct XrHands {
145    #[redraw] #[rust(DrawList::new(cx))] draw_list: DrawList,
146    #[live] draw_align: DrawCube,
147    #[live] draw_test: DrawCube,
148    #[live] draw_head: DrawCube,
149    #[area] #[live] draw_knuckle: DrawCube,
150    #[live] draw_controller: DrawCube,
151    #[live] draw_bullet: DrawCube,
152    #[live] draw_grip: DrawCube,
153    #[live] draw_aim: DrawCube,
154    #[live] draw_tip: DrawCube,
155                
156    #[live] label: DrawText,
157    #[rust] peers: Vec<XrPeer>,
158    #[rust] align_last_click: f64,
159    #[rust] align_mode: Option<AlignMode>,
160    #[rust] bullets: Bullets,
161}
162
163impl XrHands{
164    
165    pub fn leave_peer(&mut self, _cx:&mut Cx, id:LiveId){
166        self.peers.retain(|v| v.id != id);
167    }
168        
169    pub fn update_peer(&mut self, _cx:&mut Cx, id:LiveId, state:XrState, e:&XrUpdateEvent){
170        if let Some(peer) = self.peers.iter_mut().find(|v| v.id == id){
171            peer.ahead = state.time > e.state.time;
172            peer.min_lag = peer.min_lag.min((state.time - e.state.time).abs());
173            let peer_state = peer.state();
174            if state.order_counter>peer_state.order_counter ||
175            peer_state.order_counter - state.order_counter>128{
176                peer.states.insert(0, state);
177            }
178            peer.states.truncate(2);
179        }
180        else{
181            self.peers.push(XrPeer{
182                id, 
183                ahead: false,
184                min_lag: 1.0,
185                states: vec![state], 
186                bullets:Bullets::default()
187            });
188        }
189    }
190    
191    fn handle_alignment(&mut self, cx:&mut Cx, e:&XrUpdateEvent){
192        // the special space gesture
193        
194        if e.menu_pressed() || e.clicked_menu(){
195            if e.state.time - self.align_last_click < ALIGN_MODE{
196                // alright lets toggle align / settings mode
197                if let Some(align_mode) = &mut self.align_mode{
198                    // lets store the anchors
199                    cx.xr_set_local_anchor(align_mode.anchor);
200                    self.align_mode = None;
201                }
202                else if self.align_mode.is_none(){
203                    // we have to load up the alignmode settings
204                    let anchor = if let Some(anchor) = &e.state.anchor{
205                        *anchor
206                    }
207                    else{
208                        XrAnchor{
209                            left: e.state.vec_in_head_space(vec3(-0.2,0.0,-0.4)),
210                            right: e.state.vec_in_head_space(vec3(0.2,0.0,-0.4))
211                        }
212                    };
213                                    
214                    // or spawn the cubes somewhere meaningful
215                    self.align_mode = Some(AlignMode{
216                        anchor,
217                    });
218                }
219                
220            }
221            self.align_last_click = e.state.time;
222        }
223        // possibly move the cubes around
224        if let Some(align_mode) = &mut self.align_mode{
225            if e.state.left_hand.pinch_not_index(){
226                align_mode.anchor.left = e.state.left_hand.tip_pos_thumb();
227            }
228            if e.state.right_hand.pinch_not_index(){
229                align_mode.anchor.right = e.state.right_hand.tip_pos_thumb();
230            }
231            if e.state.left_controller.triggered(){
232                align_mode.anchor.left = e.state.left_controller.aim_pose.position;
233            }
234            if e.state.right_controller.triggered(){
235                align_mode.anchor.right = e.state.right_controller.aim_pose.position;
236            }
237        }
238    }
239    
240    fn draw_alignment(&mut self, cx:&mut Cx3d, _xr_state:&XrState){
241        if let Some(align) = &self.align_mode{
242            //if xr_state.time - align.start_time >  ALIGN_START_TIMEOUT{
243                // lets draw cubes from the quaternions
244                let cube = &mut self.draw_align;
245                cube.color = color!(#00f);
246                cube.transform = Pose::new(align.anchor.to_quat(),align.anchor.left).to_mat4();
247                cube.depth_clip = 1.0;
248                cube.draw(cx);
249                cube.color = color!(#0f0);
250                cube.transform = Pose::new(align.anchor.to_quat_rev(),align.anchor.right).to_mat4();
251                cube.draw(cx);
252            //}
253        }
254    }
255}
256
257impl Widget for XrHands {
258    fn handle_event(&mut self, cx: &mut Cx,event:&Event, _scope:&mut Scope){
259        if let Event::XrUpdate(e) = event{
260            self.handle_alignment(cx, e);
261            self.redraw(cx);
262        }
263    }
264    fn draw_3d(&mut self, cx: &mut Cx3d, _scope:&mut Scope)->DrawStep{
265        self.draw_list.begin_always(cx);
266        
267        fn draw_hands(
268            cx: &mut Cx3d, 
269            cube:&mut DrawCube, 
270            tip: &mut DrawCube,
271            transform: &Mat4, 
272            xr_state:&XrState, 
273        ){
274            // lets draw all the fingers
275            for hand in [&xr_state.left_hand, &xr_state.right_hand]{
276                if hand.in_view(){
277                    for (_index,joint) in hand.joints.iter().enumerate(){
278                        let mat = Mat4::mul(&joint.to_mat4(), transform);
279                        cube.cube_pos = vec3(0.0,0.0,0.0);
280                        cube.transform = mat;
281                        cube.depth_clip = 0.0;
282                        cube.draw(cx);
283                    }
284                }
285                for (i, knuckle) in XrHand::END_KNUCKLES.iter().enumerate(){
286                    if !hand.tip_active(i){continue;}
287                    let joint = &hand.joints[*knuckle];
288                    let mat = Mat4::mul(&joint.to_mat4(), transform);
289                    tip.cube_pos = vec3(0.0,0.0,-hand.tips[i]);
290                    tip.transform = mat;
291                    tip.depth_clip = 0.0;
292                    tip.draw(cx);
293                }
294            }
295        }
296        
297        fn _draw_controllers(
298            cx: &mut Cx3d, 
299            draw_aim:&mut DrawCube, 
300            draw_grip: &mut DrawCube,
301            transform: &Mat4, 
302            xr_state:&XrState, 
303        ){
304            // lets draw our hand controllers
305            let mata = Mat4::mul(&xr_state.left_controller.aim_pose.to_mat4(), transform);
306            draw_aim.cube_pos = vec3(0.0,0.0,0.0);
307            draw_aim.transform = mata;
308            draw_aim.depth_clip = 0.0;
309            draw_aim.draw(cx);
310                                
311            let mata = Mat4::mul(&xr_state.right_controller.grip_pose.to_mat4(), transform);
312            draw_grip.cube_pos = vec3(0.0,0.0,0.0);
313            draw_grip.transform = mata;
314            draw_grip.depth_clip = 0.0;
315            draw_grip.draw(cx);
316        }
317        
318        
319        fn draw_head(
320            cx: &mut Cx3d, 
321            cube:&mut DrawCube, 
322            transform: &Mat4, 
323            xr_state:&XrState, 
324        ){
325            let mata = Mat4::mul(&xr_state.head_pose.to_mat4(), transform);
326            cube.color = vec4(1.0,1.0,1.0,1.0);
327            cube.cube_pos = vec3(0.0,0.0,0.0);
328            cube.transform = mata;
329            cube.depth_clip = 0.0;
330            cube.draw(cx);
331        }
332        
333        fn _draw_democube(
334            cx: &mut Cx3d, 
335            cube:&mut DrawCube, 
336            anchor:&XrAnchor, 
337            ){
338            let _speed = 32.0; 
339            //let rot = (xr_state.time*speed).rem_euclid(360.0) as f32;
340            cube.color = vec4(1.0,1.0,1.0,1.0);
341            cube.cube_size = vec3(0.1,0.1,0.1);
342            cube.cube_pos = vec3(0.0,0.1,0.0);
343            cube.transform = anchor.to_mat4();
344                
345            /*Mat4::txyz_s_ry_rx_txyz(
346                vec3(0.,0.,0.),
347                1.0,
348                rot,rot,
349                vec3(0.,0.,-0.3)
350            );*/
351            cube.depth_clip = 1.0;
352            cube.draw(cx);
353        }
354        // alright lets draw those hands
355        let xr_state = cx.draw_event.xr_state.as_ref().unwrap();
356        
357        self.draw_alignment(cx, xr_state);
358            
359        draw_hands(cx, &mut self.draw_knuckle, &mut self.draw_tip, &Mat4::identity(), &xr_state);
360        
361        //let dt = profile_start();
362        self.bullets.draw(cx, &mut self.draw_bullet, &xr_state, &Mat4::identity());
363        
364        for peer in &mut self.peers{
365            let peer_state = peer.tween(xr_state.time);
366            if let Some(other_anchor) = &peer_state.anchor{
367                if let Some(my_anchor) = &xr_state.anchor{
368                    // alright we need a mapping mat4 from 2 anchors
369                    let anchor_map = other_anchor.mapping_to(my_anchor);
370                    draw_hands(cx, &mut self.draw_knuckle, &mut self.draw_tip, &anchor_map, &peer_state);
371                    
372                    draw_head(cx, &mut self.draw_head, &anchor_map, &peer_state);
373                                        
374                    peer.bullets.draw(cx, &mut self.draw_bullet, &peer_state, &anchor_map)
375                }
376            }
377            else{
378                draw_hands(cx, &mut self.draw_knuckle, &mut self.draw_tip, &Mat4::identity(), &peer_state)
379            }
380        }
381        //profile_end!(dt);         
382        self.draw_list.end(cx);
383        DrawStep::done()
384    }
385}
386