/src/gpac/src/compositor/navigate.c
Line | Count | Source |
1 | | /* |
2 | | * GPAC - Multimedia Framework C SDK |
3 | | * |
4 | | * Authors: Jean Le Feuvre |
5 | | * Copyright (c) Telecom ParisTech 2000-2023 |
6 | | * All rights reserved |
7 | | * |
8 | | * This file is part of GPAC / Scene Compositor sub-project |
9 | | * |
10 | | * GPAC is free software; you can redistribute it and/or modify |
11 | | * it under the terms of the GNU Lesser General Public License as published by |
12 | | * the Free Software Foundation; either version 2, or (at your option) |
13 | | * any later version. |
14 | | * |
15 | | * GPAC is distributed in the hope that it will be useful, |
16 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | | * GNU Lesser General Public License for more details. |
19 | | * |
20 | | * You should have received a copy of the GNU Lesser General Public |
21 | | * License along with this library; see the file COPYING. If not, write to |
22 | | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
23 | | * |
24 | | */ |
25 | | |
26 | | #include "nodes_stacks.h" |
27 | | #include "visual_manager.h" |
28 | | |
29 | | #if !defined(GPAC_DISABLE_COMPOSITOR) |
30 | | |
31 | | #ifndef GPAC_DISABLE_3D |
32 | | |
33 | | static void camera_changed(GF_Compositor *compositor, GF_Camera *cam) |
34 | | { |
35 | | cam->flags |= CAM_IS_DIRTY; |
36 | | gf_sc_invalidate(compositor, NULL); |
37 | | if (compositor->active_layer) gf_node_dirty_set(compositor->active_layer, 0, 1); |
38 | | } |
39 | | |
40 | | #endif |
41 | | |
42 | | static void nav_set_zoom_trans_2d(GF_VisualManager *visual, Fixed zoom, Fixed dx, Fixed dy) |
43 | 0 | { |
44 | 0 | compositor_2d_set_user_transform(visual->compositor, zoom, visual->compositor->trans_x + dx, visual->compositor->trans_y + dy, 0); |
45 | | #ifndef GPAC_DISABLE_3D |
46 | | if (visual->type_3d) camera_changed(visual->compositor, &visual->camera); |
47 | | #endif |
48 | 0 | } |
49 | | |
50 | | |
51 | | #ifndef GPAC_DISABLE_3D |
52 | | |
53 | | /*shortcut*/ |
54 | | static void gf_mx_rotation_matrix(GF_Matrix *mx, SFVec3f axis_pt, SFVec3f axis, Fixed angle) |
55 | | { |
56 | | gf_mx_init(*mx); |
57 | | gf_mx_add_translation(mx, axis_pt.x, axis_pt.y, axis_pt.z); |
58 | | gf_mx_add_rotation(mx, angle, axis.x, axis.y, axis.z); |
59 | | gf_mx_add_translation(mx, -axis_pt.x, -axis_pt.y, -axis_pt.z); |
60 | | } |
61 | | |
62 | | static void view_orbit_x(GF_Compositor *compositor, GF_Camera *cam, Fixed dx) |
63 | | { |
64 | | GF_Matrix mx; |
65 | | if (!dx) return; |
66 | | gf_mx_rotation_matrix(&mx, cam->target, cam->up, dx); |
67 | | gf_mx_apply_vec(&mx, &cam->position); |
68 | | camera_changed(compositor, cam); |
69 | | } |
70 | | static void view_orbit_y(GF_Compositor *compositor, GF_Camera *cam, Fixed dy) |
71 | | { |
72 | | GF_Matrix mx; |
73 | | SFVec3f axis; |
74 | | if (!dy) return; |
75 | | axis = camera_get_right_dir(cam); |
76 | | gf_mx_rotation_matrix(&mx, cam->target, axis, dy); |
77 | | gf_mx_apply_vec(&mx, &cam->position); |
78 | | /*update up vector*/ |
79 | | cam->up = gf_vec_cross(camera_get_pos_dir(cam), axis); |
80 | | gf_vec_norm(&cam->up); |
81 | | camera_changed(compositor, cam); |
82 | | } |
83 | | |
84 | | static void view_exam_x(GF_Compositor *compositor, GF_Camera *cam, Fixed dx) |
85 | | { |
86 | | GF_Matrix mx; |
87 | | if (!dx) return; |
88 | | gf_mx_rotation_matrix(&mx, cam->examine_center, cam->up, dx); |
89 | | gf_mx_apply_vec(&mx, &cam->position); |
90 | | gf_mx_apply_vec(&mx, &cam->target); |
91 | | camera_changed(compositor, cam); |
92 | | } |
93 | | |
94 | | static void view_exam_y(GF_Compositor *compositor, GF_Camera *cam, Fixed dy) |
95 | | { |
96 | | GF_Matrix mx; |
97 | | SFVec3f axis; |
98 | | if (!dy) return; |
99 | | axis = camera_get_right_dir(cam); |
100 | | gf_mx_rotation_matrix(&mx, cam->examine_center, axis, dy); |
101 | | gf_mx_apply_vec(&mx, &cam->position); |
102 | | gf_mx_apply_vec(&mx, &cam->target); |
103 | | /*update up vector*/ |
104 | | cam->up = gf_vec_cross(camera_get_pos_dir(cam), axis); |
105 | | gf_vec_norm(&cam->up); |
106 | | camera_changed(compositor, cam); |
107 | | } |
108 | | |
109 | | static void view_roll(GF_Compositor *compositor, GF_Camera *cam, Fixed dd) |
110 | | { |
111 | | GF_Matrix mx; |
112 | | SFVec3f delta; |
113 | | if (!dd) return; |
114 | | gf_vec_add(delta, cam->target, cam->up); |
115 | | gf_mx_rotation_matrix(&mx, cam->target, camera_get_pos_dir(cam), dd); |
116 | | gf_mx_apply_vec(&mx, &delta); |
117 | | gf_vec_diff(cam->up, delta, cam->target); |
118 | | gf_vec_norm(&cam->up); |
119 | | camera_changed(compositor, cam); |
120 | | } |
121 | | |
122 | | static void update_pan_up(GF_Compositor *compositor, GF_Camera *cam) |
123 | | { |
124 | | SFVec3f axis, dir; |
125 | | /*update up vector so that right is always horizontal (no y component)*/ |
126 | | dir = camera_get_pos_dir(cam); |
127 | | axis = camera_get_right_dir(cam); |
128 | | axis.y = 0; |
129 | | gf_vec_norm(&axis); |
130 | | cam->up = gf_vec_cross(dir, axis); |
131 | | gf_vec_norm(&cam->up); |
132 | | |
133 | | camera_changed(compositor, cam); |
134 | | } |
135 | | |
136 | | static void view_pan_x(GF_Compositor *compositor, GF_Camera *cam, Fixed dx) |
137 | | { |
138 | | GF_Matrix mx; |
139 | | if (!dx) return; |
140 | | gf_mx_rotation_matrix(&mx, cam->position, cam->up, dx); |
141 | | gf_mx_apply_vec(&mx, &cam->target); |
142 | | |
143 | | update_pan_up(compositor, cam); |
144 | | } |
145 | | static void view_pan_y(GF_Compositor *compositor, GF_Camera *cam, Fixed dy) |
146 | | { |
147 | | GF_Matrix mx; |
148 | | GF_Vec prev_target = cam->target; |
149 | | if (!dy) return; |
150 | | gf_mx_rotation_matrix(&mx, cam->position, camera_get_right_dir(cam), dy); |
151 | | gf_mx_apply_vec(&mx, &cam->target); |
152 | | switch (cam->navigate_mode) { |
153 | | case GF_NAVIGATE_WALK: |
154 | | case GF_NAVIGATE_VR: |
155 | | case GF_NAVIGATE_GAME: |
156 | | if (cam->target.z*prev_target.z<0) { |
157 | | cam->target = prev_target; |
158 | | return; |
159 | | } |
160 | | default: |
161 | | break; |
162 | | } |
163 | | |
164 | | update_pan_up(compositor, cam); |
165 | | } |
166 | | |
167 | | /*for translation moves when jumping*/ |
168 | | #define JUMP_SCALE_FACTOR 4 |
169 | | |
170 | | static void view_translate_x(GF_Compositor *compositor, GF_Camera *cam, Fixed dx) |
171 | | { |
172 | | SFVec3f v; |
173 | | if (!dx) return; |
174 | | if (cam->jumping) dx *= JUMP_SCALE_FACTOR; |
175 | | v = gf_vec_scale(camera_get_right_dir(cam), dx); |
176 | | gf_vec_add(cam->target, cam->target, v); |
177 | | gf_vec_add(cam->position, cam->position, v); |
178 | | camera_changed(compositor, cam); |
179 | | } |
180 | | static void view_translate_y(GF_Compositor *compositor, GF_Camera *cam, Fixed dy) |
181 | | { |
182 | | SFVec3f v; |
183 | | if (!dy) return; |
184 | | if (cam->jumping) dy *= JUMP_SCALE_FACTOR; |
185 | | v = gf_vec_scale(cam->up, dy); |
186 | | gf_vec_add(cam->target, cam->target, v); |
187 | | gf_vec_add(cam->position, cam->position, v); |
188 | | camera_changed(compositor, cam); |
189 | | } |
190 | | |
191 | | static void view_translate_z(GF_Compositor *compositor, GF_Camera *cam, Fixed dz) |
192 | | { |
193 | | SFVec3f v; |
194 | | if (!dz) return; |
195 | | if (cam->jumping) dz *= JUMP_SCALE_FACTOR; |
196 | | dz = gf_mulfix(dz, cam->speed); |
197 | | v = gf_vec_scale(camera_get_target_dir(cam), dz); |
198 | | gf_vec_add(cam->target, cam->target, v); |
199 | | gf_vec_add(cam->position, cam->position, v); |
200 | | camera_changed(compositor, cam); |
201 | | } |
202 | | |
203 | | static void view_zoom(GF_Compositor *compositor, GF_Camera *cam, Fixed z) |
204 | | { |
205 | | Fixed oz; |
206 | | if ((z>FIX_ONE) || (z<-FIX_ONE)) return; |
207 | | oz = gf_divfix(cam->vp_fov, cam->fieldOfView); |
208 | | if (oz<FIX_ONE) z/=4; |
209 | | oz += z; |
210 | | if (oz<=0) return; |
211 | | |
212 | | cam->fieldOfView = gf_divfix(cam->vp_fov, oz); |
213 | | if (cam->fieldOfView>GF_PI) cam->fieldOfView=GF_PI; |
214 | | camera_changed(compositor, cam); |
215 | | } |
216 | | |
217 | | Bool gf_sc_fit_world_to_screen(GF_Compositor *compositor) |
218 | | { |
219 | | GF_TraverseState tr_state; |
220 | | SFVec3f pos, diff; |
221 | | Fixed dist, d; |
222 | | GF_Camera *cam; |
223 | | GF_Node *top; |
224 | | |
225 | | #ifndef GPAC_DISABLE_VRML |
226 | | // if (gf_list_count(compositor->visual->back_stack)) return; |
227 | | if (gf_list_count(compositor->visual->view_stack)) return 0; |
228 | | #endif |
229 | | |
230 | | gf_mx_p(compositor->mx); |
231 | | top = gf_sg_get_root_node(compositor->scene); |
232 | | if (!top) { |
233 | | gf_mx_v(compositor->mx); |
234 | | return 0; |
235 | | } |
236 | | memset(&tr_state, 0, sizeof(GF_TraverseState)); |
237 | | gf_mx_init(tr_state.model_matrix); |
238 | | tr_state.traversing_mode = TRAVERSE_GET_BOUNDS; |
239 | | tr_state.visual = compositor->visual; |
240 | | gf_node_traverse(top, &tr_state); |
241 | | if (gf_node_dirty_get(top)) { |
242 | | tr_state.bbox.is_set = 0; |
243 | | } |
244 | | |
245 | | if (!tr_state.bbox.is_set) { |
246 | | gf_mx_v(compositor->mx); |
247 | | /*empty world ...*/ |
248 | | if (tr_state.bbox.radius==-1) return 1; |
249 | | /*2D world with 3D camera forced*/ |
250 | | if (tr_state.bounds.width&&tr_state.bounds.height) return 1; |
251 | | return 0; |
252 | | } |
253 | | |
254 | | cam = &compositor->visual->camera; |
255 | | |
256 | | cam->world_bbox = tr_state.bbox; |
257 | | /*fit is based on bounding sphere*/ |
258 | | dist = gf_divfix(tr_state.bbox.radius, gf_sin(cam->fieldOfView/2) ); |
259 | | gf_vec_diff(diff, cam->center, tr_state.bbox.center); |
260 | | /*do not update if camera is outside the scene bounding sphere and dist is too close*/ |
261 | | if (gf_vec_len(diff) > tr_state.bbox.radius + cam->radius) { |
262 | | gf_vec_diff(diff, cam->vp_position, tr_state.bbox.center); |
263 | | d = gf_vec_len(diff); |
264 | | if (d<dist) { |
265 | | gf_mx_v(compositor->mx); |
266 | | return 1; |
267 | | } |
268 | | } |
269 | | |
270 | | diff = gf_vec_scale(camera_get_pos_dir(cam), dist); |
271 | | gf_vec_add(pos, tr_state.bbox.center, diff); |
272 | | diff = cam->position; |
273 | | camera_set_vectors(cam, pos, cam->vp_orientation, cam->fieldOfView); |
274 | | cam->position = diff; |
275 | | camera_move_to(cam, pos, cam->target, cam->up); |
276 | | if (!compositor->player) { |
277 | | camera_stop_anim(cam); |
278 | | camera_set_vectors(cam, cam->end_pos, cam->end_ori, cam->end_fov); |
279 | | } |
280 | | |
281 | | cam->examine_center = tr_state.bbox.center; |
282 | | cam->flags |= CF_STORE_VP; |
283 | | if (cam->z_far < dist) cam->z_far = 10*dist; |
284 | | camera_changed(compositor, cam); |
285 | | gf_mx_v(compositor->mx); |
286 | | return 1; |
287 | | } |
288 | | |
289 | | static void handle_mouse_move_3d(GF_Compositor *compositor, GF_Camera *cam, u32 keys, Fixed dx, Fixed dy) |
290 | | { |
291 | | Fixed trans_scale = cam->width/20; |
292 | | //if default VP is quite far from center use larger dz/dy moves |
293 | | if (cam->vp_dist>100) trans_scale *= 10; |
294 | | |
295 | | switch (cam->navigate_mode) { |
296 | | /*FIXME- we'll likely need a "step" value for walk at some point*/ |
297 | | case GF_NAVIGATE_WALK: |
298 | | case GF_NAVIGATE_FLY: |
299 | | view_pan_x(compositor, cam, -dx); |
300 | | if (keys & GF_KEY_MOD_CTRL) view_pan_y(compositor, cam, dy); |
301 | | else view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); |
302 | | break; |
303 | | case GF_NAVIGATE_VR: |
304 | | view_pan_x(compositor, cam, -dx); |
305 | | if (keys & GF_KEY_MOD_CTRL) view_zoom(compositor, cam, dy); |
306 | | else view_pan_y(compositor, cam, dy); |
307 | | break; |
308 | | case GF_NAVIGATE_PAN: |
309 | | view_pan_x(compositor, cam, -dx); |
310 | | if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); |
311 | | else view_pan_y(compositor, cam, dy); |
312 | | break; |
313 | | case GF_NAVIGATE_SLIDE: |
314 | | view_translate_x(compositor, cam, gf_mulfix(dx, trans_scale)); |
315 | | if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); |
316 | | else view_translate_y(compositor, cam, gf_mulfix(dy, trans_scale)); |
317 | | break; |
318 | | case GF_NAVIGATE_EXAMINE: |
319 | | if (keys & GF_KEY_MOD_CTRL) { |
320 | | view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); |
321 | | view_roll(compositor, cam, gf_mulfix(dx, trans_scale)); |
322 | | } else { |
323 | | if (ABS(dx) > ABS(dy)) { |
324 | | view_exam_x(compositor, cam, -gf_mulfix(GF_PI, dx)); |
325 | | } else { |
326 | | view_exam_y(compositor, cam, gf_mulfix(GF_PI, dy)); |
327 | | } |
328 | | } |
329 | | break; |
330 | | case GF_NAVIGATE_ORBIT: |
331 | | if (keys & GF_KEY_MOD_CTRL) { |
332 | | view_translate_z(compositor, cam, gf_mulfix(dy, trans_scale)); |
333 | | } else { |
334 | | view_orbit_x(compositor, cam, -gf_mulfix(GF_PI, dx)); |
335 | | view_orbit_y(compositor, cam, gf_mulfix(GF_PI, dy)); |
336 | | } |
337 | | break; |
338 | | case GF_NAVIGATE_GAME: |
339 | | view_pan_x(compositor, cam, -dx); |
340 | | view_pan_y(compositor, cam, dy); |
341 | | break; |
342 | | } |
343 | | } |
344 | | |
345 | | static Bool compositor_handle_navigation_3d(GF_Compositor *compositor, GF_Event *ev) |
346 | | { |
347 | | Fixed x, y, trans_scale; |
348 | | Fixed dx, dy, key_trans, key_pan, key_exam; |
349 | | s32 key_inv; |
350 | | u32 keys; |
351 | | GF_Camera *cam; |
352 | | Fixed zoom = compositor->zoom; |
353 | | |
354 | | cam = NULL; |
355 | | #ifndef GPAC_DISABLE_VRML |
356 | | if (compositor->active_layer) { |
357 | | cam = compositor_layer3d_get_camera(compositor->active_layer); |
358 | | } |
359 | | #endif |
360 | | |
361 | | if (!cam) { |
362 | | cam = &compositor->visual->camera; |
363 | | } |
364 | | if (!cam || (cam->navigate_mode==GF_NAVIGATE_NONE)) return 0; |
365 | | |
366 | | keys = compositor->key_states; |
367 | | if (!cam->navigate_mode && !(keys & GF_KEY_MOD_ALT) ) return 0; |
368 | | x = y = 0; |
369 | | /*renorm between -1, 1*/ |
370 | | if (ev->type <= GF_EVENT_LAST_MOUSE) { |
371 | | x = gf_divfix( INT2FIX(ev->mouse.x - (s32) compositor->visual->width/2), INT2FIX(compositor->visual->width)); |
372 | | y = gf_divfix( INT2FIX(ev->mouse.y - (s32) compositor->visual->height/2), INT2FIX(compositor->visual->height)); |
373 | | } |
374 | | |
375 | | dx = (x - compositor->grab_x); |
376 | | dy = (compositor->grab_y - y); |
377 | | |
378 | | trans_scale = cam->width/20; |
379 | | key_trans = cam->avatar_size.x/2; |
380 | | //if default VP is quite far from center use larger dz/dy moves |
381 | | if (cam->vp_dist>100) trans_scale *= 10; |
382 | | |
383 | | if (cam->world_bbox.is_set && (key_trans*5 > cam->world_bbox.radius)) { |
384 | | key_trans = cam->world_bbox.radius / 100; |
385 | | } |
386 | | |
387 | | key_pan = FIX_ONE/20; |
388 | | key_exam = FIX_ONE/20; |
389 | | key_inv = 1; |
390 | | |
391 | | if (keys & GF_KEY_MOD_SHIFT) { |
392 | | dx *= 4; |
393 | | dy *= 4; |
394 | | key_pan *= 4; |
395 | | key_exam *= 4; |
396 | | key_trans*=4; |
397 | | } |
398 | | |
399 | | if (! compositor->orientation_sensors_active) { |
400 | | Fixed yaw, pitch, roll; |
401 | | gf_mx_get_yaw_pitch_roll(&compositor->visual->camera.modelview, &yaw, &pitch, &roll); |
402 | | compositor->audio_renderer->yaw = yaw; |
403 | | compositor->audio_renderer->pitch = pitch; |
404 | | compositor->audio_renderer->roll = roll; |
405 | | } |
406 | | |
407 | | switch (ev->type) { |
408 | | case GF_EVENT_MOUSEDOWN: |
409 | | /*left*/ |
410 | | if (ev->mouse.button==GF_MOUSE_LEFT) { |
411 | | compositor->grab_x = x; |
412 | | compositor->grab_y = y; |
413 | | compositor->navigation_state = 1; |
414 | | compositor->auto_rotate=0; |
415 | | |
416 | | /*change vp and examine center to current location*/ |
417 | | if ((keys & GF_KEY_MOD_CTRL) && compositor->hit_square_dist) { |
418 | | cam->vp_position = cam->position; |
419 | | cam->vp_orientation = camera_get_orientation(cam->position, cam->target, cam->up); |
420 | | cam->vp_fov = cam->fieldOfView; |
421 | | cam->examine_center = compositor->hit_world_point; |
422 | | camera_changed(compositor, cam); |
423 | | return 1; |
424 | | } |
425 | | } |
426 | | /*right*/ |
427 | | else if (ev->mouse.button==GF_MOUSE_RIGHT) { |
428 | | if (compositor->navigation_state && (cam->navigate_mode==GF_NAVIGATE_WALK)) { |
429 | | camera_jump(cam); |
430 | | gf_sc_invalidate(compositor, NULL); |
431 | | return 1; |
432 | | } |
433 | | else if (keys & GF_KEY_MOD_CTRL) gf_sc_fit_world_to_screen(compositor); |
434 | | } |
435 | | break; |
436 | | |
437 | | case GF_EVENT_MOUSEMOVE: |
438 | | if (compositor->orientation_sensors_active) return 0; |
439 | | |
440 | | if (!compositor->navigation_state) { |
441 | | if (cam->navigate_mode==GF_NAVIGATE_GAME) { |
442 | | /*init mode*/ |
443 | | compositor->grab_x = x; |
444 | | compositor->grab_y = y; |
445 | | compositor->navigation_state = 1; |
446 | | } |
447 | | compositor->auto_rotate=0; |
448 | | return 0; |
449 | | } |
450 | | compositor->navigation_state++; |
451 | | |
452 | | if (x <= -0.49) compositor->auto_rotate = 1; |
453 | | else if (x >= 0.49) compositor->auto_rotate = 2; |
454 | | else if (y <= -0.49) compositor->auto_rotate = 3; |
455 | | else if (y >= 0.49) compositor->auto_rotate = 4; |
456 | | else |
457 | | compositor->auto_rotate = 0; |
458 | | |
459 | | handle_mouse_move_3d(compositor, cam, keys, dx, dy); |
460 | | |
461 | | compositor->grab_x = x; |
462 | | compositor->grab_y = y; |
463 | | return 1; |
464 | | |
465 | | case GF_EVENT_MOUSEWHEEL: |
466 | | switch (cam->navigate_mode) { |
467 | | /*FIXME- we'll likely need a "step" value for walk at some point*/ |
468 | | case GF_NAVIGATE_WALK: |
469 | | case GF_NAVIGATE_FLY: |
470 | | view_pan_y(compositor, cam, gf_mulfix(key_pan, ev->mouse.wheel_pos)); |
471 | | break; |
472 | | case GF_NAVIGATE_VR: |
473 | | view_zoom(compositor, cam, gf_mulfix(key_pan, ev->mouse.wheel_pos)); |
474 | | break; |
475 | | case GF_NAVIGATE_SLIDE: |
476 | | case GF_NAVIGATE_EXAMINE: |
477 | | case GF_NAVIGATE_ORBIT: |
478 | | case GF_NAVIGATE_PAN: |
479 | | if (cam->is_3D) { |
480 | | view_translate_z(compositor, cam, gf_mulfix(trans_scale, ev->mouse.wheel_pos) * ((keys & GF_KEY_MOD_SHIFT) ? 4 : 1)); |
481 | | } else { |
482 | | nav_set_zoom_trans_2d(compositor->visual, zoom + INT2FIX(ev->mouse.wheel_pos)/10, 0, 0); |
483 | | } |
484 | | } |
485 | | return 1; |
486 | | |
487 | | case GF_EVENT_MULTITOUCH: |
488 | | compositor->auto_rotate=0; |
489 | | compositor->navigation_state = 0; |
490 | | if (ev->mtouch.num_fingers==2) { |
491 | | if( ABS(ev->mtouch.pinch) * 100 > 2 ) { |
492 | | if (cam->is_3D) { |
493 | | view_translate_z(compositor, cam, gf_mulfix(cam->width, compositor->visual->width* ev->mtouch.pinch)); |
494 | | } else { |
495 | | nav_set_zoom_trans_2d(compositor->visual, zoom + gf_mulfix(trans_scale, ev->mtouch.pinch), 0, 0); |
496 | | } |
497 | | return 1; |
498 | | } |
499 | | if( ABS(ev->mtouch.rotation) > GF_PI/40 ) { |
500 | | view_roll(compositor, cam, gf_mulfix(ev->mtouch.rotation, trans_scale)); |
501 | | return 1; |
502 | | } |
503 | | } else if (ev->mtouch.num_fingers==3) { |
504 | | compositor->visual->camera.start_zoom = compositor->zoom; |
505 | | compositor->zoom = FIX_ONE; |
506 | | compositor->interoccular_offset = 0; |
507 | | compositor->focdist = 0; |
508 | | compositor->interoccular_offset = 0; |
509 | | compositor->focdist = 0; |
510 | | compositor_3d_reset_camera(compositor); |
511 | | return 1; |
512 | | } |
513 | | return 0; |
514 | | |
515 | | case GF_EVENT_MOUSEUP: |
516 | | if (ev->mouse.button==GF_MOUSE_LEFT) { |
517 | | compositor->navigation_state = 0; |
518 | | } |
519 | | break; |
520 | | |
521 | | case GF_EVENT_KEYDOWN: |
522 | | switch (ev->key.key_code) { |
523 | | case GF_KEY_BACKSPACE: |
524 | | gf_sc_reset_graphics(compositor); |
525 | | return 1; |
526 | | case GF_KEY_C: |
527 | | compositor->collide_mode = compositor->collide_mode ? GF_COLLISION_NONE : GF_COLLISION_DISPLACEMENT; |
528 | | return 1; |
529 | | case GF_KEY_J: |
530 | | if (cam->navigate_mode==GF_NAVIGATE_WALK) { |
531 | | camera_jump(cam); |
532 | | gf_sc_invalidate(compositor, NULL); |
533 | | return 1; |
534 | | } |
535 | | break; |
536 | | case GF_KEY_HOME: |
537 | | if (!compositor->navigation_state) { |
538 | | compositor->visual->camera.start_zoom = compositor->zoom; |
539 | | compositor->zoom = FIX_ONE; |
540 | | compositor->interoccular_offset = 0; |
541 | | compositor->focdist = 0; |
542 | | compositor->interoccular_offset = 0; |
543 | | compositor->focdist = 0; |
544 | | compositor_3d_reset_camera(compositor); |
545 | | } |
546 | | break; |
547 | | case GF_KEY_END: |
548 | | if (cam->navigate_mode==GF_NAVIGATE_GAME) { |
549 | | cam->navigate_mode = GF_NAVIGATE_WALK; |
550 | | compositor->navigation_state = 0; |
551 | | return 1; |
552 | | } |
553 | | break; |
554 | | case GF_KEY_LEFT: |
555 | | key_inv = -1; |
556 | | case GF_KEY_RIGHT: |
557 | | if (keys & GF_KEY_MOD_ALT) { |
558 | | if ( (keys & GF_KEY_MOD_SHIFT) && (compositor->visual->nb_views > 1) ) { |
559 | | /*+ or - 10 cm*/ |
560 | | compositor->focdist += INT2FIX(key_inv); |
561 | | cam->flags |= CAM_IS_DIRTY; |
562 | | GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("AutoStereo view distance %f - focus %f\n", FIX2FLT(compositor->video_out->dispdist)/100, FIX2FLT(compositor->focdist)/100)); |
563 | | gf_sc_invalidate(compositor, NULL); |
564 | | return 1; |
565 | | } |
566 | | return 0; |
567 | | } |
568 | | |
569 | | |
570 | | switch (cam->navigate_mode) { |
571 | | case GF_NAVIGATE_SLIDE: |
572 | | if (keys & GF_KEY_MOD_CTRL) view_pan_x(compositor, cam, key_inv * key_pan); |
573 | | else view_translate_x(compositor, cam, key_inv * key_trans); |
574 | | break; |
575 | | case GF_NAVIGATE_EXAMINE: |
576 | | if (keys & GF_KEY_MOD_CTRL) view_roll(compositor, cam, gf_mulfix(dx, trans_scale)); |
577 | | else view_exam_x(compositor, cam, -key_inv * key_exam); |
578 | | break; |
579 | | case GF_NAVIGATE_ORBIT: |
580 | | if (keys & GF_KEY_MOD_CTRL) view_translate_x(compositor, cam, key_inv * key_trans); |
581 | | else view_orbit_x(compositor, cam, -key_inv * key_exam); |
582 | | break; |
583 | | case GF_NAVIGATE_GAME: |
584 | | view_translate_x(compositor, cam, key_inv * key_trans); |
585 | | break; |
586 | | case GF_NAVIGATE_VR: |
587 | | view_pan_x(compositor, cam, -key_inv * key_pan); |
588 | | break; |
589 | | /*walk/fly/pan*/ |
590 | | default: |
591 | | if (keys & GF_KEY_MOD_CTRL) view_translate_x(compositor, cam, key_inv * key_trans); |
592 | | else view_pan_x(compositor, cam, -key_inv * key_pan); |
593 | | break; |
594 | | } |
595 | | return 1; |
596 | | case GF_KEY_DOWN: |
597 | | key_inv = -1; |
598 | | case GF_KEY_UP: |
599 | | if (keys & GF_KEY_MOD_ALT) { |
600 | | if ( (keys & GF_KEY_MOD_SHIFT) && (compositor->visual->nb_views > 1) ) { |
601 | | compositor->interoccular_offset += FLT2FIX(0.5) * key_inv; |
602 | | GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("AutoStereo interoccular distance %f\n", FIX2FLT(compositor->iod + compositor->interoccular_offset))); |
603 | | cam->flags |= CAM_IS_DIRTY; |
604 | | gf_sc_invalidate(compositor, NULL); |
605 | | return 1; |
606 | | } |
607 | | return 0; |
608 | | } |
609 | | switch (cam->navigate_mode) { |
610 | | case GF_NAVIGATE_SLIDE: |
611 | | if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, key_inv * key_trans); |
612 | | else view_translate_y(compositor, cam, key_inv * key_trans); |
613 | | break; |
614 | | case GF_NAVIGATE_EXAMINE: |
615 | | if (keys & GF_KEY_MOD_CTRL) view_translate_z(compositor, cam, key_inv * key_trans); |
616 | | else view_exam_y(compositor, cam, -key_inv * key_exam); |
617 | | break; |
618 | | case GF_NAVIGATE_ORBIT: |
619 | | if (keys & GF_KEY_MOD_CTRL) view_translate_y(compositor, cam, key_inv * key_trans); |
620 | | else view_orbit_y(compositor, cam, -key_inv * key_exam); |
621 | | break; |
622 | | case GF_NAVIGATE_PAN: |
623 | | if (keys & GF_KEY_MOD_CTRL) view_translate_y(compositor, cam, key_inv * key_trans); |
624 | | else view_pan_y(compositor, cam, key_inv * key_pan); |
625 | | break; |
626 | | case GF_NAVIGATE_GAME: |
627 | | view_translate_z(compositor, cam, key_inv * key_trans); |
628 | | break; |
629 | | case GF_NAVIGATE_VR: |
630 | | if (keys & GF_KEY_MOD_CTRL) view_zoom(compositor, cam, key_inv * key_pan); |
631 | | else view_pan_y(compositor, cam, key_inv * key_pan); |
632 | | break; |
633 | | /*walk/fly*/ |
634 | | default: |
635 | | if (keys & GF_KEY_MOD_CTRL) view_pan_y(compositor, cam, key_inv * key_pan); |
636 | | else view_translate_z(compositor, cam, key_inv * key_trans); |
637 | | break; |
638 | | } |
639 | | return 1; |
640 | | |
641 | | case GF_KEY_PAGEDOWN: |
642 | | if (keys & GF_KEY_MOD_CTRL) { |
643 | | view_zoom(compositor, cam, FIX_ONE/10); |
644 | | return 1; |
645 | | } |
646 | | break; |
647 | | case GF_KEY_PAGEUP: |
648 | | if (keys & GF_KEY_MOD_CTRL) { |
649 | | view_zoom(compositor, cam, -FIX_ONE/10); |
650 | | return 1; |
651 | | } |
652 | | break; |
653 | | case GF_KEY_D: |
654 | | if (keys & GF_KEY_MOD_CTRL) { |
655 | | if (compositor->tvtd==TILE_DEBUG_FULL) compositor->tvtd = 0; |
656 | | else compositor->tvtd ++; |
657 | | gf_sc_invalidate(compositor, NULL); |
658 | | return 1; |
659 | | } |
660 | | break; |
661 | | case GF_KEY_G: |
662 | | if (keys & GF_KEY_MOD_CTRL) { |
663 | | compositor->vrhud_mode++; |
664 | | if (compositor->vrhud_mode==5) compositor->vrhud_mode=0; |
665 | | gf_sc_invalidate(compositor, NULL); |
666 | | return 1; |
667 | | } |
668 | | break; |
669 | | case GF_KEY_A: |
670 | | if (keys & GF_KEY_MOD_CTRL) { |
671 | | compositor->tvtf = !compositor->tvtf; |
672 | | gf_sc_invalidate(compositor, NULL); |
673 | | return 1; |
674 | | } |
675 | | break; |
676 | | } |
677 | | break; |
678 | | case GF_EVENT_SENSOR_ORIENTATION: |
679 | | { |
680 | | Fixed z, w, yaw, /*pitch, */roll; |
681 | | GF_Vec target; |
682 | | GF_Matrix mx; |
683 | | |
684 | | /* In iOS we get x, y, z in quaternions (first measurement is the frame of reference) */ |
685 | | if (ev->sensor.w) { |
686 | | x = ev->sensor.x; |
687 | | y = ev->sensor.y; |
688 | | z = ev->sensor.z; |
689 | | w = ev->sensor.w; |
690 | | |
691 | | yaw = gf_atan2(2*gf_mulfix(z,w) - 2*gf_mulfix(y,x) , 1 - 2*gf_mulfix(z,z) - 2*gf_mulfix(x,x)); |
692 | | //pitch = asin(2*y*z + 2*x*w); |
693 | | roll = gf_atan2(2*gf_mulfix(y,w) - 2*gf_mulfix(z,x) , 1 - 2*gf_mulfix(y,y) - 2*gf_mulfix(x,x)); |
694 | | } else { |
695 | | /* |
696 | | * In Android we get yaw, pitch, roll values (in rad) |
697 | | * The frame of reference is absolute |
698 | | */ |
699 | | yaw = ev->sensor.x; |
700 | | //pitch = ev->sensor.y; |
701 | | roll = ev->sensor.z; |
702 | | } |
703 | | target.x = 0; |
704 | | target.y = -FIX_ONE; |
705 | | target.z = 0; |
706 | | gf_mx_init(mx); |
707 | | gf_mx_add_rotation(&mx, yaw, 0, FIX_ONE, 0); |
708 | | gf_mx_add_rotation(&mx, -roll, FIX_ONE, 0, 0); |
709 | | |
710 | | gf_mx_apply_vec(&mx, &target); |
711 | | |
712 | | cam->target = target; |
713 | | update_pan_up(compositor, cam); |
714 | | } |
715 | | return 1; |
716 | | } |
717 | | return 0; |
718 | | } |
719 | | |
720 | | #endif |
721 | | |
722 | | |
723 | | static Bool compositor_handle_navigation_2d(GF_VisualManager *visual, GF_Event *ev) |
724 | 0 | { |
725 | 0 | Fixed x, y, dx, dy, key_trans, key_rot, zoom, new_zoom; |
726 | 0 | u32 navigation_mode; |
727 | 0 | s32 key_inv; |
728 | 0 | Bool is_pixel_metrics = visual->compositor->traverse_state->pixel_metrics; |
729 | 0 | u32 keys = visual->compositor->key_states; |
730 | |
|
731 | 0 | zoom = visual->compositor->zoom; |
732 | 0 | navigation_mode = visual->compositor->navigate_mode; |
733 | | #ifndef GPAC_DISABLE_3D |
734 | | if (visual->type_3d) navigation_mode = visual->camera.navigate_mode; |
735 | | #endif |
736 | |
|
737 | 0 | if (navigation_mode==GF_NAVIGATE_NONE) return 0; |
738 | 0 | if (!navigation_mode && !(keys & GF_KEY_MOD_ALT) ) return 0; |
739 | | |
740 | | |
741 | 0 | x = y = 0; |
742 | | /*renorm between -1, 1*/ |
743 | 0 | if (ev->type <= GF_EVENT_LAST_MOUSE) { |
744 | 0 | x = INT2FIX(ev->mouse.x); |
745 | 0 | y = INT2FIX(ev->mouse.y); |
746 | 0 | } |
747 | 0 | dx = x - visual->compositor->grab_x; |
748 | 0 | if (visual->center_coords) { |
749 | 0 | dy = visual->compositor->grab_y - y; |
750 | 0 | } else { |
751 | 0 | dy = y - visual->compositor->grab_y; |
752 | 0 | } |
753 | 0 | if (!is_pixel_metrics) { |
754 | 0 | dx /= visual->width; |
755 | 0 | dy /= visual->height; |
756 | 0 | } |
757 | |
|
758 | 0 | key_inv = 1; |
759 | 0 | key_trans = INT2FIX(2); |
760 | 0 | key_rot = GF_PI/100; |
761 | |
|
762 | 0 | if (keys & GF_KEY_MOD_SHIFT) { |
763 | 0 | dx *= 4; |
764 | 0 | dy *= 4; |
765 | 0 | key_rot *= 4; |
766 | 0 | key_trans*=4; |
767 | 0 | } |
768 | |
|
769 | 0 | if (!is_pixel_metrics) { |
770 | 0 | key_trans /= visual->width; |
771 | 0 | } |
772 | |
|
773 | 0 | switch (ev->type) { |
774 | 0 | case GF_EVENT_MOUSEDOWN: |
775 | | /*left*/ |
776 | 0 | if (ev->mouse.button==GF_MOUSE_LEFT) { |
777 | 0 | visual->compositor->grab_x = x; |
778 | 0 | visual->compositor->grab_y = y; |
779 | 0 | visual->compositor->navigation_state = 1; |
780 | | /*update zoom center*/ |
781 | 0 | if (keys & GF_KEY_MOD_CTRL) { |
782 | 0 | visual->compositor->trans_x -= visual->compositor->grab_x - INT2FIX(visual->width)/2; |
783 | 0 | visual->compositor->trans_y += INT2FIX(visual->height)/2 - visual->compositor->grab_y; |
784 | 0 | nav_set_zoom_trans_2d(visual, visual->compositor->zoom, 0, 0); |
785 | 0 | } |
786 | 0 | return 0; |
787 | 0 | } |
788 | 0 | break; |
789 | | |
790 | 0 | case GF_EVENT_MOUSEUP: |
791 | 0 | if (ev->mouse.button==GF_MOUSE_LEFT) { |
792 | 0 | visual->compositor->navigation_state = 0; |
793 | 0 | return 0; |
794 | 0 | } |
795 | 0 | break; |
796 | 0 | case GF_EVENT_MULTITOUCH: |
797 | 0 | if (ev->mtouch.num_fingers==2) { |
798 | 0 | if( ABS(ev->mtouch.pinch) * 100 > 2 ) { |
799 | 0 | new_zoom = zoom + ev->mtouch.pinch * MIN(visual->width, visual->height)/100; |
800 | 0 | nav_set_zoom_trans_2d(visual, new_zoom, 0, 0); |
801 | 0 | return 1; |
802 | 0 | } |
803 | 0 | if( ABS(ev->mtouch.rotation) > GF_PI/40 ) { |
804 | 0 | visual->compositor->rotation -= ev->mtouch.rotation; |
805 | 0 | nav_set_zoom_trans_2d(visual, zoom, 0, 0); |
806 | 0 | return 1; |
807 | 0 | } |
808 | 0 | } else if (ev->mtouch.num_fingers==3) { |
809 | 0 | visual->compositor->trans_x = visual->compositor->trans_y = 0; |
810 | 0 | visual->compositor->rotation = 0; |
811 | 0 | visual->compositor->zoom = FIX_ONE; |
812 | 0 | nav_set_zoom_trans_2d(visual, FIX_ONE, 0, 0); |
813 | 0 | return 1; |
814 | 0 | } |
815 | 0 | return 0; |
816 | | |
817 | 0 | case GF_EVENT_MOUSEWHEEL: |
818 | 0 | switch (navigation_mode) { |
819 | 0 | case GF_NAVIGATE_SLIDE: |
820 | 0 | new_zoom = zoom + INT2FIX(ev->mouse.wheel_pos)/10; |
821 | 0 | nav_set_zoom_trans_2d(visual, new_zoom, 0, 0); |
822 | 0 | return 1; |
823 | 0 | case GF_NAVIGATE_EXAMINE: |
824 | 0 | if (ev->mouse.wheel_pos>0) |
825 | 0 | visual->compositor->rotation += gf_asin( GF_PI / 10); |
826 | 0 | else |
827 | 0 | visual->compositor->rotation -= gf_asin( GF_PI / 10); |
828 | 0 | nav_set_zoom_trans_2d(visual, zoom, 0, 0); |
829 | 0 | return 1; |
830 | 0 | } |
831 | 0 | return 0; |
832 | | |
833 | 0 | case GF_EVENT_MOUSEMOVE: |
834 | 0 | if (!visual->compositor->navigation_state) return 0; |
835 | 0 | visual->compositor->navigation_state++; |
836 | 0 | switch (navigation_mode) { |
837 | 0 | case GF_NAVIGATE_SLIDE: |
838 | 0 | if (keys & GF_KEY_MOD_CTRL) { |
839 | 0 | if (dy) { |
840 | 0 | new_zoom = zoom; |
841 | 0 | if (new_zoom > FIX_ONE) new_zoom += dy/20; |
842 | 0 | else new_zoom += dy/80; |
843 | 0 | nav_set_zoom_trans_2d(visual, new_zoom, 0, 0); |
844 | 0 | } |
845 | 0 | } else { |
846 | 0 | nav_set_zoom_trans_2d(visual, zoom, dx, dy); |
847 | 0 | } |
848 | 0 | break; |
849 | 0 | case GF_NAVIGATE_EXAMINE: |
850 | 0 | { |
851 | 0 | Fixed sin = gf_mulfix(GF_PI, dy) / visual->height; |
852 | | //truncate in [-1;1] for arcsin() |
853 | 0 | if (sin < -FIX_ONE) |
854 | 0 | sin = -FIX_ONE; |
855 | 0 | if (sin > FIX_ONE) |
856 | 0 | sin = FIX_ONE; |
857 | 0 | visual->compositor->rotation += gf_asin(sin); |
858 | 0 | nav_set_zoom_trans_2d(visual, zoom, 0, 0); |
859 | 0 | } |
860 | 0 | break; |
861 | 0 | } |
862 | 0 | visual->compositor->grab_x = x; |
863 | 0 | visual->compositor->grab_y = y; |
864 | 0 | return 1; |
865 | 0 | case GF_EVENT_KEYDOWN: |
866 | 0 | switch (ev->key.key_code) { |
867 | 0 | case GF_KEY_BACKSPACE: |
868 | 0 | gf_sc_reset_graphics(visual->compositor); |
869 | 0 | return 1; |
870 | 0 | case GF_KEY_HOME: |
871 | 0 | if (!visual->compositor->navigation_state) { |
872 | 0 | visual->compositor->trans_x = visual->compositor->trans_y = 0; |
873 | 0 | visual->compositor->rotation = 0; |
874 | 0 | visual->compositor->zoom = FIX_ONE; |
875 | 0 | nav_set_zoom_trans_2d(visual, FIX_ONE, 0, 0); |
876 | 0 | } |
877 | 0 | return 1; |
878 | 0 | case GF_KEY_LEFT: |
879 | 0 | key_inv = -1; |
880 | 0 | case GF_KEY_RIGHT: |
881 | 0 | if (navigation_mode == GF_NAVIGATE_SLIDE) { |
882 | 0 | nav_set_zoom_trans_2d(visual, zoom, key_inv*key_trans, 0); |
883 | 0 | } |
884 | 0 | else { |
885 | 0 | visual->compositor->rotation -= key_inv * key_rot; |
886 | 0 | nav_set_zoom_trans_2d(visual, zoom, 0, 0); |
887 | 0 | } |
888 | 0 | return 1; |
889 | 0 | case GF_KEY_DOWN: |
890 | 0 | key_inv = -1; |
891 | 0 | case GF_KEY_UP: |
892 | 0 | if (navigation_mode == GF_NAVIGATE_SLIDE) { |
893 | 0 | if (keys & GF_KEY_MOD_CTRL) { |
894 | 0 | new_zoom = zoom; |
895 | 0 | if (new_zoom > FIX_ONE) new_zoom += key_inv*FIX_ONE/10; |
896 | 0 | else new_zoom += key_inv*FIX_ONE/20; |
897 | 0 | nav_set_zoom_trans_2d(visual, new_zoom, 0, 0); |
898 | 0 | } else { |
899 | 0 | nav_set_zoom_trans_2d(visual, zoom, 0, key_inv*key_trans); |
900 | 0 | } |
901 | 0 | } |
902 | 0 | else { |
903 | 0 | visual->compositor->rotation += key_inv*key_rot; |
904 | 0 | nav_set_zoom_trans_2d(visual, zoom, 0, 0); |
905 | 0 | } |
906 | 0 | return 1; |
907 | 0 | } |
908 | 0 | break; |
909 | 0 | } |
910 | 0 | return 0; |
911 | 0 | } |
912 | | |
913 | | void compositor_handle_auto_navigation(GF_Compositor *compositor) |
914 | 0 | { |
915 | | #ifndef GPAC_DISABLE_3D |
916 | | GF_Camera *cam = NULL; |
917 | | Fixed dx, dy; |
918 | | #ifndef GPAC_DISABLE_VRML |
919 | | if (compositor->active_layer) { |
920 | | cam = compositor_layer3d_get_camera(compositor->active_layer); |
921 | | } |
922 | | if (!cam) |
923 | | cam = &compositor->visual->camera; |
924 | | #endif |
925 | | |
926 | | dx = dy = 0; |
927 | | switch (compositor->auto_rotate) { |
928 | | case 1: |
929 | | dx = -FIX_ONE/100; |
930 | | break; |
931 | | case 2: |
932 | | dx = FIX_ONE/100; |
933 | | break; |
934 | | case 3: |
935 | | dy = FIX_ONE/100; |
936 | | if (cam->up.z>0.9999) compositor->auto_rotate=4; |
937 | | break; |
938 | | case 4: |
939 | | dy = -FIX_ONE/100; |
940 | | if (cam->up.z<-0.9999) compositor->auto_rotate=3; |
941 | | break; |
942 | | default: |
943 | | return; |
944 | | } |
945 | | if (compositor->gazer_enabled) |
946 | | compositor->gaze_changed = GF_FALSE; |
947 | | handle_mouse_move_3d(compositor, cam, 0, dx, dy); |
948 | | #endif |
949 | 0 | } |
950 | | |
951 | | Bool compositor_handle_navigation(GF_Compositor *compositor, GF_Event *ev) |
952 | 0 | { |
953 | 0 | if (!compositor->scene) return 0; |
954 | | #ifndef GPAC_DISABLE_3D |
955 | | if ( (compositor->visual->type_3d>0) || compositor->active_layer) |
956 | | return compositor_handle_navigation_3d(compositor, ev); |
957 | | #endif |
958 | 0 | return compositor_handle_navigation_2d(compositor->visual, ev); |
959 | 0 | } |
960 | | |
961 | | #endif //!defined(GPAC_DISABLE_COMPOSITOR) |