LCOV - code coverage report
Current view: top level - compositor - mpeg4_grouping_2d.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 171 185 92.4 %
Date: 2021-04-29 23:48:07 Functions: 13 13 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             : #include "nodes_stacks.h"
      27             : #include "mpeg4_grouping.h"
      28             : #include "visual_manager.h"
      29             : 
      30             : #ifndef GPAC_DISABLE_VRML
      31             : 
      32             : typedef struct
      33             : {
      34             :         s32 last_switch;
      35             : } SwitchStack;
      36             : 
      37       28748 : static void TraverseSwitch(GF_Node *node, void *rs, Bool is_destroy)
      38             : {
      39             :         GF_ChildNodeItem *l;
      40             :         u32 i;
      41             :         Bool prev_switch;
      42             :         GF_ChildNodeItem *children;
      43             :         s32 whichChoice;
      44             :         GF_Node *child;
      45       28748 :         SwitchStack *st = (SwitchStack *)gf_node_get_private(node);
      46             :         GF_TraverseState *tr_state;
      47             :         tr_state = (GF_TraverseState *)rs;
      48             :         children = NULL;
      49             : 
      50             :         whichChoice = -1;
      51       28748 :         if (is_destroy) {
      52         431 :                 gf_sc_check_focus_upon_destroy(node);
      53         431 :                 gf_free(st);
      54         431 :                 return;
      55             :         }
      56             :         /*WARNING: X3D/MPEG4 NOT COMPATIBLE*/
      57       28317 :         switch (gf_node_get_tag(node)) {
      58       28317 :         case TAG_MPEG4_Switch:
      59       28317 :                 children = ((M_Switch *)node)->choice;
      60       28317 :                 whichChoice = ((M_Switch *)node)->whichChoice;
      61       28317 :                 break;
      62             : #ifndef GPAC_DISABLE_X3D
      63           0 :         case TAG_X3D_Switch:
      64           0 :                 children = ((X_Switch *)node)->children;
      65           0 :                 whichChoice = ((X_Switch *)node)->whichChoice;
      66           0 :                 break;
      67             : #endif
      68             :         }
      69             : 
      70       28317 :         if (tr_state->traversing_mode!=TRAVERSE_GET_BOUNDS) {
      71       28272 :                 prev_switch = tr_state->switched_off;
      72             :                 /*check changes in choice field*/
      73       28272 :                 if ((gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) || (st->last_switch != whichChoice) ) {
      74         739 :                         tr_state->switched_off = 1;
      75             :                         i=0;
      76             :                         l = children;
      77        4427 :                         while (l) {
      78             :                                 //                      if ((s32) i!=whichChoice) gf_node_traverse(l->node, tr_state);
      79        2949 :                                 if ((s32) i == st->last_switch) gf_node_traverse(l->node, tr_state);
      80        2949 :                                 l = l->next;
      81        2949 :                                 i++;
      82             :                         }
      83         739 :                         tr_state->switched_off = 0;
      84         739 :                         st->last_switch = whichChoice;
      85             :                 }
      86             : 
      87       28272 :                 gf_node_dirty_clear(node, 0);
      88             : 
      89             :                 /*no need to check for sensors since a sensor is active for the whole parent group, that is for switch itself
      90             :                 CSQ: switch cannot be used to switch sensors, too bad...*/
      91       28272 :                 tr_state->switched_off = prev_switch;
      92             :         }
      93             : 
      94       28317 :         if (!children) return;
      95       28175 :         if (whichChoice==-2) {
      96             : #ifndef GPAC_DISABLE_3D
      97           0 :                 if (tr_state->visual->autostereo_type) {
      98             :                         u32 idx;
      99           0 :                         u32 count = gf_node_list_get_count(children);
     100             :                         /*this should be a bit more subtle (reusing views if missing, ...)...*/
     101           0 :                         idx = tr_state->visual->current_view % count;
     102             : 
     103           0 :                         child = (GF_Node*)gf_node_list_get_child(children, idx);
     104           0 :                         gf_node_traverse(child, tr_state);
     105           0 :                         return;
     106             :                 } else
     107             : #endif //GPAC_DISABLE_3D
     108             :                 {
     109             :                         /*fallback to first view*/
     110             :                         whichChoice=0;
     111             :                 }
     112             :         }
     113       28175 :         if (whichChoice>=0) {
     114       26902 :                 child = (GF_Node*)gf_node_list_get_child(children, whichChoice);
     115       26902 :                 gf_node_traverse(child, tr_state);
     116             :         }
     117             : }
     118             : 
     119         431 : void compositor_init_switch(GF_Compositor *compositor, GF_Node *node)
     120             : {
     121         431 :         SwitchStack *st = (SwitchStack *)gf_malloc(sizeof(SwitchStack));
     122         431 :         st->last_switch = -1;
     123         431 :         gf_node_set_private(node, st);
     124         431 :         gf_node_set_callback_function(node, TraverseSwitch);
     125         431 : }
     126             : 
     127             : 
     128             : /*transform2D*/
     129             : typedef struct
     130             : {
     131             :         GROUPING_MPEG4_STACK_2D
     132             :         GF_Matrix2D mat;
     133             :         u8 is_identity;
     134             :         u8 is_null;
     135             : } Transform2DStack;
     136             : 
     137      301981 : static void traverse_transform(GF_Node *node, Transform2DStack *stack, GF_TraverseState *tr_state)
     138             : {
     139      301981 :         if (stack->is_null) return;
     140             : 
     141             :         /*note we don't clear dirty flag, this is done in traversing*/
     142      299995 :         if (stack->is_identity) {
     143      111123 :                 group_2d_traverse(node, (GroupingNode2D *)stack, tr_state);
     144             :         }
     145             : #ifndef GPAC_DISABLE_3D
     146      188872 :         else if (tr_state->visual->type_3d) {
     147             :                 GF_Matrix mx_bckup;
     148        5005 :                 gf_mx_copy(mx_bckup, tr_state->model_matrix);
     149             : 
     150        5005 :                 gf_mx_add_matrix_2d(&tr_state->model_matrix, &stack->mat);
     151        5005 :                 group_2d_traverse(node, (GroupingNode2D *)stack, tr_state);
     152             :                 gf_mx_copy(tr_state->model_matrix, mx_bckup);
     153             :         }
     154             : #endif
     155             :         else {
     156             :                 GF_Matrix2D bckup;
     157      183867 :                 gf_mx2d_copy(bckup, tr_state->transform);
     158      183867 :                 gf_mx2d_pre_multiply(&tr_state->transform, &stack->mat);
     159             : 
     160      183867 :                 group_2d_traverse(node, (GroupingNode2D *)stack, tr_state);
     161             : 
     162             :                 gf_mx2d_copy(tr_state->transform, bckup);
     163             :         }
     164             : 
     165      299995 :         if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) {
     166        1563 :                 gf_mx2d_apply_rect(&stack->mat, &tr_state->bounds);
     167             :         }
     168             : }
     169             : 
     170             : 
     171      296364 : static void TraverseTransform2D(GF_Node *node, void *rs, Bool is_destroy)
     172             : {
     173             :         M_Transform2D *tr = (M_Transform2D *)node;
     174      296364 :         Transform2DStack *ptr = (Transform2DStack *)gf_node_get_private(node);
     175             :         GF_TraverseState *tr_state;
     176             : 
     177      296364 :         if (is_destroy) {
     178        4753 :                 gf_sc_check_focus_upon_destroy(node);
     179        4753 :                 group_2d_destroy(node, (GroupingNode2D*)ptr);
     180        4753 :                 gf_free(ptr);
     181        4753 :                 return;
     182             :         }
     183             : 
     184             :         tr_state = (GF_TraverseState *) rs;
     185             : 
     186      291611 :         if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
     187       19738 :                 gf_mx2d_init(ptr->mat);
     188        9869 :                 ptr->is_identity = 1;
     189        9869 :                 if ((tr->scale.x != FIX_ONE) || (tr->scale.y != FIX_ONE)) {
     190        2540 :                         gf_mx2d_add_scale_at(&ptr->mat, tr->scale.x, tr->scale.y, 0, 0, tr->scaleOrientation);
     191        2540 :                         ptr->is_identity = 0;
     192             :                 }
     193        9869 :                 if (tr->rotationAngle) {
     194         886 :                         gf_mx2d_add_rotation(&ptr->mat, tr->center.x, tr->center.y, tr->rotationAngle);
     195         886 :                         ptr->is_identity = 0;
     196             :                 }
     197        9869 :                 if (tr->translation.x || tr->translation.y) {
     198        7001 :                         ptr->is_identity = 0;
     199        7001 :                         gf_mx2d_add_translation(&ptr->mat, tr->translation.x, tr->translation.y);
     200             :                 }
     201        9869 :                 gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
     202        9869 :                 ptr->is_null = (!tr->scale.x || !tr->scale.y) ? 1 : 0;
     203             :         }
     204      291611 :         traverse_transform(node, ptr, tr_state);
     205             : }
     206             : 
     207        4753 : void compositor_init_transform2d(GF_Compositor *compositor, GF_Node *node)
     208             : {
     209             :         Transform2DStack *stack;
     210        4753 :         GF_SAFEALLOC(stack, Transform2DStack);
     211        4753 :         if (!stack) {
     212           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate transform2d stack\n"));
     213             :                 return;
     214             :         }
     215             : 
     216        9506 :         gf_mx2d_init(stack->mat);
     217        4753 :         stack->is_identity = 1;
     218        4753 :         gf_node_set_private(node, stack);
     219        4753 :         gf_node_set_callback_function(node, TraverseTransform2D);
     220             : }
     221             : 
     222        1929 : void tr_mx2d_get_matrix(GF_Node *n, GF_Matrix2D *mat)
     223             : {
     224             :         M_TransformMatrix2D *tr = (M_TransformMatrix2D*)n;
     225        3858 :         gf_mx2d_init(*mat);
     226        1929 :         mat->m[0] = tr->mxx;
     227        1929 :         mat->m[1] = tr->mxy;
     228        1929 :         mat->m[2] = tr->tx;
     229        1929 :         mat->m[3] = tr->myx;
     230        1929 :         mat->m[4] = tr->myy;
     231        1929 :         mat->m[5] = tr->ty;
     232        1929 : }
     233             : 
     234             : 
     235             : /*TransformMatrix2D*/
     236       11239 : static void TraverseTransformMatrix2D(GF_Node *node, void *rs, Bool is_destroy)
     237             : {
     238       11239 :         Transform2DStack *ptr = (Transform2DStack *) gf_node_get_private(node);
     239             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     240             : 
     241       11239 :         if (is_destroy) {
     242         869 :                 gf_sc_check_focus_upon_destroy(node);
     243         869 :                 group_2d_destroy(node, (GroupingNode2D*)ptr);
     244         869 :                 gf_free(ptr);
     245         869 :                 return;
     246             :         }
     247             : 
     248       10370 :         if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
     249             :                 M_TransformMatrix2D *tr = (M_TransformMatrix2D*)node;
     250        1047 :                 tr_mx2d_get_matrix(node, &ptr->mat);
     251        1047 :                 if ((tr->mxx==FIX_ONE) && (tr->mxy==0) && (tr->tx==0)
     252          17 :                         && (tr->myx==0) && (tr->myy==FIX_ONE) && (tr->ty==0) )
     253          17 :                         ptr->is_identity = 1;
     254             :                 else
     255        1030 :                         ptr->is_identity = 0;
     256             : 
     257        1047 :                 ptr->is_null = ( (!ptr->mat.m[0] && !ptr->mat.m[1]) || (!ptr->mat.m[3] && !ptr->mat.m[4]) ) ? 1 : 0;
     258        1047 :                 gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
     259             :         }
     260       10370 :         traverse_transform(node, ptr, tr_state);
     261             : }
     262             : 
     263             : 
     264         869 : void compositor_init_transformmatrix2d(GF_Compositor *compositor, GF_Node *node)
     265             : {
     266             :         Transform2DStack *stack;
     267         869 :         GF_SAFEALLOC(stack, Transform2DStack);
     268         869 :         if (!stack) return;
     269             : 
     270        1738 :         gf_mx2d_init(stack->mat);
     271         869 :         gf_node_set_private(node, stack);
     272         869 :         gf_node_set_callback_function(node, TraverseTransformMatrix2D);
     273             : }
     274             : 
     275             : 
     276             : typedef struct
     277             : {
     278             :         GROUPING_MPEG4_STACK_2D
     279             :         GF_ColorMatrix cmat;
     280             : } ColorTransformStack;
     281             : 
     282             : /*ColorTransform*/
     283       24496 : static void TraverseColorTransform(GF_Node *node, void *rs, Bool is_destroy)
     284             : {
     285             :         Bool c_changed;
     286             :         M_ColorTransform *tr = (M_ColorTransform *)node;
     287       24496 :         ColorTransformStack *ptr = (ColorTransformStack  *)gf_node_get_private(node);
     288             :         GF_TraverseState *tr_state = (GF_TraverseState *) rs;
     289             :         Bool prev_inv;
     290             : 
     291       24496 :         if (is_destroy) {
     292         430 :                 gf_sc_check_focus_upon_destroy(node);
     293         430 :                 group_2d_destroy(node, (GroupingNode2D*)ptr);
     294         430 :                 gf_free(ptr);
     295         430 :                 return;
     296             :         }
     297       24066 :         if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
     298           0 :                 group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state);
     299           0 :                 return;
     300             :         }
     301             : 
     302       24066 :         prev_inv = tr_state->invalidate_all;
     303             :         c_changed = 0;
     304       24066 :         if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
     305        1048 :                 gf_cmx_set(&ptr->cmat,
     306             :                            tr->mrr , tr->mrg, tr->mrb, tr->mra, tr->tr,
     307             :                            tr->mgr , tr->mgg, tr->mgb, tr->mga, tr->tg,
     308             :                            tr->mbr, tr->mbg, tr->mbb, tr->mba, tr->tb,
     309             :                            tr->mar, tr->mag, tr->mab, tr->maa, tr->ta);
     310             :                 c_changed = 1;
     311        1048 :                 gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
     312             :         }
     313             : 
     314       24066 :         if ((tr_state->traversing_mode==TRAVERSE_SORT)
     315        5111 :                 && !tr->maa && !tr->mar && !tr->mag && !tr->mab && !tr->ta)
     316             :                 return;
     317             : 
     318             :         /*if modified redraw all nodes*/
     319       24058 :         if (c_changed) tr_state->invalidate_all = 1;
     320             : 
     321             :         /*note we don't clear dirty flag, this is done in traversing*/
     322       24058 :         if (ptr->cmat.identity) {
     323           0 :                 group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state);
     324             :         } else {
     325             :                 GF_ColorMatrix gf_cmx_bck;
     326       24058 :                 gf_cmx_copy(&gf_cmx_bck, &tr_state->color_mat);
     327       24058 :                 gf_cmx_multiply(&tr_state->color_mat, &ptr->cmat);
     328             : 
     329             : 
     330       24058 :                 group_2d_traverse(node, (GroupingNode2D *) ptr, tr_state);
     331             :                 /*restore traversing state*/
     332       24058 :                 gf_cmx_copy(&tr_state->color_mat, &gf_cmx_bck);
     333             :         }
     334       24058 :         tr_state->invalidate_all = prev_inv;
     335             : }
     336             : 
     337         430 : void compositor_init_colortransform(GF_Compositor *compositor, GF_Node *node)
     338             : {
     339             :         ColorTransformStack *stack;
     340         430 :         GF_SAFEALLOC(stack, ColorTransformStack);
     341         430 :         if (!stack) return;
     342             : 
     343         430 :         gf_cmx_init(&stack->cmat);
     344         430 :         gf_node_set_private(node, stack);
     345         430 :         gf_node_set_callback_function(node, TraverseColorTransform);
     346             : }
     347             : 
     348             : 
     349             : struct og_pos
     350             : {
     351             :         Fixed priority;
     352             :         u32 position;
     353             : };
     354             : typedef struct
     355             : {
     356             :         GROUPING_MPEG4_STACK_2D
     357             :         u32 *positions;
     358             : } OrderedGroupStack;
     359             : 
     360             : 
     361          13 : static s32 compare_priority(const void* elem1, const void* elem2)
     362             : {
     363             :         struct og_pos *p1, *p2;
     364             :         p1 = (struct og_pos *)elem1;
     365             :         p2 = (struct og_pos *)elem2;
     366          13 :         if (p1->priority < p2->priority) return -1;
     367          13 :         if (p1->priority > p2->priority) return 1;
     368           5 :         return 0;
     369             : }
     370             : 
     371             : 
     372       29695 : static void TraverseOrderedGroup(GF_Node *node, void *rs, Bool is_destroy)
     373             : {
     374             :         u32 i, count;
     375             :         struct og_pos *priorities;
     376             :         Bool invalidate_backup;
     377       29695 :         OrderedGroupStack *stack = (OrderedGroupStack *) gf_node_get_private(node);
     378             :         M_OrderedGroup *og = (M_OrderedGroup *) node;
     379             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     380             : 
     381       29695 :         if (is_destroy) {
     382         672 :                 gf_sc_check_focus_upon_destroy(node);
     383         672 :                 group_2d_destroy(node, (GroupingNode2D*)stack);
     384         672 :                 if (stack->positions) gf_free(stack->positions);
     385         672 :                 gf_free(stack);
     386         672 :                 return;
     387             :         }
     388             : 
     389       29023 :         if (!og->order.count || (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) ) {
     390       28989 :                 gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
     391       28989 :                 group_2d_traverse(node, (GroupingNode2D*)stack, tr_state);
     392       28989 :                 return;
     393             :         }
     394             : 
     395          34 :         invalidate_backup = tr_state->invalidate_all;
     396             :         /*check whether the OrderedGroup node has changed*/
     397          34 :         if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
     398           5 :                 if (stack->positions) gf_free(stack->positions);
     399           5 :                 count = gf_node_list_get_count(og->children);
     400           5 :                 priorities = (struct og_pos*)gf_malloc(sizeof(struct og_pos)*count);
     401          20 :                 for (i=0; i<count; i++) {
     402          15 :                         priorities[i].position = i;
     403          15 :                         priorities[i].priority = (i<og->order.count) ? og->order.vals[i] : 0;
     404             :                 }
     405           5 :                 qsort(priorities, count, sizeof(struct og_pos), compare_priority);
     406             : 
     407           5 :                 stack->positions = (u32*)gf_malloc(sizeof(u32) * count);
     408           5 :                 for (i=0; i<count; i++) stack->positions[i] = priorities[i].position;
     409           5 :                 gf_free(priorities);
     410             : 
     411           5 :                 tr_state->invalidate_all = 1;
     412           5 :                 gf_node_dirty_clear(node, GF_SG_NODE_DIRTY);
     413             :         }
     414          34 :         group_2d_traverse_with_order(node, (GroupingNode2D*)stack, tr_state, stack->positions);
     415          34 :         tr_state->invalidate_all = invalidate_backup;
     416             : }
     417             : 
     418         672 : void compositor_init_orderedgroup(GF_Compositor *compositor, GF_Node *node)
     419             : {
     420             :         OrderedGroupStack *ptr;
     421         672 :         GF_SAFEALLOC(ptr, OrderedGroupStack);
     422         672 :         if (!ptr) return;
     423             :         
     424         672 :         gf_node_set_private(node, ptr);
     425         672 :         gf_node_set_callback_function(node, TraverseOrderedGroup);
     426             : }
     427             : 
     428             : #endif  /*GPAC_DISABLE_VRML*/
     429             : 

Generated by: LCOV version 1.13