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 :
29 : #include <gpac/options.h>
30 :
31 :
32 : GF_EXPORT
33 2 : GF_Err gf_sc_get_viewpoint(GF_Compositor *compositor, u32 viewpoint_idx, const char **outName, Bool *is_bound)
34 : {
35 : #ifndef GPAC_DISABLE_VRML
36 : u32 count;
37 : GF_Node *n;
38 2 : if (!compositor->visual) return GF_BAD_PARAM;
39 2 : count = gf_list_count(compositor->visual->view_stack);
40 2 : if (!viewpoint_idx) return GF_BAD_PARAM;
41 2 : if (viewpoint_idx>count) return GF_EOS;
42 :
43 0 : n = (GF_Node*)gf_list_get(compositor->visual->view_stack, viewpoint_idx-1);
44 0 : switch (gf_node_get_tag(n)) {
45 0 : case TAG_MPEG4_Viewport:
46 0 : if (outName)
47 0 : *outName = ((M_Viewport*)n)->description.buffer;
48 0 : if (is_bound)
49 0 : *is_bound = ((M_Viewport*)n)->isBound;
50 : return GF_OK;
51 0 : case TAG_MPEG4_Viewpoint:
52 : #ifndef GPAC_DISABLE_X3D
53 : case TAG_X3D_Viewpoint:
54 : #endif
55 0 : if (outName)
56 0 : *outName = ((M_Viewpoint*)n)->description.buffer;
57 0 : if (is_bound)
58 0 : *is_bound = ((M_Viewpoint*)n)->isBound;
59 : return GF_OK;
60 0 : default:
61 0 : if (outName)
62 0 : *outName = NULL;
63 0 : if (is_bound)
64 0 : *is_bound = GF_FALSE;
65 : return GF_OK;
66 : }
67 : #else
68 : return GF_NOT_SUPPORTED;
69 : #endif
70 : }
71 :
72 : GF_EXPORT
73 2 : GF_Err gf_sc_set_viewpoint(GF_Compositor *compositor, u32 viewpoint_idx, const char *viewpoint_name)
74 : {
75 : #ifndef GPAC_DISABLE_VRML
76 : u32 count, i;
77 : GF_Node *n;
78 2 : if (!compositor->visual) return GF_BAD_PARAM;
79 2 : count = gf_list_count(compositor->visual->view_stack);
80 2 : if (viewpoint_idx>count) return GF_BAD_PARAM;
81 0 : if (!viewpoint_idx && !viewpoint_name) return GF_BAD_PARAM;
82 :
83 0 : if (viewpoint_idx) {
84 : Bool bind;
85 0 : n = (GF_Node*)gf_list_get(compositor->visual->view_stack, viewpoint_idx-1);
86 0 : bind = Bindable_GetIsBound(n);
87 0 : Bindable_SetSetBind(n, !bind);
88 0 : return GF_OK;
89 : }
90 0 : for (i=0; i<count; i++) {
91 : char *name = NULL;
92 0 : n = (GF_Node*)gf_list_get(compositor->visual->view_stack, viewpoint_idx-1);
93 0 : switch (gf_node_get_tag(n)) {
94 0 : case TAG_MPEG4_Viewport:
95 0 : name = ((M_Viewport*)n)->description.buffer;
96 0 : break;
97 0 : case TAG_MPEG4_Viewpoint:
98 0 : name = ((M_Viewpoint*)n)->description.buffer;
99 0 : break;
100 : #ifndef GPAC_DISABLE_X3D
101 0 : case TAG_X3D_Viewpoint:
102 0 : name = ((M_Viewpoint*)n)->description.buffer;
103 0 : break;
104 : #endif
105 : default:
106 : break;
107 : }
108 0 : if (name && !stricmp(name, viewpoint_name)) {
109 0 : Bool bind = Bindable_GetIsBound(n);
110 0 : Bindable_SetSetBind(n, !bind);
111 0 : return GF_OK;
112 : }
113 : }
114 : return GF_BAD_PARAM;
115 : #else
116 : return GF_NOT_SUPPORTED;
117 : #endif
118 : }
119 :
120 : #ifndef GPAC_DISABLE_VRML
121 :
122 :
123 : #define VPCHANGED(__comp) { GF_Event evt; evt.type = GF_EVENT_VIEWPOINTS; gf_sc_send_event(__comp, &evt); }
124 :
125 :
126 144 : static void DestroyViewStack(GF_Node *node)
127 : {
128 144 : ViewStack *st = (ViewStack *) gf_node_get_private(node);
129 144 : PreDestroyBindable(node, st->reg_stacks);
130 144 : gf_list_del(st->reg_stacks);
131 144 : VPCHANGED(gf_sc_get_compositor(node));
132 144 : gf_free(st);
133 144 : }
134 :
135 7 : static void viewport_set_bind(GF_Node *node, GF_Route *route)
136 : {
137 7 : GF_Compositor *rend = gf_sc_get_compositor(node);
138 7 : ViewStack *st = (ViewStack *) gf_node_get_private(node);
139 7 : Bindable_OnSetBind(node, st->reg_stacks, NULL);
140 :
141 7 : gf_sc_invalidate(rend, NULL);
142 : /*notify change of vp stack*/
143 7 : VPCHANGED(rend);
144 : /*and dirty ourselves to force frustrum update*/
145 7 : gf_node_dirty_set(node, 0, 0);
146 7 : }
147 :
148 :
149 1075 : static void TraverseViewport(GF_Node *node, void *rs, Bool is_destroy)
150 : {
151 : Fixed sx, sy, w, h, tx, ty;
152 : #ifndef GPAC_DISABLE_3D
153 : GF_Matrix mx;
154 : #endif
155 : GF_Matrix2D mat;
156 : GF_Rect rc, rc_bckup;
157 1075 : ViewStack *st = (ViewStack *) gf_node_get_private(node);
158 : M_Viewport *vp = (M_Viewport *) node;
159 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
160 :
161 1075 : if (is_destroy) {
162 51 : DestroyViewStack(node);
163 51 : return;
164 : }
165 :
166 : #ifndef GPAC_DISABLE_3D
167 1024 : if (tr_state->visual->type_3d>1) return;
168 : #endif
169 :
170 : /*first traverse, bound if needed*/
171 1024 : if (gf_list_find(tr_state->viewpoints, node) < 0) {
172 51 : gf_list_add(tr_state->viewpoints, node);
173 : assert(gf_list_find(st->reg_stacks, tr_state->viewpoints)==-1);
174 51 : gf_list_add(st->reg_stacks, tr_state->viewpoints);
175 :
176 51 : if (gf_list_get(tr_state->viewpoints, 0) == vp) {
177 51 : if (!vp->isBound) Bindable_SetIsBound(node, 1);
178 : } else {
179 0 : if (gf_inline_is_default_viewpoint(node)) Bindable_SetSetBindEx(node, 1, tr_state->viewpoints);
180 : }
181 51 : VPCHANGED(tr_state->visual->compositor);
182 : /*in any case don't draw the first time (since the viewport could have been declared last)*/
183 51 : gf_sc_invalidate(tr_state->visual->compositor, NULL);
184 51 : return;
185 : }
186 :
187 973 : if (tr_state->traversing_mode != TRAVERSE_BINDABLE) return;
188 580 : if (!vp->isBound) return;
189 :
190 557 : if (gf_list_get(tr_state->viewpoints, 0) != vp)
191 : return;
192 :
193 : #ifndef GPAC_DISABLE_3D
194 557 : if (tr_state->visual->type_3d) {
195 234 : w = tr_state->bbox.max_edge.x - tr_state->bbox.min_edge.x;
196 234 : h = tr_state->bbox.max_edge.y - tr_state->bbox.min_edge.y;
197 : } else
198 : #endif
199 : {
200 323 : w = tr_state->bounds.width;
201 323 : h = tr_state->bounds.height;
202 : }
203 557 : if (!w || !h) return;
204 :
205 :
206 : /*if no parent this is the main viewport, don't update if not changed*/
207 : // if (!tr_state->is_layer && !gf_node_dirty_get(node)) return;
208 :
209 557 : gf_node_dirty_clear(node, 0);
210 :
211 557 : gf_mx2d_init(mat);
212 557 : gf_mx2d_add_translation(&mat, vp->position.x, vp->position.y);
213 557 : gf_mx2d_add_rotation(&mat, 0, 0, vp->orientation);
214 :
215 : //compute scaling ratio
216 557 : sx = (vp->size.x>=0) ? vp->size.x : w;
217 557 : sy = (vp->size.y>=0) ? vp->size.y : h;
218 557 : rc = gf_rect_center(sx, sy);
219 : rc_bckup = rc;
220 :
221 557 : switch (vp->fit) {
222 : /*covers all area and respect aspect ratio*/
223 262 : case 2:
224 262 : if (gf_divfix(rc.width, w) > gf_divfix(rc.height, h)) {
225 12 : rc.width = gf_muldiv(rc.width, h, rc.height);
226 : rc.height = h;
227 : } else {
228 250 : rc.height = gf_muldiv(rc.height , w, rc.width);
229 : rc.width = w;
230 : }
231 : break;
232 : /*fits inside the area and respect AR*/
233 95 : case 1:
234 95 : if (gf_divfix(rc.width, w)> gf_divfix(rc.height, h)) {
235 71 : rc.height = gf_muldiv(rc.height, w, rc.width);
236 : rc.width = w;
237 : } else {
238 24 : rc.width = gf_muldiv(rc.width, h, rc.height);
239 : rc.height = h;
240 : }
241 : break;
242 : /*fit entirely: nothing to change*/
243 : case 0:
244 : rc.width = w;
245 : rc.height = h;
246 : break;
247 : default:
248 : return;
249 : }
250 557 : sx = gf_divfix(rc.width, rc_bckup.width);
251 557 : sy = gf_divfix(rc.height, rc_bckup.height);
252 :
253 : /*viewport on root visual, remove compositor scale*/
254 557 : if (!tr_state->is_layer && (tr_state->visual->compositor->visual==tr_state->visual) ) {
255 473 : sx = gf_divfix(sx, tr_state->visual->compositor->scale_x);
256 473 : sy = gf_divfix(sy, tr_state->visual->compositor->scale_y);
257 : }
258 :
259 557 : rc.x = - rc.width/2;
260 557 : rc.y = rc.height/2;
261 :
262 : tx = ty = 0;
263 557 : if (vp->fit && vp->alignment.count) {
264 : /*left alignment*/
265 357 : if (vp->alignment.vals[0] == -1) tx = rc.width/2 - w/2;
266 345 : else if (vp->alignment.vals[0] == 1) tx = w/2 - rc.width/2;
267 :
268 357 : if (vp->alignment.count>1) {
269 : /*top-alignment*/
270 298 : if (vp->alignment.vals[1]==-1) ty = rc.height/2 - h/2;
271 286 : else if (vp->alignment.vals[1]==1) ty = h/2 - rc.height/2;
272 : }
273 : }
274 :
275 557 : gf_mx2d_init(mat);
276 557 : if (tr_state->pixel_metrics) {
277 557 : gf_mx2d_add_scale(&mat, sx, sy);
278 : } else {
279 : /*if we are not in pixelMetrics, undo the meterMetrics->pixelMetrics transformation*/
280 0 : gf_mx2d_add_scale(&mat, gf_divfix(sx, tr_state->min_hsize), gf_divfix(sy, tr_state->min_hsize) );
281 : }
282 557 : gf_mx2d_add_translation(&mat, tx, ty);
283 :
284 557 : gf_mx2d_add_translation(&mat, -gf_mulfix(vp->position.x,sx), -gf_mulfix(vp->position.y,sy) );
285 557 : gf_mx2d_add_rotation(&mat, 0, 0, vp->orientation);
286 :
287 557 : tr_state->bounds = rc;
288 557 : tr_state->bounds.x += tx;
289 557 : tr_state->bounds.y += ty;
290 :
291 : #ifndef GPAC_DISABLE_3D
292 557 : if (tr_state->visual->type_3d) {
293 : /*in layers directly modify the model matrix*/
294 234 : if (tr_state->is_layer) {
295 28 : gf_mx_from_mx2d(&mx, &mat);
296 28 : gf_mx_add_matrix(&tr_state->model_matrix, &mx);
297 : }
298 : /*otherwise add to camera viewport matrix*/
299 : else {
300 206 : gf_mx_from_mx2d(&tr_state->camera->viewport, &mat);
301 206 : tr_state->camera->flags = (CAM_HAS_VIEWPORT | CAM_IS_DIRTY);
302 : }
303 : } else
304 : #endif
305 323 : gf_mx2d_pre_multiply(&tr_state->transform, &mat);
306 : }
307 :
308 51 : void compositor_init_viewport(GF_Compositor *compositor, GF_Node *node)
309 : {
310 : ViewStack *ptr;
311 51 : GF_SAFEALLOC(ptr, ViewStack);
312 51 : if (!ptr) {
313 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate viewport stack\n"));
314 : return;
315 : }
316 :
317 51 : ptr->reg_stacks = gf_list_new();
318 :
319 51 : gf_node_set_private(node, ptr);
320 51 : gf_node_set_callback_function(node, TraverseViewport);
321 51 : ((M_Viewport*)node)->on_set_bind = viewport_set_bind;
322 : }
323 :
324 :
325 : #ifndef GPAC_DISABLE_3D
326 :
327 11 : static void viewpoint_set_bind(GF_Node *node, GF_Route *route)
328 : {
329 11 : GF_Compositor *rend = gf_sc_get_compositor(node);
330 11 : ViewStack *st = (ViewStack *) gf_node_get_private(node);
331 :
332 11 : if (!((M_Viewpoint*)node)->isBound )
333 11 : st->prev_was_bound = 0;
334 11 : Bindable_OnSetBind(node, st->reg_stacks, NULL);
335 11 : gf_sc_invalidate(rend, NULL);
336 : /*notify change of vp stack*/
337 11 : VPCHANGED(rend);
338 : /*and dirty ourselves to force frustrum update*/
339 11 : gf_node_dirty_set(node, 0, 0);
340 11 : }
341 :
342 19790 : static void TraverseViewpoint(GF_Node *node, void *rs, Bool is_destroy)
343 : {
344 : SFVec3f pos, v1, v2;
345 : SFRotation ori;
346 : GF_Matrix mx;
347 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
348 : M_Viewpoint *vp = (M_Viewpoint*) node;
349 19790 : ViewStack *st = (ViewStack *) gf_node_get_private(node);
350 :
351 19790 : if (is_destroy) {
352 61 : DestroyViewStack(node);
353 61 : return;
354 : }
355 : /*may happen in get_bounds*/
356 19729 : if (!tr_state->viewpoints) return;
357 : // if (!tr_state->camera->is_3D) return;
358 :
359 : /*first traverse, bound if needed*/
360 19686 : if (gf_list_find(tr_state->viewpoints, node) < 0) {
361 63 : gf_list_add(tr_state->viewpoints, node);
362 : assert(gf_list_find(st->reg_stacks, tr_state->viewpoints)==-1);
363 63 : gf_list_add(st->reg_stacks, tr_state->viewpoints);
364 :
365 63 : if (gf_list_get(tr_state->viewpoints, 0) == vp) {
366 55 : if (!vp->isBound) Bindable_SetIsBound(node, 1);
367 : } else {
368 8 : if (gf_inline_is_default_viewpoint(node)) Bindable_SetSetBind(node, 1);
369 : }
370 63 : VPCHANGED(tr_state->visual->compositor);
371 : /*in any case don't draw the first time (since the viewport could have been declared last)*/
372 63 : if (tr_state->layer3d) gf_node_dirty_set(tr_state->layer3d, GF_SG_VRML_BINDABLE_DIRTY, 0);
373 63 : gf_sc_invalidate(tr_state->visual->compositor, NULL);
374 : }
375 : /*not evaluating vp, return*/
376 19686 : if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
377 : /*store model matrix if changed - NOTE: we always have a 1-frame delay between VP used and real world...
378 : we could remove this by pre-traversing the scene before applying vp, but that would mean 2 scene
379 : traversals*/
380 12195 : if ((tr_state->traversing_mode==TRAVERSE_SORT) || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) ) {
381 6450 : if (!gf_mx_equal(&st->world_view_mx, &tr_state->model_matrix)) {
382 : gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
383 254 : gf_node_dirty_set(node, 0, 0);
384 : }
385 : }
386 : return;
387 : }
388 :
389 : /*not bound or in 2D visual*/
390 7491 : if (!vp->isBound || !tr_state->navigations) return;
391 :
392 7417 : if (!gf_node_dirty_get(node)) {
393 7215 : if ((tr_state->vp_size.x == st->last_vp_size.x) && (tr_state->vp_size.y == st->last_vp_size.y)) return;
394 : }
395 202 : gf_node_dirty_clear(node, 0);
396 :
397 202 : st->last_vp_size.x = tr_state->vp_size.x;
398 202 : st->last_vp_size.y = tr_state->vp_size.y;
399 :
400 : /*move to local system*/
401 202 : gf_mx_copy(mx, st->world_view_mx);
402 202 : gf_mx_add_translation(&mx, vp->position.x, vp->position.y, vp->position.z);
403 202 : gf_mx_add_rotation(&mx, vp->orientation.q, vp->orientation.x, vp->orientation.y, vp->orientation.z);
404 202 : gf_mx_decompose(&mx, &pos, &v1, &ori, &v2);
405 : /*get center*/
406 202 : v1.x = v1.y = v1.z = 0;
407 : #ifndef GPAC_DISABLE_X3D
408 : /*X3D specifies examine center*/
409 202 : if (gf_node_get_tag(node)==TAG_X3D_Viewpoint) v1 = ((X_Viewpoint *)node)->centerOfRotation;
410 : #endif
411 202 : gf_mx_apply_vec(&st->world_view_mx, &v1);
412 : /*set frustrum param - animate only if not bound last frame and jump false*/
413 202 : visual_3d_viewpoint_change(tr_state, node, (!st->prev_was_bound && !vp->jump) ? 1 : 0, vp->fieldOfView, pos, ori, v1);
414 202 : st->prev_was_bound = 1;
415 : }
416 :
417 61 : void compositor_init_viewpoint(GF_Compositor *compositor, GF_Node *node)
418 : {
419 : ViewStack *st;
420 61 : GF_SAFEALLOC(st, ViewStack);
421 61 : if (!st) {
422 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate viewpoint stack\n"));
423 : return;
424 : }
425 :
426 61 : st->reg_stacks = gf_list_new();
427 122 : gf_mx_init(st->world_view_mx);
428 61 : gf_node_set_private(node, st);
429 61 : gf_node_set_callback_function(node, TraverseViewpoint);
430 61 : ((M_Viewpoint*)node)->on_set_bind = viewpoint_set_bind;
431 : }
432 :
433 : #endif
434 :
435 0 : static void navinfo_set_bind(GF_Node *node, GF_Route *route)
436 : {
437 0 : if (node) {
438 0 : ViewStack *st = (ViewStack *) gf_node_get_private(node);
439 0 : Bindable_OnSetBind(node, st->reg_stacks, NULL);
440 0 : gf_sc_invalidate( gf_sc_get_compositor(node), NULL);
441 : }
442 0 : }
443 :
444 5187 : static void TraverseNavigationInfo(GF_Node *node, void *rs, Bool is_destroy)
445 : {
446 : u32 i;
447 : #ifndef GPAC_DISABLE_3D
448 : u32 nb_select_mode;
449 : SFVec3f start, end;
450 : Fixed scale;
451 5187 : ViewStack *st = (ViewStack *) gf_node_get_private(node);
452 : #endif
453 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
454 : M_NavigationInfo *ni = (M_NavigationInfo *) node;
455 :
456 5187 : if (is_destroy) {
457 28 : DestroyViewStack(node);
458 28 : return;
459 : }
460 : #ifdef GPAC_DISABLE_3D
461 :
462 : /*FIXME, we only deal with one node, no bind stack for the current time*/
463 : for (i=0; i<ni->type.count; i++) {
464 : if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "NONE")) {
465 : tr_state->visual->compositor->navigation_disabled = 1;
466 : }
467 : }
468 : #else
469 :
470 5159 : if (!tr_state->navigations) return;
471 :
472 : /*first traverse, bound if needed*/
473 5146 : if (gf_list_find(tr_state->navigations, node) < 0) {
474 28 : gf_list_add(tr_state->navigations, node);
475 28 : if (gf_list_get(tr_state->navigations, 0) == ni) {
476 28 : if (!ni->isBound) Bindable_SetIsBound(node, 1);
477 : }
478 : assert(gf_list_find(st->reg_stacks, tr_state->navigations)==-1);
479 28 : gf_list_add(st->reg_stacks, tr_state->navigations);
480 28 : gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
481 : /*in any case don't draw the first time*/
482 28 : gf_sc_invalidate(tr_state->visual->compositor, NULL);
483 28 : return;
484 : }
485 : /*not bound*/
486 5118 : if (!ni->isBound) return;
487 : /*not evaluating, return*/
488 5118 : if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
489 3060 : if ((tr_state->traversing_mode==TRAVERSE_SORT) || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) ) {
490 1300 : if (!gf_mx_equal(&st->world_view_mx, &tr_state->model_matrix)) {
491 : gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
492 0 : gf_node_dirty_set(node, 0, 0);
493 : }
494 : }
495 : return;
496 : }
497 :
498 2058 : if (!gf_node_dirty_get(node)) return;
499 20 : gf_node_dirty_clear(node, 0);
500 :
501 : nb_select_mode = 0;
502 20 : tr_state->camera->navigation_flags = 0;
503 20 : tr_state->camera->navigate_mode = 0;
504 55 : for (i=0; i<ni->type.count; i++) {
505 35 : if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "ANY")) tr_state->camera->navigation_flags |= NAV_ANY;
506 : else {
507 22 : nb_select_mode++;
508 : }
509 :
510 35 : if (!tr_state->camera->navigate_mode) {
511 27 : if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "NONE")) tr_state->camera->navigate_mode = GF_NAVIGATE_NONE;
512 26 : else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "WALK")) tr_state->camera->navigate_mode = GF_NAVIGATE_WALK;
513 22 : else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "EXAMINE")) tr_state->camera->navigate_mode = GF_NAVIGATE_EXAMINE;
514 9 : else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "FLY")) tr_state->camera->navigate_mode = GF_NAVIGATE_FLY;
515 9 : else if (ni->type.vals[i] && !stricmp(ni->type.vals[i], "VR")) tr_state->camera->navigate_mode = GF_NAVIGATE_VR;
516 : }
517 : }
518 20 : if (nb_select_mode>1) tr_state->camera->navigation_flags |= NAV_SELECTABLE;
519 :
520 20 : if (ni->headlight) tr_state->camera->navigation_flags |= NAV_HEADLIGHT;
521 :
522 20 : start.x = start.y = start.z = 0;
523 20 : end.x = end.y = 0;
524 20 : end.z = FIX_ONE;
525 20 : gf_mx_apply_vec(&st->world_view_mx, &start);
526 20 : gf_mx_apply_vec(&st->world_view_mx, &end);
527 20 : gf_vec_diff(end, end, start);
528 20 : scale = gf_vec_len(end);
529 :
530 20 : tr_state->camera->speed = gf_mulfix(scale, ni->speed);
531 20 : tr_state->camera->visibility = gf_mulfix(scale, ni->visibilityLimit);
532 20 : if (ni->avatarSize.count) tr_state->camera->avatar_size.x = gf_mulfix(scale, ni->avatarSize.vals[0]);
533 20 : if (ni->avatarSize.count>1) tr_state->camera->avatar_size.y = gf_mulfix(scale, ni->avatarSize.vals[1]);
534 20 : if (ni->avatarSize.count>2) tr_state->camera->avatar_size.z = gf_mulfix(scale, ni->avatarSize.vals[2]);
535 :
536 : #if 0
537 : if (tr_state->pixel_metrics) {
538 : u32 s = MAX(tr_state->visual->width, tr_state->visual->height);
539 : s /= 2;
540 : // tr_state->camera->speed = ni->speed;
541 : tr_state->camera->visibility *= s;
542 : tr_state->camera->avatar_size.x *= s;
543 : tr_state->camera->avatar_size.y *= s;
544 : tr_state->camera->avatar_size.z *= s;
545 : }
546 : #endif
547 :
548 : #endif
549 :
550 : }
551 :
552 28 : void compositor_init_navigation_info(GF_Compositor *compositor, GF_Node *node)
553 : {
554 : ViewStack *st;
555 28 : GF_SAFEALLOC(st, ViewStack);
556 28 : if (!st) {
557 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate navigation stack\n"));
558 : return;
559 : }
560 :
561 28 : st->reg_stacks = gf_list_new();
562 28 : gf_node_set_private(node, st);
563 28 : gf_node_set_callback_function(node, TraverseNavigationInfo);
564 28 : ((M_NavigationInfo*)node)->on_set_bind = navinfo_set_bind;
565 :
566 : #ifdef GPAC_ENABLE_COVERAGE
567 28 : if (gf_sys_is_cov_mode()) {
568 : navinfo_set_bind(NULL, NULL);
569 : }
570 : #endif
571 : }
572 :
573 :
574 : #ifndef GPAC_DISABLE_3D
575 :
576 2 : static void fog_set_bind(GF_Node *node, GF_Route *route)
577 : {
578 2 : ViewStack *st = (ViewStack *) gf_node_get_private(node);
579 2 : Bindable_OnSetBind(node, st->reg_stacks, NULL);
580 2 : gf_sc_invalidate(gf_sc_get_compositor(node), NULL);
581 2 : }
582 :
583 5035 : static void TraverseFog(GF_Node *node, void *rs, Bool is_destroy)
584 : {
585 : Fixed density, vrange;
586 : SFVec3f start, end;
587 : ViewStack *vp_st;
588 : M_Viewpoint *vp;
589 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
590 : M_Fog *fog = (M_Fog *) node;
591 5035 : ViewStack *st = (ViewStack *) gf_node_get_private(node);
592 :
593 5035 : if (is_destroy) {
594 4 : DestroyViewStack(node);
595 4 : return;
596 : }
597 :
598 5031 : if (!tr_state->fogs) return;
599 :
600 : /*first traverse, bound if needed*/
601 4907 : if (gf_list_find(tr_state->fogs, node) < 0) {
602 4 : gf_list_add(tr_state->fogs, node);
603 4 : if (gf_list_get(tr_state->fogs, 0) == fog) {
604 4 : if (!fog->isBound) Bindable_SetIsBound(node, 1);
605 : }
606 : assert(gf_list_find(st->reg_stacks, tr_state->fogs)==-1);
607 4 : gf_list_add(st->reg_stacks, tr_state->fogs);
608 :
609 4 : gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
610 : /*in any case don't draw the first time*/
611 4 : gf_sc_invalidate(tr_state->visual->compositor, NULL);
612 4 : return;
613 : }
614 : /*not evaluating, return*/
615 4903 : if (tr_state->traversing_mode != TRAVERSE_BINDABLE) {
616 3607 : if ((tr_state->traversing_mode==TRAVERSE_SORT) || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) )
617 2168 : gf_mx_copy(st->world_view_mx, tr_state->model_matrix);
618 : return;
619 : }
620 : /*not bound*/
621 1296 : if (!fog->isBound || !fog->visibilityRange) return;
622 :
623 : /*fog visibility is expressed in current bound VP so get its matrix*/
624 1288 : vp = (M_Viewpoint*)gf_list_get(tr_state->viewpoints, 0);
625 : vp_st = NULL;
626 1288 : if (vp && vp->isBound) vp_st = (ViewStack *) gf_node_get_private((GF_Node *)vp);
627 :
628 1288 : start.x = start.y = start.z = 0;
629 1288 : end.x = end.y = 0;
630 1288 : end.z = fog->visibilityRange;
631 1288 : if (vp_st) {
632 1172 : gf_mx_apply_vec(&vp_st->world_view_mx, &start);
633 1172 : gf_mx_apply_vec(&vp_st->world_view_mx, &end);
634 : }
635 1288 : gf_mx_apply_vec(&st->world_view_mx, &start);
636 1288 : gf_mx_apply_vec(&st->world_view_mx, &end);
637 1288 : gf_vec_diff(end, end, start);
638 1288 : vrange = gf_vec_len(end);
639 :
640 1288 : density = gf_invfix(vrange);
641 1288 : visual_3d_set_fog(tr_state->visual, fog->fogType.buffer, fog->color, density, vrange);
642 : }
643 :
644 4 : void compositor_init_fog(GF_Compositor *compositor, GF_Node *node)
645 : {
646 : ViewStack *st;
647 4 : GF_SAFEALLOC(st, ViewStack);
648 4 : if (!st) {
649 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate fog stack\n"));
650 : return;
651 : }
652 :
653 4 : st->reg_stacks = gf_list_new();
654 4 : gf_node_set_private(node, st);
655 4 : gf_node_set_callback_function(node, TraverseFog);
656 4 : ((M_Fog*)node)->on_set_bind = fog_set_bind;
657 : }
658 :
659 : #endif /*GPAC_DISABLE_3D*/
660 :
661 : #endif /*GPAC_DISABLE_VRML*/
|