LCOV - code coverage report
Current view: top level - compositor - mpeg4_layer_2d.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 148 172 86.0 %
Date: 2021-04-29 23:48:07 Functions: 3 3 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             : 
      28             : #include "nodes_stacks.h"
      29             : #include "mpeg4_grouping.h"
      30             : #include "visual_manager.h"
      31             : 
      32             : #ifndef GPAC_DISABLE_VRML
      33             : 
      34             : 
      35             : typedef struct
      36             : {
      37             :         GROUPING_MPEG4_STACK_2D
      38             :         GF_List *backs;
      39             :         GF_List *views;
      40             :         Bool first;
      41             :         GF_Rect clip;
      42             : } Layer2DStack;
      43             : 
      44             : 
      45             : 
      46        5371 : static void l2d_CheckBindables(GF_Node *n, GF_TraverseState *tr_state, Bool force_traverse)
      47             : {
      48             :         GF_Node *btop;
      49             :         M_Layer2D *l2d;
      50             :         l2d = (M_Layer2D *)n;
      51        5371 :         if (force_traverse) gf_node_traverse(l2d->background, tr_state);
      52        5371 :         btop = (GF_Node*)gf_list_get(tr_state->backgrounds, 0);
      53        5371 :         if (btop != l2d->background) {
      54           1 :                 gf_node_unregister(l2d->background, n);
      55           1 :                 gf_node_register(btop, n);
      56           1 :                 l2d->background = btop;
      57           1 :                 gf_node_event_out(n, 4/*"background"*/);
      58             :         }
      59        5371 :         if (force_traverse) gf_node_traverse(l2d->viewport, tr_state);
      60        5371 :         btop = (GF_Node*)gf_list_get(tr_state->viewpoints, 0);
      61        5371 :         if (btop != l2d->viewport) {
      62           0 :                 gf_node_unregister(l2d->viewport, n);
      63           0 :                 gf_node_register(btop, n);
      64           0 :                 l2d->viewport = btop;
      65           0 :                 gf_node_event_out(n, 5/*"viewport"*/);
      66             :         }
      67        5371 : }
      68             : 
      69             : 
      70             : #if VIEWPORT_CLIPS
      71             : static void rect_intersect(GF_Rect *rc1, GF_Rect *rc2)
      72             : {
      73             :         if (! gf_rect_overlaps(*rc1, *rc2)) {
      74             :                 rc1->width = rc1->height = 0;
      75             :                 return;
      76             :         }
      77             :         if (rc2->x > rc1->x) {
      78             :                 rc1->width -= rc2->x - rc1->x;
      79             :                 rc1->x = rc2->x;
      80             :         }
      81             :         if (rc2->x + rc2->width < rc1->x + rc1->width) {
      82             :                 rc1->width = rc2->width + rc2->x - rc1->x;
      83             :         }
      84             :         if (rc2->y < rc1->y) {
      85             :                 rc1->height -= rc1->y - rc2->y;
      86             :                 rc1->y = rc2->y;
      87             :         }
      88             :         if (rc2->y - rc2->height > rc1->y - rc1->height) {
      89             :                 rc1->height = rc1->y - rc2->y + rc2->height;
      90             :         }
      91             : }
      92             : #endif
      93             : 
      94        5755 : static void TraverseLayer2D(GF_Node *node, void *rs, Bool is_destroy)
      95             : {
      96             :         GF_List *oldb, *oldv;
      97             :         GF_Node *viewport;
      98             :         GF_Node *back;
      99             :         Bool prev_layer;
     100             :         GF_Matrix2D backup;
     101             :         GF_IRect prev_clip;
     102             :         GF_Rect rc;
     103             :         SFVec2f prev_vp;
     104             : 
     105             : #ifndef GPAC_DISABLE_3D
     106             :         GF_Matrix mx3d, prev_layer_mx;
     107             :         GF_List *oldf, *oldn;
     108             :         GF_List *node_list_backup;
     109             :         GF_Rect prev_clipper;
     110             :         Bool had_clip;
     111             : #endif
     112             : 
     113             :         M_Layer2D *l = (M_Layer2D *)node;
     114        5755 :         Layer2DStack *st = (Layer2DStack *) gf_node_get_private(node);
     115             :         GF_TraverseState *tr_state = (GF_TraverseState *) rs;
     116             : 
     117        5755 :         if (is_destroy) {
     118         384 :                 BindableStackDelete(st->backs);
     119         384 :                 BindableStackDelete(st->views);
     120         384 :                 group_2d_destroy(node, (GroupingNode2D*)st);
     121         384 :                 gf_free(st);
     122         384 :                 return;
     123             :         }
     124             : 
     125             :         /*layers can only be used in a 2D context*/
     126             : #ifndef GPAC_DISABLE_3D
     127        5371 :         if (tr_state->visual->type_3d && tr_state->camera && tr_state->camera->is_3D) return;
     128             : #endif
     129             : 
     130             :         /*layer2D maintains its own stacks*/
     131        5371 :         oldb = tr_state->backgrounds;
     132        5371 :         oldv = tr_state->viewpoints;
     133        5371 :         tr_state->backgrounds = st->backs;
     134        5371 :         tr_state->viewpoints = st->views;
     135        5371 :         prev_layer = tr_state->is_layer;
     136        5371 :         tr_state->is_layer = 1;
     137             : #ifndef GPAC_DISABLE_3D
     138        5371 :         oldf = tr_state->fogs;
     139        5371 :         oldn = tr_state->navigations;
     140        5371 :         tr_state->fogs = tr_state->navigations = NULL;
     141             : #endif
     142             : 
     143        5371 :         l2d_CheckBindables(node, tr_state, st->first);
     144             : 
     145        5371 :         back = (GF_Node*)gf_list_get(st->backs, 0);
     146             : 
     147        5371 :         viewport = (GF_Node*)gf_list_get(st->views, 0);
     148             : 
     149        5371 :         if ((tr_state->traversing_mode == TRAVERSE_SORT) || (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS)) {
     150             :                 /*override group bounds*/
     151        5195 :                 visual_get_size_info(tr_state, &st->clip.width, &st->clip.height);
     152             :                 /*setup bounds in local coord system*/
     153        5195 :                 if (l->size.x>=0) st->clip.width = l->size.x;
     154        5195 :                 if (l->size.y>=0) st->clip.height = l->size.y;
     155        5195 :                 st->clip = gf_rect_center(st->clip.width, st->clip.height);
     156        5195 :                 st->bounds = st->clip;
     157             :         }
     158             : 
     159        5371 :         prev_vp = tr_state->vp_size;
     160        5371 :         tr_state->vp_size.x = st->clip.width;
     161        5371 :         tr_state->vp_size.y = st->clip.height;
     162             : 
     163        5371 :         switch (tr_state->traversing_mode) {
     164        5148 :         case TRAVERSE_SORT:
     165             : #ifndef GPAC_DISABLE_3D
     166        5148 :                 if (tr_state->visual->type_3d) {
     167         805 :                         gf_mx_copy(prev_layer_mx, tr_state->layer_matrix);
     168         805 :                         tr_state->layer_clipper = compositor_2d_update_clipper(tr_state, st->clip, &had_clip, &prev_clipper, 1);
     169             : 
     170         805 :                         gf_mx_copy(mx3d, tr_state->model_matrix);
     171             : 
     172             :                         /*setup clipping*/
     173         805 :                         if (had_clip) {
     174         157 :                                 visual_3d_reset_clipper_2d(tr_state->visual);
     175             :                         }
     176         805 :                         visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper, &mx3d);
     177             : 
     178             :                         /*apply background BEFORE viewport*/
     179         805 :                         if (back) {
     180         471 :                                 tr_state->traversing_mode = TRAVERSE_BINDABLE;
     181         471 :                                 gf_bbox_from_rect(&tr_state->bbox, &st->clip);
     182         471 :                                 gf_node_traverse(back, tr_state);
     183             :                         }
     184             : 
     185             :                         /*apply viewport*/
     186         805 :                         if (viewport) {
     187          28 :                                 tr_state->traversing_mode = TRAVERSE_BINDABLE;
     188          28 :                                 tr_state->bounds = st->clip;
     189          28 :                                 gf_node_traverse(viewport, tr_state);
     190             :                         }
     191             : 
     192             : 
     193         805 :                         node_list_backup = tr_state->visual->alpha_nodes_to_draw;
     194         805 :                         tr_state->visual->alpha_nodes_to_draw = gf_list_new();
     195         805 :                         tr_state->traversing_mode = TRAVERSE_SORT;
     196             :                         /*reset cull flag*/
     197         805 :                         tr_state->cull_flag = 0;
     198         805 :                         group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
     199             : 
     200         805 :                         visual_3d_flush_contexts(tr_state->visual, tr_state);
     201         805 :                         tr_state->traversing_mode = TRAVERSE_SORT;
     202             : 
     203             :                         assert(!gf_list_count(tr_state->visual->alpha_nodes_to_draw));
     204         805 :                         gf_list_del(tr_state->visual->alpha_nodes_to_draw);
     205         805 :                         tr_state->visual->alpha_nodes_to_draw = node_list_backup;
     206             : 
     207             :                         gf_mx_copy(tr_state->model_matrix, mx3d);
     208             : 
     209         805 :                         visual_3d_reset_clipper_2d(tr_state->visual);
     210             : 
     211         805 :                         tr_state->has_layer_clip = had_clip;
     212         805 :                         if (had_clip) {
     213         157 :                                 tr_state->layer_clipper = prev_clipper;
     214             :                                 gf_mx_copy(tr_state->layer_matrix, prev_layer_mx);
     215         157 :                                 visual_3d_set_clipper_2d(tr_state->visual, tr_state->layer_clipper, &prev_layer_mx);
     216             :                         }
     217             :                 } else
     218             : #endif
     219             :                 {
     220        4343 :                         gf_mx2d_copy(backup, tr_state->transform);
     221             : 
     222        4343 :                         prev_clip = tr_state->visual->top_clipper;
     223        4343 :                         rc = st->clip;
     224             : 
     225             :                         /*get clipper in world coordinate*/
     226        4343 :                         gf_mx2d_apply_rect(&tr_state->transform, &rc);
     227             : 
     228        4343 :                         if (viewport) {
     229          56 :                                 tr_state->traversing_mode = TRAVERSE_BINDABLE;
     230          56 :                                 tr_state->bounds = st->clip;
     231          56 :                                 gf_node_traverse(viewport, tr_state);
     232             : #if VIEWPORT_CLIPS
     233             :                                 /*move viewport box in world coordinate*/
     234             :                                 gf_mx2d_apply_rect(&backup, &tr_state->bounds);
     235             :                                 /*and intersect with layer clipper*/
     236             :                                 rect_intersect(&rc, &tr_state->bounds);
     237             : #endif
     238             :                         }
     239             : 
     240        4343 :                         rc.x -= FIX_ONE;
     241        4343 :                         rc.width += 2*FIX_ONE;
     242        4343 :                         rc.y += FIX_ONE;
     243        4343 :                         rc.height += 2*FIX_ONE;
     244        4343 :                         tr_state->visual->top_clipper = gf_rect_pixelize(&rc);
     245        4343 :                         gf_irect_intersect(&tr_state->visual->top_clipper, &prev_clip);
     246        4343 :                         tr_state->traversing_mode = TRAVERSE_SORT;
     247             : 
     248        4343 :                         if (tr_state->visual->top_clipper.width && tr_state->visual->top_clipper.height) {
     249        4201 :                                 if (back && Bindable_GetIsBound(back) ) {
     250             :                                         DrawableContext *ctx;
     251             : 
     252         860 :                                         ctx = b2d_get_context((M_Background2D*) back, st->backs);
     253        1720 :                                         gf_mx2d_init(ctx->transform);
     254         860 :                                         ctx->bi->clip = tr_state->visual->top_clipper;
     255         860 :                                         ctx->bi->unclip = rc;
     256             : 
     257         860 :                                         if (tr_state->immediate_draw) {
     258           6 :                                                 tr_state->ctx = ctx;
     259           6 :                                                 tr_state->traversing_mode = TRAVERSE_DRAW_2D;
     260           6 :                                                 gf_node_traverse(back, tr_state);
     261           6 :                                                 tr_state->traversing_mode = TRAVERSE_SORT;
     262           6 :                                                 tr_state->ctx = NULL;
     263             :                                         } else {
     264         854 :                                                 DrawableContext *back_ctx = visual_2d_get_drawable_context(tr_state->visual);
     265             : 
     266         854 :                                                 gf_node_traverse(back, tr_state);
     267             : 
     268         854 :                                                 back_ctx->flags = ctx->flags;
     269         854 :                                                 back_ctx->flags &= ~CTX_IS_TRANSPARENT;
     270         854 :                                                 back_ctx->flags |= CTX_IS_BACKGROUND;
     271         854 :                                                 back_ctx->aspect = ctx->aspect;
     272         854 :                                                 back_ctx->drawable = ctx->drawable;
     273         854 :                                                 drawable_check_bounds(back_ctx, tr_state->visual);
     274         854 :                                                 back_ctx->bi->clip = ctx->bi->clip;
     275         854 :                                                 back_ctx->bi->unclip = ctx->bi->unclip;
     276             :                                         }
     277             :                                         /*keep track of node drawn*/
     278         860 :                                         if (!(ctx->drawable->flags & DRAWABLE_REGISTERED_WITH_VISUAL) ) {
     279             :                                                 struct _drawable_store *it;
     280          17 :                                                 GF_SAFEALLOC(it, struct _drawable_store);
     281          17 :                                                 if (!it) {
     282           0 :                                                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Layer2D] Failed to allocate drawable store\n"));
     283             :                                                 } else {
     284          17 :                                                         it->drawable = ctx->drawable;
     285          17 :                                                         if (tr_state->visual->last_prev_entry) {
     286          13 :                                                                 tr_state->visual->last_prev_entry->next = it;
     287          13 :                                                                 tr_state->visual->last_prev_entry = it;
     288             :                                                         } else {
     289           4 :                                                                 tr_state->visual->prev_nodes = tr_state->visual->last_prev_entry = it;
     290             :                                                         }
     291          17 :                                                         GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Layer2D] Registering new drawn node %s on visual\n", gf_node_get_class_name(it->drawable->node)));
     292          17 :                                                         ctx->drawable->flags |= DRAWABLE_REGISTERED_WITH_VISUAL;
     293             :                                                 }
     294             :                                         }
     295             :                                 }
     296             : 
     297        4201 :                                 group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
     298             :                         }
     299        4343 :                         tr_state->visual->top_clipper = prev_clip;
     300             :                         gf_mx2d_copy(tr_state->transform, backup);
     301             :                 }
     302             :                 break;
     303             : 
     304             :         /*check picking - we must fall in our 2D clipper*/
     305         176 :         case TRAVERSE_PICK:
     306         176 :                 if (gf_sc_pick_in_clipper(tr_state, &st->clip)) {
     307             : 
     308             : #ifndef GPAC_DISABLE_3D
     309         135 :                         if (tr_state->visual->type_3d) {
     310             :                                 /*apply viewport*/
     311           0 :                                 if (viewport) {
     312           0 :                                         gf_mx_copy(mx3d, tr_state->model_matrix);
     313           0 :                                         tr_state->traversing_mode = TRAVERSE_BINDABLE;
     314           0 :                                         tr_state->bounds = st->clip;
     315           0 :                                         gf_node_traverse(viewport, tr_state);
     316           0 :                                         tr_state->traversing_mode = TRAVERSE_PICK;
     317           0 :                                         group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
     318             :                                         gf_mx_copy(tr_state->model_matrix, mx3d);
     319             :                                 } else {
     320           0 :                                         group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
     321             :                                 }
     322             :                         } else
     323             : #endif
     324             :                         {
     325         135 :                                 if (viewport) {
     326           0 :                                         gf_mx2d_copy(backup, tr_state->transform);
     327           0 :                                         tr_state->traversing_mode = TRAVERSE_BINDABLE;
     328           0 :                                         tr_state->bounds = st->clip;
     329           0 :                                         gf_node_traverse(viewport, tr_state);
     330           0 :                                         tr_state->traversing_mode = TRAVERSE_PICK;
     331           0 :                                         group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
     332             :                                         gf_mx2d_copy(tr_state->transform, backup);
     333             :                                 } else {
     334         135 :                                         group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
     335             :                                 }
     336             :                         }
     337             :                 }
     338             :                 break;
     339          47 :         case TRAVERSE_GET_BOUNDS:
     340          47 :                 if (tr_state->for_node) {
     341           0 :                         group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
     342             :                 } else {
     343          47 :                         tr_state->bounds = st->clip;
     344             : #ifndef GPAC_DISABLE_3D
     345          47 :                         gf_bbox_from_rect(&tr_state->bbox, &st->clip);
     346             : #endif
     347             :                 }
     348             :                 break;
     349             : 
     350           0 :         case TRAVERSE_DRAW_2D:
     351           0 :                 group_2d_traverse(node, (GroupingNode2D *)st, tr_state);
     352           0 :                 break;
     353             : 
     354             : #ifndef GPAC_DISABLE_3D
     355             :         /*drawing a layer means drawing all sub-elements as a whole (no depth sorting with parents)*/
     356             :         case TRAVERSE_DRAW_3D:
     357             :                 assert(0);
     358             :                 break;
     359             : #endif
     360             :         }
     361             : 
     362             :         /*restore traversing state*/
     363        5371 :         tr_state->vp_size = prev_vp;
     364        5371 :         tr_state->backgrounds = oldb;
     365        5371 :         tr_state->viewpoints = oldv;
     366        5371 :         tr_state->is_layer = prev_layer;
     367             : #ifndef GPAC_DISABLE_3D
     368        5371 :         tr_state->fogs = oldf;
     369        5371 :         tr_state->navigations = oldn;
     370             : #endif
     371             : 
     372             :         /*in case we missed bindables*/
     373        5371 :         if (st->first) {
     374         319 :                 st->first = 0;
     375         319 :                 gf_sc_invalidate(tr_state->visual->compositor, NULL);
     376             :         }
     377             : }
     378             : 
     379         384 : void compositor_init_layer2d(GF_Compositor *compositor, GF_Node *node)
     380             : {
     381             :         Layer2DStack *stack;
     382         384 :         GF_SAFEALLOC(stack, Layer2DStack);
     383         384 :         if (!stack) {
     384           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate layer2d stack\n"));
     385             :                 return;
     386             :         }
     387             : 
     388         384 :         stack->backs = gf_list_new();
     389         384 :         stack->views = gf_list_new();
     390         384 :         stack->first = 1;
     391             : 
     392         384 :         gf_node_set_private(node, stack);
     393         384 :         gf_node_set_callback_function(node, TraverseLayer2D);
     394             : }
     395             : 
     396             : 
     397             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13