~ubuntu-branches/debian/experimental/gpac/experimental

« back to all changes in this revision

Viewing changes to src/compositor/mpeg4_viewport.c

  • Committer: Package Import Robot
  • Author(s): Andres Mejia
  • Date: 2012-02-04 00:12:54 UTC
  • Revision ID: package-import@ubuntu.com-20120204001254-l7v7u4kc4m7cxcqn
Tags: upstream-0.4.5+svn3450~dfsg3
ImportĀ upstreamĀ versionĀ 0.4.5+svn3450~dfsg3

Show diffs side-by-side

added added

removed removed

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