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 :
27 : #include "nodes_stacks.h"
28 : #include "mpeg4_grouping.h"
29 : #include "visual_manager.h"
30 :
31 : #ifndef GPAC_DISABLE_VRML
32 :
33 : /*This is the generic routine for child traversing*/
34 359686 : void group_2d_traverse(GF_Node *node, GroupingNode2D *group, GF_TraverseState *tr_state)
35 : {
36 : u32 backup;
37 : #ifdef GF_SR_USE_VIDEO_CACHE
38 : Bool group_cached;
39 : #endif
40 : GF_List *sensor_backup;
41 : GF_ChildNodeItem *child;
42 :
43 359686 : backup = gf_node_dirty_get(node);
44 359686 : if (backup & GF_SG_CHILD_DIRTY) {
45 : GF_SensorHandler *hsens;
46 : Bool check_anchor=0;
47 51502 : u32 ntag = gf_node_get_tag(node);
48 51502 : group->flags &= ~GROUP_HAS_SENSORS;
49 51502 : if (group->sensors) gf_list_reset(group->sensors);
50 :
51 51502 : drawable_reset_group_highlight(tr_state, node);
52 :
53 : /*never performs bounds recompute on the fly in 2D since we don't cull 2D groups
54 : but still mark the group as empty*/
55 51502 : group->bounds.width = 0;
56 : /*special case for anchor which is a parent node acting as a sensor*/
57 51502 : if (ntag==TAG_MPEG4_Anchor) check_anchor=1;
58 : #ifndef GPAC_DISABLE_X3D
59 51496 : else if (ntag==TAG_X3D_Anchor) check_anchor=1;
60 : #endif
61 : if (check_anchor) {
62 : GF_SensorHandler *gf_sc_anchor_get_handler(GF_Node *n);
63 :
64 6 : hsens = gf_sc_anchor_get_handler(node);
65 6 : if (hsens) {
66 6 : if (!group->sensors) group->sensors = gf_list_new();
67 6 : gf_list_add(group->sensors, hsens);
68 6 : group->flags |= GROUP_HAS_SENSORS | GROUP_IS_ANCHOR;
69 : }
70 : } else {
71 51496 : child = ((GF_ParentNode *)node)->children;
72 309937 : while (child) {
73 206945 : hsens = compositor_mpeg4_get_sensor_handler_ex(child->node, GF_TRUE);
74 206945 : if (hsens) {
75 7673 : if (!group->sensors) group->sensors = gf_list_new();
76 7673 : gf_list_add(group->sensors, hsens);
77 7673 : group->flags |= GROUP_HAS_SENSORS;
78 : }
79 206945 : child = child->next;
80 : }
81 : }
82 : }
83 : /*sub-tree not dirty and getting bounds, direct copy */
84 308184 : else if ((tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) && !tr_state->for_node && group->bounds.width) {
85 916 : tr_state->bounds = group->bounds;
86 916 : return;
87 : }
88 :
89 :
90 : #ifdef GF_SR_USE_VIDEO_CACHE
91 : group_cached = group_2d_cache_traverse(node, group, tr_state);
92 : #endif
93 :
94 : /*now here is the trick: ExternProtos may not be loaded at this point, in which case we can't
95 : perform proper culling. Unloaded ExternProto signal themselves by invalidating their parent
96 : graph to get a new traversal. We must therefore reset the CHILD_DIRTY flag before computing
97 : bounds otherwise we'll never re-invalidate the subgraph anymore*/
98 358770 : gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
99 :
100 :
101 : #ifdef GF_SR_USE_VIDEO_CACHE
102 : if (group_cached) return;
103 : #endif
104 :
105 : /*no culling in 2d*/
106 :
107 : /*picking: collect sensors*/
108 : sensor_backup = NULL;
109 358770 : if ((tr_state->traversing_mode==TRAVERSE_PICK) && (group->flags & GROUP_HAS_SENSORS) ) {
110 : /*reset sensor stack if any sensors at this level*/
111 60648 : sensor_backup = tr_state->vrml_sensors;
112 : assert(group->sensors);
113 60648 : tr_state->vrml_sensors = group->sensors;
114 : }
115 :
116 :
117 358770 : if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
118 651 : child = ((GF_ParentNode *)node)->children;
119 651 : backup = tr_state->text_split_mode;
120 651 : if (tr_state->text_split_mode && (gf_node_list_get_count(child)>1) ) tr_state->text_split_mode = 0;
121 651 : group->flags &= ~GROUP_SKIP_CULLING;
122 651 : group->bounds.width = group->bounds.height = 0;
123 651 : tr_state->bounds.width = tr_state->bounds.height = 0;
124 : #ifndef GPAC_DISABLE_3D
125 651 : tr_state->bbox.is_set = 0;
126 : #endif
127 2930 : while (child) {
128 1628 : gf_node_traverse(child->node, tr_state);
129 1628 : if (tr_state->disable_cull) {
130 2 : group->flags |= GROUP_SKIP_CULLING;
131 2 : tr_state->disable_cull = 0;
132 : }
133 : /*handle 3D nodes in 2D groups*/
134 : #ifndef GPAC_DISABLE_3D
135 1628 : if (tr_state->bbox.is_set) {
136 99 : gf_rect_from_bbox(&tr_state->bounds, &tr_state->bbox);
137 99 : tr_state->bbox.is_set = 0;
138 : }
139 : #endif
140 1628 : gf_rect_union(&group->bounds, &tr_state->bounds);
141 1628 : tr_state->bounds.width = tr_state->bounds.height = 0;
142 1628 : child = child->next;
143 : }
144 :
145 651 : tr_state->bounds = group->bounds;
146 :
147 651 : if (group->flags & GROUP_SKIP_CULLING)
148 2 : tr_state->disable_cull = 1;
149 651 : tr_state->text_split_mode = backup;
150 : }
151 : /*TRAVERSE_SORT */
152 358119 : else if (tr_state->traversing_mode==TRAVERSE_SORT) {
153 227222 : Bool prev_inv = tr_state->invalidate_all;
154 : #ifdef GF_SR_USE_VIDEO_CACHE
155 : DrawableContext *first_ctx = tr_state->visual->cur_context;
156 : Bool skip_first_ctx = (first_ctx && first_ctx->drawable) ? 1 : 0;
157 : u32 cache_too_small = 0;
158 : u32 traverse_time = gf_sys_clock();
159 : u32 last_cache_idx = gf_list_count(tr_state->visual->compositor->cached_groups_queue);
160 : tr_state->cache_too_small = 0;
161 : #endif
162 :
163 227222 : if (backup & GF_SG_VRML_COLOR_DIRTY) {
164 0 : tr_state->invalidate_all = 1;
165 0 : gf_node_dirty_clear(node, GF_SG_VRML_COLOR_DIRTY);
166 : }
167 :
168 227222 : child = ((GF_ParentNode *)node)->children;
169 1039149 : while (child) {
170 584705 : gf_node_traverse(child->node, tr_state);
171 584705 : child = child->next;
172 : #ifdef GF_SR_USE_VIDEO_CACHE
173 : if (tr_state->cache_too_small)
174 : cache_too_small++;
175 : #endif
176 : }
177 :
178 227222 : tr_state->invalidate_all = prev_inv;
179 :
180 : #ifdef GF_SR_USE_VIDEO_CACHE
181 : if (cache_too_small) {
182 : tr_state->cache_too_small = 1;
183 : } else {
184 : /*get the traversal time for each group*/
185 : traverse_time = gf_sys_clock() - traverse_time;
186 : group->traverse_time += traverse_time;
187 : /*record the traversal information and turn cache on if possible*/
188 : group_2d_cache_evaluate(node, group, tr_state, first_ctx, skip_first_ctx, last_cache_idx);
189 : }
190 : #endif
191 :
192 227222 : drawable_check_focus_highlight(node, tr_state, NULL);
193 : }
194 : else {
195 130897 : child = ((GF_ParentNode *)node)->children;
196 673279 : while (child) {
197 411485 : gf_node_traverse(child->node, tr_state);
198 411485 : child = child->next;
199 : }
200 :
201 : }
202 :
203 358770 : if (sensor_backup) {
204 : /*restore previous traversing state sensors */
205 60648 : tr_state->vrml_sensors = sensor_backup;
206 : }
207 : }
208 :
209 : /*This is the routine for OrderedGroup child traversing*/
210 34 : void group_2d_traverse_with_order(GF_Node *node, GroupingNode2D *group, GF_TraverseState *tr_state, u32 *positions)
211 : {
212 : u32 i, count;
213 : Bool backup;
214 : GF_List *sensor_backup;
215 : GF_Node *child;
216 : GF_ChildNodeItem *list;
217 : #ifdef GF_SR_USE_VIDEO_CACHE
218 : Bool group_cached;
219 : #endif
220 :
221 34 : backup = gf_node_dirty_get(node);
222 34 : if (backup & GF_SG_CHILD_DIRTY) {
223 : GF_SensorHandler *hsens;
224 : Bool check_anchor=0;
225 : /*never trigger bounds recompute in 2D since we don't cull 2D groups*/
226 1 : u32 ntag = gf_node_get_tag(node);
227 1 : group->flags &= ~GROUP_HAS_SENSORS;
228 1 : drawable_reset_group_highlight(tr_state, node);
229 : /*special case for anchor which is a parent node acting as a sensor*/
230 1 : if (ntag==TAG_MPEG4_Anchor) check_anchor=1;
231 : #ifndef GPAC_DISABLE_X3D
232 1 : else if (ntag==TAG_X3D_Anchor) check_anchor=1;
233 : #endif
234 : if (check_anchor) {
235 : GF_SensorHandler *gf_sc_anchor_get_handler(GF_Node *n);
236 :
237 0 : hsens = gf_sc_anchor_get_handler(node);
238 0 : if (hsens) {
239 0 : if (!group->sensors) group->sensors = gf_list_new();
240 0 : gf_list_add(group->sensors, hsens);
241 0 : group->flags |= GROUP_HAS_SENSORS | GROUP_IS_ANCHOR;
242 : }
243 : } else {
244 1 : list = ((GF_ParentNode *)node)->children;
245 5 : while (list) {
246 3 : hsens = compositor_mpeg4_get_sensor_handler_ex(list->node, GF_TRUE);
247 3 : if (hsens) {
248 1 : if (!group->sensors) group->sensors = gf_list_new();
249 1 : gf_list_add(group->sensors, hsens);
250 1 : group->flags |= GROUP_HAS_SENSORS;
251 : }
252 3 : list = list->next;
253 : }
254 : }
255 : }
256 : /*not parent (eg form, layout...) sub-tree not dirty and getting bounds, direct copy */
257 33 : else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
258 0 : tr_state->bounds = group->bounds;
259 0 : return;
260 : }
261 :
262 : #ifdef GF_SR_USE_VIDEO_CACHE
263 : group_cached = group_2d_cache_traverse(node, group, tr_state);
264 : #endif
265 :
266 : /*now here is the trick: ExternProtos may not be loaded at this point, in which case we can't
267 : perform proper culling. Unloaded ExternProto signal themselves by invalidating their parent
268 : graph to get a new traversal. We must therefore reset the CHILD_DIRTY flag before computing
269 : bounds otherwise we'll never re-invalidate the subgraph anymore*/
270 34 : gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
271 :
272 :
273 : #ifdef GF_SR_USE_VIDEO_CACHE
274 : if (group_cached) return;
275 : #endif
276 :
277 : /*picking: collect sensors*/
278 : sensor_backup = NULL;
279 34 : if ((tr_state->traversing_mode==TRAVERSE_PICK) && (group->flags & GROUP_HAS_SENSORS) ) {
280 : /*reset sensor stack if any sensors at this level*/
281 28 : sensor_backup = tr_state->vrml_sensors;
282 28 : tr_state->vrml_sensors = group->sensors;
283 : }
284 :
285 34 : if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
286 0 : list = ((GF_ParentNode *)node)->children;
287 0 : backup = tr_state->text_split_mode;
288 0 : if (tr_state->text_split_mode && (gf_node_list_get_count(list)>1) ) tr_state->text_split_mode = 0;
289 0 : group->flags &= ~GROUP_SKIP_CULLING;
290 0 : group->bounds.width = group->bounds.height = 0;
291 0 : tr_state->bounds.width = tr_state->bounds.height = 0;
292 : #ifndef GPAC_DISABLE_3D
293 0 : tr_state->bbox.is_set = 0;
294 : #endif
295 0 : count = gf_node_list_get_count(list);
296 0 : for (i=0; i<count; i++) {
297 0 : child = gf_node_list_get_child(list, positions[i]);
298 0 : gf_node_traverse(child, tr_state);
299 0 : if (tr_state->disable_cull) {
300 0 : group->flags |= GROUP_SKIP_CULLING;
301 0 : tr_state->disable_cull = 0;
302 : }
303 : /*handle 3D nodes in 2D groups*/
304 : #ifndef GPAC_DISABLE_3D
305 0 : if (tr_state->bbox.is_set) {
306 0 : gf_rect_from_bbox(&tr_state->bounds, &tr_state->bbox);
307 0 : tr_state->bbox.is_set = 0;
308 : }
309 : #endif
310 0 : gf_rect_union(&group->bounds, &tr_state->bounds);
311 0 : tr_state->bounds.width = tr_state->bounds.height = 0;
312 : }
313 0 : tr_state->bounds = group->bounds;
314 :
315 0 : if (group->flags & GROUP_SKIP_CULLING)
316 0 : tr_state->disable_cull = 1;
317 0 : tr_state->text_split_mode = backup;
318 :
319 : /*TRAVERSE_SORT */
320 34 : } else if (tr_state->traversing_mode==TRAVERSE_SORT) {
321 6 : Bool prev_inv = tr_state->invalidate_all;
322 : #ifdef GF_SR_USE_VIDEO_CACHE
323 : DrawableContext *first_ctx = tr_state->visual->cur_context;
324 : u32 cache_too_small = 0;
325 : Bool skip_first_ctx = (first_ctx && first_ctx->drawable) ? 1 : 0;
326 : u32 traverse_time = gf_sys_clock();
327 : u32 last_cache_idx = gf_list_count(tr_state->visual->compositor->cached_groups_queue);
328 : tr_state->cache_too_small = 0;
329 : #endif
330 :
331 6 : if (backup & GF_SG_VRML_COLOR_DIRTY) {
332 0 : tr_state->invalidate_all = 1;
333 0 : gf_node_dirty_clear(node, GF_SG_VRML_COLOR_DIRTY);
334 : }
335 :
336 6 : list = ((GF_ParentNode *)node)->children;
337 6 : count = gf_node_list_get_count(list);
338 24 : for (i=0; i<count; i++) {
339 18 : child = gf_node_list_get_child(list, positions[i]);
340 18 : gf_node_traverse(child, tr_state);
341 : #ifdef GF_SR_USE_VIDEO_CACHE
342 : if (tr_state->cache_too_small)
343 : cache_too_small++;
344 : #endif
345 : }
346 6 : tr_state->invalidate_all = prev_inv;
347 :
348 : #ifdef GF_SR_USE_VIDEO_CACHE
349 : if (cache_too_small) {
350 : tr_state->cache_too_small = 1;
351 : } else {
352 : /*get the traversal time for each group*/
353 : traverse_time = gf_sys_clock() - traverse_time;
354 : group->traverse_time += traverse_time;
355 : /*record the traversal information and turn cache on if possible*/
356 : group_2d_cache_evaluate(node, group, tr_state, first_ctx, skip_first_ctx, last_cache_idx);
357 : }
358 : #endif
359 :
360 6 : drawable_check_focus_highlight(node, tr_state, NULL);
361 : } else {
362 28 : list = ((GF_ParentNode *)node)->children;
363 28 : count = gf_node_list_get_count(list);
364 112 : for (i=0; i<count; i++) {
365 84 : child = gf_node_list_get_child(list, positions[i]);
366 84 : gf_node_traverse(child, tr_state);
367 : }
368 : }
369 :
370 34 : if (sensor_backup) {
371 : /*restore previous traversing state sensors*/
372 28 : tr_state->vrml_sensors = sensor_backup;
373 : }
374 : }
375 :
376 : /*
377 : * 3D Grouping tools
378 : */
379 :
380 : #ifndef GPAC_DISABLE_3D
381 :
382 146 : void group_3d_delete(GF_Node *node)
383 : {
384 146 : GroupingNode *group = (GroupingNode *)gf_node_get_private(node);
385 :
386 146 : gf_free(group);
387 146 : }
388 :
389 144 : GroupingNode *group_3d_new(GF_Node *node)
390 : {
391 : GroupingNode *st;
392 144 : GF_SAFEALLOC(st, GroupingNode);
393 144 : gf_node_set_private(node, st);
394 144 : return st;
395 : }
396 :
397 : /*returns 2 if local light, 1 if global light and 0 if not a light*/
398 56029 : static u32 get_light_type(GF_Node *n)
399 : {
400 56029 : switch (gf_node_get_tag(n)) {
401 : case TAG_MPEG4_DirectionalLight:
402 : #ifndef GPAC_DISABLE_X3D
403 : case TAG_X3D_DirectionalLight:
404 : #endif
405 : return 2;
406 906 : case TAG_MPEG4_PointLight:
407 : case TAG_MPEG4_SpotLight:
408 906 : return 1;
409 51536 : default:
410 51536 : return 0;
411 : }
412 : }
413 : /*This is the generic routine for child traversing*/
414 87673 : void group_3d_traverse(GF_Node *node, GroupingNode *group, GF_TraverseState *tr_state)
415 : {
416 : u32 mode_back;
417 : Bool split_text_backup, do_lights;
418 : DirectionalLightContext *dl;
419 : GF_List *sensor_backup;
420 : GF_SensorHandler *hsens;
421 : GF_ChildNodeItem *l;
422 :
423 87673 : if (gf_node_dirty_get(node) & GF_SG_CHILD_DIRTY) {
424 : //we are drawing 3D object but configured for 2D, force 3D
425 16898 : if (!tr_state->visual->type_3d && tr_state->visual->compositor->hybrid_opengl) {
426 24 : tr_state->visual->compositor->root_visual_setup=0;
427 24 : tr_state->visual->compositor->force_type_3d=1;
428 : }
429 :
430 : /*need to recompute bounds*/
431 16898 : if (tr_state->traversing_mode!=TRAVERSE_GET_BOUNDS) {
432 : /*traverse subtree to recompute bounds*/
433 : mode_back = tr_state->traversing_mode;
434 5437 : tr_state->traversing_mode=TRAVERSE_GET_BOUNDS;
435 5437 : group_3d_traverse(node, group, tr_state);
436 5437 : tr_state->traversing_mode = mode_back;
437 : }
438 : /*we're recomputing bounds*/
439 : else {
440 11461 : u32 ntag = gf_node_get_tag(node);
441 11461 : group->flags &= ~(GROUP_HAS_SENSORS | GROUP_HAS_LIGHTS);
442 :
443 : /*special case for anchor which is a parent node acting as a sensor*/
444 22922 : if ((ntag==TAG_MPEG4_Anchor)
445 : #ifndef GPAC_DISABLE_X3D
446 11461 : || (ntag==TAG_X3D_Anchor)
447 : #endif
448 0 : ) group->flags |= GROUP_HAS_SENSORS;
449 :
450 11461 : l = ((GF_ParentNode*)node)->children;
451 66212 : while (l) {
452 43290 : hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
453 43290 : if (hsens) {
454 652 : group->flags |= GROUP_HAS_SENSORS;
455 : }
456 42638 : else if (get_light_type(l->node)) {
457 1058 : group->flags |= GROUP_HAS_LIGHTS;
458 : }
459 43290 : l = l->next;
460 : }
461 :
462 : /*now here is the trick: ExternProtos may not be loaded at this point, in which case we can't
463 : perform proper culling. Unloaded ExternProto signal themselves by invalidating their parent
464 : graph to get a new traversal. We must therefore reset the CHILD_DIRTY flag before computing
465 : bounds otherwise we'll never re-invalidate the subgraph anymore*/
466 11461 : gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
467 : }
468 : }
469 : /*not parent (eg form, layout...) sub-tree not dirty and getting bounds, direct copy */
470 70775 : else if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
471 8022 : tr_state->bbox = group->bbox;
472 8022 : if (!tr_state->bbox.is_set) tr_state->bbox.radius=-FIX_ONE;
473 8022 : gf_node_dirty_clear(node, 0);
474 8022 : return;
475 : }
476 :
477 79651 : gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
478 :
479 79651 : mode_back=tr_state->cull_flag;
480 : /*if culling not disabled*/
481 79651 : if (!(group->flags & GROUP_SKIP_CULLING)
482 : /*for geometry AND lights*/
483 76626 : && (tr_state->traversing_mode==TRAVERSE_SORT)
484 : /*do cull*/
485 29113 : && !visual_3d_node_cull(tr_state, &group->bbox, 0)) {
486 :
487 698 : tr_state->cull_flag = mode_back;
488 698 : return;
489 : }
490 :
491 :
492 : /*picking: collect sensors*/
493 : sensor_backup = NULL;
494 78953 : if ((tr_state->traversing_mode==TRAVERSE_PICK) && (group->flags & GROUP_HAS_SENSORS) ) {
495 : /*reset sensor stack if any sensors at this level*/
496 834 : sensor_backup = tr_state->vrml_sensors;
497 834 : tr_state->vrml_sensors = gf_list_new();
498 :
499 834 : l = ((GF_ParentNode*)node)->children;
500 3902 : while (l) {
501 2234 : hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
502 2234 : if (hsens && hsens->IsEnabled(l->node))
503 834 : gf_list_add(tr_state->vrml_sensors, hsens);
504 :
505 2234 : l = l->next;
506 : }
507 : }
508 :
509 : /*turn on local lights and global ones*/
510 : do_lights = 0;
511 78953 : if (group->flags & GROUP_HAS_LIGHTS) {
512 : /*turn on global lights*/
513 4659 : if (tr_state->traversing_mode==TRAVERSE_LIGHTING) {
514 1646 : l = ((GF_ParentNode*)node)->children;
515 9773 : while (l) {
516 6481 : if (get_light_type(l->node)==2) gf_node_traverse(l->node, tr_state);
517 6481 : l = l->next;
518 : }
519 : }
520 : /*turn on local lights*/
521 3013 : else if (tr_state->traversing_mode==TRAVERSE_SORT) {
522 : do_lights = 1;
523 1789 : tr_state->traversing_mode = TRAVERSE_DRAW_3D;
524 1789 : tr_state->local_light_on = 1;
525 :
526 1789 : l = ((GF_ParentNode*)node)->children;
527 10488 : while (l) {
528 6910 : if (get_light_type(l->node)==1) {
529 : /*store lights for alpha draw*/
530 302 : dl = (DirectionalLightContext*)gf_malloc(sizeof(DirectionalLightContext));
531 302 : dl->dlight = l->node;
532 302 : memcpy(&dl->light_matrix, &tr_state->model_matrix, sizeof(GF_Matrix));
533 302 : gf_list_add(tr_state->local_lights, dl);
534 : /*and turn them on for non-alpha draw*/
535 302 : gf_node_traverse(dl->dlight, tr_state);
536 : }
537 6910 : l = l->next;
538 : }
539 1789 : tr_state->traversing_mode = TRAVERSE_SORT;
540 : }
541 : }
542 :
543 :
544 78953 : if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
545 11461 : l = ((GF_ParentNode*)node)->children;
546 11461 : split_text_backup = tr_state->text_split_mode;
547 11461 : if (tr_state->text_split_mode && (gf_node_list_get_count(l)>1) ) tr_state->text_split_mode = 0;
548 11461 : group->bbox.is_set = tr_state->bbox.is_set = 0;
549 11461 : tr_state->bounds.width = 0;
550 11461 : group->flags &= ~GROUP_SKIP_CULLING;
551 :
552 66212 : while (l) {
553 43290 : gf_node_traverse(l->node, tr_state);
554 43290 : if (tr_state->disable_cull) {
555 1050 : group->flags |= GROUP_SKIP_CULLING;
556 1050 : tr_state->disable_cull = 0;
557 : }
558 : /*handle 2D nodes in 3D groups*/
559 43290 : if (tr_state->bounds.width) {
560 585 : gf_bbox_from_rect(&tr_state->bbox, &tr_state->bounds);
561 585 : tr_state->bounds.width = 0;
562 : }
563 :
564 43290 : if (tr_state->bbox.is_set) {
565 16716 : gf_bbox_union(&group->bbox, &tr_state->bbox);
566 : }
567 43290 : tr_state->bbox.is_set = 0;
568 43290 : l = l->next;
569 : }
570 11461 : tr_state->bbox = group->bbox;
571 11461 : if (group->flags & GROUP_SKIP_CULLING)
572 702 : tr_state->disable_cull = 1;
573 11461 : tr_state->text_split_mode = split_text_backup;
574 : } else {
575 67492 : l = ((GF_ParentNode*)node)->children;
576 309613 : while (l) {
577 174629 : gf_node_traverse(l->node, tr_state);
578 174629 : l = l->next;
579 : }
580 :
581 67492 : if (tr_state->traversing_mode==TRAVERSE_SORT)
582 30053 : drawable3d_check_focus_highlight(node, tr_state, NULL);
583 : }
584 78953 : tr_state->cull_flag = mode_back;
585 :
586 78953 : if (sensor_backup) {
587 : /*destroy current traversing state sensors and restore previous*/
588 834 : gf_list_del(tr_state->vrml_sensors);
589 834 : tr_state->vrml_sensors = sensor_backup;
590 : }
591 :
592 : /*remove dlights*/
593 78953 : if (do_lights) {
594 : u32 lcount;
595 1789 : tr_state->traversing_mode = TRAVERSE_DRAW_3D;
596 1789 : tr_state->local_light_on = 0;
597 3880 : while ( (lcount = gf_list_count(tr_state->local_lights)) ) {
598 302 : dl = (DirectionalLightContext*)gf_list_get(tr_state->local_lights, lcount-1);
599 302 : gf_list_rem(tr_state->local_lights, lcount-1);
600 302 : gf_node_traverse(dl->dlight, tr_state);
601 302 : gf_free(dl);
602 : }
603 : /*and back to sort mode*/
604 1789 : tr_state->traversing_mode = TRAVERSE_SORT;
605 : }
606 : }
607 :
608 :
609 : #endif
610 :
611 :
612 : /*
613 : * 2D ParentNode tools - used by all nodes performing children layout
614 : */
615 :
616 :
617 226 : void parent_node_setup(ParentNode2D *group)
618 : {
619 226 : group->groups = gf_list_new();
620 226 : }
621 :
622 226 : void parent_node_predestroy(ParentNode2D *group)
623 : {
624 : /*just in case*/
625 226 : parent_node_reset(group);
626 226 : gf_list_del(group->groups);
627 226 : }
628 :
629 819 : void parent_node_reset(ParentNode2D *group)
630 : {
631 7713 : while (gf_list_count(group->groups)) {
632 6075 : ChildGroup *cg = (ChildGroup *)gf_list_get(group->groups, 0);
633 6075 : gf_list_rem(group->groups, 0);
634 6075 : gf_free(cg);
635 : }
636 819 : }
637 :
638 6075 : void parent_node_start_group(ParentNode2D *group, GF_Node *n, Bool discardable)
639 : {
640 : ChildGroup *cg;
641 6075 : if (!n) {
642 3347 : cg = gf_list_last(group->groups);
643 3347 : if (!cg) return;
644 3347 : n = cg->child;
645 : }
646 6075 : GF_SAFEALLOC(cg, ChildGroup);
647 6075 : if (!cg) {
648 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate child group\n"));
649 : return;
650 : }
651 6075 : cg->child = n;
652 6075 : cg->text_type = discardable;
653 6075 : gf_list_add(group->groups, cg);
654 : }
655 :
656 2728 : void parent_node_end_group(ParentNode2D *group, GF_Rect *bounds)
657 : {
658 2728 : ChildGroup *cg = (ChildGroup *)gf_list_last(group->groups);
659 2728 : if (!cg) return;
660 : /*don't override splitted text info*/
661 2728 : if (cg->ascent || cg->descent) return;
662 2221 : cg->original = *bounds;
663 2221 : cg->final = cg->original;
664 : }
665 :
666 3854 : void parent_node_end_text_group(ParentNode2D *group, GF_Rect *bounds, Fixed ascent, Fixed descent, u32 text_split_idx)
667 : {
668 3854 : ChildGroup *cg = (ChildGroup *)gf_list_last(group->groups);
669 3854 : if (!cg) return;
670 3854 : cg->text_split_idx = text_split_idx;
671 3854 : cg->ascent = ascent;
672 3854 : cg->descent = descent;
673 3854 : cg->final = cg->original = *bounds;
674 : }
675 :
676 :
677 :
678 587 : void parent_node_traverse(GF_Node *node, ParentNode2D *group, GF_TraverseState *tr_state)
679 : {
680 : Bool split_text_backup;
681 : GF_List *sensor_backup;
682 : GF_ChildNodeItem *l;
683 :
684 587 : if (gf_node_dirty_get(node) & GF_SG_CHILD_DIRTY) {
685 : Bool check_anchor=0;
686 : /*parent groups must recompute their bounds themselves since they modify children layout*/
687 242 : u32 ntag = gf_node_get_tag(node);
688 242 : group->flags &= ~GROUP_HAS_SENSORS;
689 : /*special case for anchor which is a parent node acting as a sensor*/
690 242 : if (ntag==TAG_MPEG4_Anchor) check_anchor=1;
691 : #ifndef GPAC_DISABLE_X3D
692 242 : else if (ntag==TAG_X3D_Anchor) check_anchor=1;
693 : #endif
694 : if (check_anchor) {
695 0 : group->flags |= GROUP_HAS_SENSORS | GROUP_IS_ANCHOR;
696 : } else {
697 242 : l = ((GF_ParentNode *)node)->children;
698 1838 : while (l) {
699 1355 : GF_SensorHandler *hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
700 1355 : if (hsens) {
701 1 : group->flags |= GROUP_HAS_SENSORS;
702 1 : break;
703 : }
704 1354 : l = l->next;
705 : }
706 : }
707 :
708 : /*now here is the trick: ExternProtos may not be loaded at this point, in which case we can't
709 : perform proper culling. Unloaded ExternProto signal themselves by invalidating their parent
710 : graph to get a new traversal. We must therefore reset the CHILD_DIRTY flag before computing
711 : bounds otherwise we'll never re-invalidate the subgraph anymore*/
712 242 : gf_node_dirty_clear(node, GF_SG_CHILD_DIRTY);
713 : }
714 587 : gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
715 :
716 : /*no culling in 2D*/
717 :
718 : /*picking: collect sensors*/
719 : sensor_backup = NULL;
720 587 : if ((tr_state->traversing_mode==TRAVERSE_PICK) && (group->flags & GROUP_HAS_SENSORS) ) {
721 : /*reset sensor stack if any sensors at this level*/
722 0 : sensor_backup = tr_state->vrml_sensors;
723 0 : tr_state->vrml_sensors = gf_list_new();
724 :
725 :
726 : /*add sensor(s) to traversing state*/
727 0 : l = ((GF_ParentNode *)node)->children;
728 0 : while (l) {
729 0 : GF_SensorHandler *hsens = compositor_mpeg4_get_sensor_handler_ex(l->node, GF_TRUE);
730 0 : if (hsens) gf_list_add(tr_state->vrml_sensors, hsens);
731 0 : l = l->next;
732 : }
733 : }
734 :
735 :
736 587 : split_text_backup = tr_state->text_split_mode;
737 :
738 587 : group->flags &= ~GROUP_SKIP_CULLING;
739 587 : tr_state->bounds.width = tr_state->bounds.height = 0;
740 : #ifndef GPAC_DISABLE_3D
741 587 : tr_state->bbox.is_set = 0;
742 : #endif
743 :
744 587 : l = ((GF_ParentNode *)node)->children;
745 3902 : while (l) {
746 2728 : parent_node_start_group(group, l->node, 0);
747 :
748 2728 : tr_state->bounds.width = tr_state->bounds.height = 0;
749 :
750 2728 : gf_node_traverse(l->node, tr_state);
751 :
752 : /*handle 3D nodes in 2D groups*/
753 : #ifndef GPAC_DISABLE_3D
754 2728 : if (tr_state->bbox.is_set) {
755 0 : gf_rect_from_bbox(&tr_state->bounds, &tr_state->bbox);
756 0 : tr_state->bbox.is_set = 0;
757 : }
758 : #endif
759 2728 : parent_node_end_group(group, &tr_state->bounds);
760 2728 : l = l->next;
761 : }
762 587 : tr_state->text_split_mode = split_text_backup;
763 :
764 587 : if (sensor_backup) {
765 : /*destroy current traversing state sensors and restore previous*/
766 0 : gf_list_del(tr_state->vrml_sensors);
767 0 : tr_state->vrml_sensors = sensor_backup;
768 : }
769 587 : }
770 :
771 : /*final drawing of each group*/
772 11002 : void parent_node_child_traverse(ChildGroup *cg, GF_TraverseState *tr_state)
773 : {
774 : Fixed dx, dy;
775 :
776 11002 : dx = cg->final.x - cg->original.x + cg->scroll_x;
777 11002 : dy = cg->final.y - cg->original.y + cg->scroll_y;
778 11002 : tr_state->text_split_idx = cg->text_split_idx;
779 :
780 : #ifndef GPAC_DISABLE_3D
781 11002 : if (tr_state->visual->type_3d) {
782 : GF_Matrix mx_bckup;
783 :
784 80 : gf_mx_copy(mx_bckup, tr_state->model_matrix);
785 80 : gf_mx_add_translation(&tr_state->model_matrix, dx, dy, 0);
786 80 : gf_node_traverse(cg->child, tr_state);
787 : gf_mx_copy(tr_state->model_matrix, mx_bckup);
788 : } else
789 : #endif
790 : {
791 : GF_Matrix2D mx2d;
792 10922 : gf_mx2d_copy(mx2d, tr_state->transform);
793 10922 : gf_mx2d_init(tr_state->transform);
794 10922 : gf_mx2d_add_translation(&tr_state->transform, dx, dy);
795 10922 : gf_mx2d_add_matrix(&tr_state->transform, &mx2d);
796 10922 : gf_node_traverse(cg->child, tr_state);
797 : gf_mx2d_copy(tr_state->transform, mx2d);
798 : }
799 11002 : tr_state->text_split_idx = 0;
800 11002 : }
801 :
802 4500 : void parent_node_child_traverse_matrix(ChildGroup *cg, GF_TraverseState *tr_state, GF_Matrix2D *mat2D)
803 : {
804 4500 : if (!mat2D) return;
805 :
806 3406 : tr_state->text_split_idx = cg->text_split_idx;
807 : #ifndef GPAC_DISABLE_3D
808 3406 : if (tr_state->visual->type_3d) {
809 : GF_Matrix mx, mx_bckup;
810 0 : gf_mx_from_mx2d(&mx, mat2D);
811 0 : gf_mx_copy(mx_bckup, tr_state->model_matrix);
812 0 : gf_mx_add_matrix(&tr_state->model_matrix, &mx);
813 0 : gf_node_traverse(cg->child, tr_state);
814 : gf_mx_copy(tr_state->model_matrix, mx_bckup);
815 : } else
816 : #endif
817 : {
818 : GF_Matrix2D mx2d;
819 :
820 3406 : gf_mx2d_copy(mx2d, tr_state->transform);
821 3406 : gf_mx2d_pre_multiply(&tr_state->transform, mat2D);
822 3406 : gf_node_traverse(cg->child, tr_state);
823 : gf_mx2d_copy(tr_state->transform, mx2d);
824 : }
825 3406 : tr_state->text_split_idx = 0;
826 : }
827 :
828 : #endif /*GPAC_DISABLE_VRML*/
|