LCOV - code coverage report
Current view: top level - compositor - mpeg4_grouping.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 315 367 85.8 %
Date: 2021-04-29 23:48:07 Functions: 15 15 100.0 %

          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*/

Generated by: LCOV version 1.13