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