LCOV - code coverage report
Current view: top level - compositor - mpeg4_geometry_2d.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 348 425 81.9 %
Date: 2021-04-29 23:48:07 Functions: 23 24 95.8 %

          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 "visual_manager.h"
      30             : 
      31        1008 : Bool compositor_get_2d_plane_intersection(GF_Ray *ray, SFVec3f *res)
      32             : {
      33             :         GF_Plane p;
      34             :         Fixed t, t2;
      35        1008 :         if (!ray->dir.x && !ray->dir.y) {
      36         553 :                 res->x = ray->orig.x;
      37         553 :                 res->y = ray->orig.y;
      38         553 :                 res->z = 0;
      39         553 :                 return 1;
      40             :         }
      41         455 :         p.normal.x = p.normal.y = 0;
      42         455 :         p.normal.z = FIX_ONE;
      43             :         p.d = 0;
      44         455 :         t2 = gf_vec_dot(p.normal, ray->dir);
      45         455 :         if (t2 == 0) return 0;
      46         455 :         t = - gf_divfix(gf_vec_dot(p.normal, ray->orig) + p.d, t2);
      47         455 :         if (t<0) return 0;
      48         455 :         *res = gf_vec_scale(ray->dir, t);
      49         455 :         gf_vec_add(*res, ray->orig, *res);
      50         455 :         return 1;
      51             : }
      52             : 
      53             : #ifndef GPAC_DISABLE_VRML
      54             : 
      55             : /*
      56             :                 Shape
      57             : */
      58      308794 : static void TraverseShape(GF_Node *node, void *rs, Bool is_destroy)
      59             : {
      60             :         GF_TraverseState *tr_state;
      61             :         M_Shape *shape;
      62      308794 :         if (is_destroy ) return;
      63             : 
      64             :         tr_state = (GF_TraverseState *)rs;
      65             : #ifndef GPAC_DISABLE_3D
      66      304137 :         if (tr_state->traversing_mode==TRAVERSE_LIGHTING) return;
      67             : #endif
      68             : 
      69             :         shape = (M_Shape *) node;
      70      289306 :         if (!shape->geometry) return;
      71             : 
      72             :         /*reset this node dirty flag (because bitmap may trigger bounds invalidation on the fly)*/
      73      283534 :         gf_node_dirty_clear(node, 0);
      74             : 
      75             : 
      76             :         /*check traverse mode, and take care of switch-off flag*/
      77      283534 :         if (tr_state->traversing_mode==TRAVERSE_GET_BOUNDS) {
      78        4805 :                 tr_state->appear = (GF_Node *) shape->appearance;
      79             : 
      80             :                 /*this is done regardless of switch flag*/
      81        4805 :                 gf_node_traverse((GF_Node *) shape->geometry, tr_state);
      82             : 
      83        4805 :                 if (tr_state->appear) {
      84             :                         /*apply line width*/
      85        4731 :                         GF_Node *m = ((M_Appearance *)tr_state->appear)->material;
      86        4731 :                         if (m && (gf_node_get_tag(m)==TAG_MPEG4_Material2D) ) {
      87             :                                 DrawAspect2D asp;
      88             :                                 Fixed width = 0;
      89        2190 :                                 asp.line_scale = FIX_ONE;
      90        2190 :                                 m = ((M_Material2D *)m)->lineProps;
      91        2190 :                                 if (m) {
      92          11 :                                         switch (gf_node_get_tag(m)) {
      93          11 :                                         case TAG_MPEG4_LineProperties:
      94          11 :                                                 width = ((M_LineProperties *) m)->width;
      95          11 :                                                 drawable_compute_line_scale(tr_state, &asp);
      96          11 :                                                 break;
      97           0 :                                         case TAG_MPEG4_XLineProperties:
      98           0 :                                                 if ( ((M_XLineProperties *) m)->isCenterAligned)
      99           0 :                                                         width = ((M_XLineProperties *) m)->width;
     100           0 :                                                 if ( ((M_XLineProperties *) m)->isScalable)
     101           0 :                                                         drawable_compute_line_scale(tr_state, &asp);
     102             :                                                 break;
     103             :                                         }
     104          11 :                                         width = gf_mulfix(width, asp.line_scale);
     105          11 :                                         tr_state->bounds.width += width;
     106          11 :                                         tr_state->bounds.height += width;
     107          11 :                                         tr_state->bounds.y += width/2;
     108          11 :                                         tr_state->bounds.x -= width/2;
     109             :                                 }
     110             :                         }
     111        4731 :                         tr_state->appear = NULL;
     112             :                 }
     113             :         } else {
     114      278729 :                 if (tr_state->switched_off) return;
     115             : 
     116      277695 :                 tr_state->appear = (GF_Node *) shape->appearance;
     117             : 
     118      277695 :                 switch (tr_state->traversing_mode) {
     119      175772 :                 case TRAVERSE_SORT:
     120             : #ifndef GPAC_DISABLE_3D
     121      175772 :                         if (tr_state->visual->type_3d)
     122       23665 :                                 visual_3d_register_context(tr_state, shape->geometry);
     123             :                         else
     124             : #endif
     125      152107 :                                 gf_node_traverse((GF_Node *) shape->geometry, tr_state);
     126             :                         break;
     127       96995 :                 case TRAVERSE_PICK:
     128       96995 :                         gf_node_traverse((GF_Node *) shape->geometry, tr_state);
     129       96995 :                         break;
     130             : #ifndef GPAC_DISABLE_3D
     131             :                 /*if we're here we passed culler already*/
     132           0 :                 case TRAVERSE_DRAW_3D:
     133           0 :                         if (!tr_state->visual->type_3d && tr_state->visual->compositor->hybrid_opengl) {
     134           0 :                                 tr_state->visual->compositor->root_visual_setup=0;
     135           0 :                                 tr_state->visual->compositor->force_type_3d=1;
     136             :                         }
     137           0 :                         gf_node_traverse((GF_Node *) shape->geometry, tr_state);
     138           0 :                         break;
     139        4928 :                 case TRAVERSE_COLLIDE:
     140        4928 :                         visual_3d_vrml_drawable_collide(shape->geometry, tr_state);
     141        4928 :                         break;
     142             : #endif
     143             :                 }
     144             : 
     145      277695 :                 tr_state->appear = NULL;
     146             :         }
     147             : }
     148             : 
     149        4657 : void compositor_init_shape(GF_Compositor *compositor, GF_Node *node)
     150             : {
     151        4657 :         gf_node_set_callback_function(node, TraverseShape);
     152        4657 : }
     153             : 
     154      123482 : static void circle_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
     155             : {
     156      123482 :         if (gf_node_dirty_get(node)) {
     157        1788 :                 Fixed a = ((M_Circle *) node)->radius * 2;
     158        1788 :                 drawable_reset_path(stack);
     159        1788 :                 gf_path_add_ellipse(stack->path, 0, 0, a, a);
     160        1788 :                 gf_node_dirty_clear(node, 0);
     161        1788 :                 drawable_mark_modified(stack, tr_state);
     162             :         }
     163      123482 : }
     164      124386 : static void TraverseCircle(GF_Node *node, void *rs, Bool is_destroy)
     165             : {
     166             :         DrawableContext *ctx;
     167      124386 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
     168             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     169             : 
     170      124386 :         if (is_destroy) {
     171         904 :                 drawable_node_del(node);
     172         904 :                 return;
     173             :         }
     174             : 
     175      123482 :         circle_check_changes(node, stack, tr_state);
     176             : 
     177      123482 :         switch (tr_state->traversing_mode) {
     178             : #ifndef GPAC_DISABLE_3D
     179        1007 :         case TRAVERSE_DRAW_3D:
     180        1007 :                 if (!stack->mesh) {
     181         181 :                         Fixed a = ((M_Circle *) node)->radius * 2;
     182         181 :                         stack->mesh = new_mesh();
     183         181 :                         mesh_new_ellipse(stack->mesh, a, a, tr_state->visual->compositor->fast);
     184             :                 }
     185        1007 :                 visual_3d_draw_2d(stack, tr_state);
     186        1007 :                 return;
     187             : #endif
     188         193 :         case TRAVERSE_GET_BOUNDS:
     189         193 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
     190         193 :                 return;
     191       71242 :         case TRAVERSE_PICK:
     192       71242 :                 vrml_drawable_pick(stack, tr_state);
     193       71242 :                 return;
     194       51040 :         case TRAVERSE_SORT:
     195             : #ifndef GPAC_DISABLE_3D
     196       51040 :                 if (tr_state->visual->type_3d) return;
     197             : #endif
     198       51040 :                 ctx = drawable_init_context_mpeg4(stack, tr_state);
     199       51040 :                 if (!ctx) return;
     200       16882 :                 drawable_finalize_sort(ctx, tr_state, NULL);
     201       16882 :                 return;
     202             :         }
     203             : }
     204             : 
     205         904 : void compositor_init_circle(GF_Compositor *compositor, GF_Node *node)
     206             : {
     207         904 :         drawable_stack_new(compositor, node);
     208         904 :         gf_node_set_callback_function(node, TraverseCircle);
     209         904 : }
     210             : 
     211         104 : static void ellipse_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
     212             : {
     213         104 :         if (gf_node_dirty_get(node)) {
     214           4 :                 drawable_reset_path(stack);
     215           4 :                 gf_path_add_ellipse(stack->path, 0, 0, ((M_Ellipse *) node)->radius.x*2, ((M_Ellipse *) node)->radius.y*2);
     216           4 :                 gf_node_dirty_clear(node, 0);
     217           4 :                 drawable_mark_modified(stack, tr_state);
     218             :         }
     219         104 : }
     220         108 : static void TraverseEllipse(GF_Node *node, void *rs, Bool is_destroy)
     221             : {
     222             :         DrawableContext *ctx;
     223         108 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
     224             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     225             : 
     226         108 :         if (is_destroy) {
     227           4 :                 drawable_node_del(node);
     228           4 :                 return;
     229             :         }
     230             : 
     231         104 :         ellipse_check_changes(node, stack, tr_state);
     232             : 
     233         104 :         switch (tr_state->traversing_mode) {
     234             : #ifndef GPAC_DISABLE_3D
     235           0 :         case TRAVERSE_DRAW_3D:
     236           0 :                 if (!stack->mesh) {
     237           0 :                         stack->mesh = new_mesh();
     238           0 :                         mesh_new_ellipse(stack->mesh, ((M_Ellipse *) node)->radius.x * 2, ((M_Ellipse *) node)->radius.y * 2, tr_state->visual->compositor->fast);
     239             :                 }
     240           0 :                 visual_3d_draw_2d(stack, tr_state);
     241           0 :                 return;
     242             : #endif
     243          11 :         case TRAVERSE_PICK:
     244          11 :                 vrml_drawable_pick(stack, tr_state);
     245          11 :                 return;
     246           4 :         case TRAVERSE_GET_BOUNDS:
     247           4 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
     248           4 :                 return;
     249          89 :         case TRAVERSE_SORT:
     250             : #ifndef GPAC_DISABLE_3D
     251          89 :                 if (tr_state->visual->type_3d) return;
     252             : #endif
     253          89 :                 ctx = drawable_init_context_mpeg4(stack, tr_state);
     254          89 :                 if (!ctx) return;
     255          89 :                 drawable_finalize_sort(ctx, tr_state, NULL);
     256          89 :                 break;
     257             :         }
     258             : }
     259             : 
     260           4 : void compositor_init_ellipse(GF_Compositor  *compositor, GF_Node *node)
     261             : {
     262           4 :         drawable_stack_new(compositor, node);
     263           4 :         gf_node_set_callback_function(node, TraverseEllipse);
     264           4 : }
     265             : 
     266       23668 : static void compositor_2d_draw_rectangle(GF_TraverseState *tr_state)
     267             : {
     268       23668 :         DrawableContext *ctx = tr_state->ctx;
     269             : 
     270       23668 :         if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->data
     271             : #ifndef GPAC_DISABLE_3D
     272        2982 :                 && !tr_state->visual->compositor->hybrid_opengl
     273             : #endif
     274             :            ) {
     275             :                 Bool res;
     276             : 
     277             :                 /*get image size WITHOUT line size or antialias margin*/
     278        2742 :                 if ( !(ctx->flags & CTX_NO_ANTIALIAS) ) {
     279             :                         GF_Rect orig_unclip;
     280             :                         GF_IRect orig_clip;
     281        2435 :                         orig_unclip = ctx->bi->unclip;
     282        2435 :                         orig_clip = ctx->bi->clip;
     283             : 
     284        2435 :                         gf_path_get_bounds(ctx->drawable->path, &ctx->bi->unclip);
     285        2435 :                         gf_mx2d_apply_rect(&ctx->transform, &ctx->bi->unclip);
     286        2435 :                         ctx->bi->clip = gf_rect_pixelize(&ctx->bi->unclip);
     287        2435 :                         gf_irect_intersect(&ctx->bi->clip, &orig_clip);
     288             : 
     289        2435 :                         res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx);
     290             : 
     291             :                         /*strike path*/
     292        2435 :                         ctx->bi->unclip = orig_unclip;
     293        2435 :                         ctx->bi->clip = orig_clip;
     294        2435 :                         if (res) {
     295         682 :                                 ctx->flags |= CTX_PATH_FILLED;
     296         682 :                                 visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
     297             :                         }
     298             :                 } else {
     299         307 :                         res = tr_state->visual->DrawBitmap(tr_state->visual, tr_state, ctx);
     300             :                 }
     301             :                 /*if failure retry with raster*/
     302        2742 :                 if (res) return;
     303             :         }
     304             : 
     305       22689 :         visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state);
     306       22689 :         visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
     307             : }
     308             : 
     309       71030 : static void rectangle_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
     310             : {
     311             :         /*if modified update node - we don't update for other traversing mode in order not to mess up the dirty
     312             :         rect tracking (otherwise we would miss geometry changes with same bounds)*/
     313       71030 :         if (gf_node_dirty_get(node)) {
     314         382 :                 drawable_reset_path(stack);
     315         382 :                 gf_path_add_rect_center(stack->path, 0, 0, ((M_Rectangle *) node)->size.x, ((M_Rectangle *) node)->size.y);
     316         382 :                 gf_node_dirty_clear(node, 0);
     317         382 :                 drawable_mark_modified(stack, tr_state);
     318             :         }
     319       71030 : }
     320             : 
     321       85682 : Bool rectangle_check_adaptation(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
     322             : {
     323             :         GF_TextureHandler *txh;
     324             :         GF_MediaObjectVRInfo vrinfo;
     325             :         s32 gaze_x, gaze_y;
     326             :         Bool is_visible = GF_FALSE;
     327       85682 :         if (! tr_state->visual->compositor->gazer_enabled)
     328             :                 return GF_TRUE;
     329             : 
     330           0 :         if (!tr_state->appear || ! ((M_Appearance *)tr_state->appear)->texture)
     331             :                 return GF_TRUE;
     332             :         
     333           0 :         txh = gf_sc_texture_get_handler( ((M_Appearance *) tr_state->appear)->texture );
     334           0 :         if (!txh->stream) return GF_TRUE;
     335             : 
     336           0 :         if (! gf_mo_get_srd_info(txh->stream, &vrinfo))
     337             :                 return GF_TRUE;
     338             : 
     339           0 :         if (!vrinfo.srd_w && !vrinfo.srd_h && vrinfo.is_tiled_srd) {
     340           0 :                 if (txh->stream->srd_full_w && txh->stream->srd_full_h) {
     341           0 :                         gaze_x = tr_state->visual->compositor->gaze_x;
     342           0 :                         gaze_x *= txh->stream->srd_full_w;
     343           0 :                         gaze_x /= tr_state->visual->width;
     344             : 
     345           0 :                         gaze_y = tr_state->visual->compositor->gaze_y;
     346           0 :                         gaze_y *= txh->stream->srd_full_h;
     347           0 :                         gaze_y /= tr_state->visual->height;
     348             : 
     349           0 :                         gf_mo_hint_gaze(txh->stream, gaze_x, gaze_y);
     350             :                 }
     351             : 
     352             :                 return GF_TRUE;
     353             :         }
     354             : 
     355           0 :         gaze_x = tr_state->visual->compositor->gaze_x;
     356           0 :         gaze_x *= vrinfo.srd_max_x;
     357           0 :         gaze_x /= tr_state->visual->width;
     358             : 
     359           0 :         gaze_y = tr_state->visual->compositor->gaze_y;
     360           0 :         gaze_y *= vrinfo.srd_max_y;
     361           0 :         gaze_y /= tr_state->visual->height;
     362             : 
     363             :         //simple test condition: only keep the first row
     364           0 :         if ((gaze_x>=vrinfo.srd_x) && (gaze_x<=vrinfo.srd_x+vrinfo.srd_w) && (gaze_y>=vrinfo.srd_y) && (gaze_y<=vrinfo.srd_y+vrinfo.srd_h)) {
     365             : 
     366           0 :                 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texture %d Partial plane is under gaze coord %d %d\n", txh->stream->OD_ID, tr_state->visual->compositor->gaze_x, tr_state->visual->compositor->gaze_y));
     367             :                 is_visible = GF_TRUE;
     368             :         }
     369             : 
     370           0 :         if (vrinfo.has_full_coverage) {
     371           0 :                 if (is_visible) {
     372           0 :                         if (!txh->is_open) {
     373           0 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texture %d stoped on visible partial plane - starting it\n", txh->stream->OD_ID));
     374             :                                 assert(txh->stream && txh->stream->odm);
     375           0 :                                 txh->stream->odm->disable_buffer_at_next_play = GF_TRUE;
     376             : 
     377           0 :                                 gf_sc_texture_play(txh, NULL);
     378             :                         }
     379           0 :                         if (! txh->data)  return GF_FALSE;
     380           0 :                         return GF_TRUE;
     381             :                 } else {
     382           0 :                         if (txh->is_open) {
     383           0 :                                 GF_LOG(GF_LOG_INFO, GF_LOG_COMPOSE, ("[Compositor] Texure %d playing on hidden partial plane - stopping it\n", txh->stream->OD_ID));
     384           0 :                                 gf_sc_texture_stop_no_unregister(txh);
     385             :                         }
     386             :                         return GF_FALSE;
     387             :                 }
     388             :         } else {
     389           0 :                 if (is_visible) {
     390           0 :                         gf_mo_hint_quality_degradation(txh->stream, 0);
     391           0 :                         if (! txh->data)  return GF_FALSE;
     392             :                 } else {
     393           0 :                         gf_mo_hint_quality_degradation(txh->stream, 100);
     394             :                 }
     395             :         }
     396             :         return GF_TRUE;
     397             : }
     398             : 
     399       71421 : static void TraverseRectangle(GF_Node *node, void *rs, Bool is_destroy)
     400             : {
     401             :         DrawableContext *ctx;
     402       71421 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
     403             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     404             : 
     405       71421 :         if (is_destroy) {
     406         391 :                 drawable_node_del(node);
     407         391 :                 return;
     408             :         }
     409             : 
     410       71030 :         rectangle_check_changes(node, stack, tr_state);
     411             : 
     412       71030 :         if (! rectangle_check_adaptation(node, stack, tr_state))
     413             :                 return;
     414             : 
     415       71030 :         switch (tr_state->traversing_mode) {
     416       23668 :         case TRAVERSE_DRAW_2D:
     417       23668 :                 compositor_2d_draw_rectangle(tr_state);
     418       23668 :                 return;
     419             : #ifndef GPAC_DISABLE_3D
     420        3604 :         case TRAVERSE_DRAW_3D:
     421        3604 :                 if (!stack->mesh) {
     422          62 :                         stack->mesh = new_mesh();
     423          62 :                         mesh_new_rectangle(stack->mesh, ((M_Rectangle *) node)->size, NULL, 0);
     424             :                 }
     425        3604 :                 visual_3d_draw_2d(stack, tr_state);
     426        3604 :                 return;
     427             : #endif
     428       15552 :         case TRAVERSE_PICK:
     429       15552 :                 vrml_drawable_pick(stack, tr_state);
     430       15552 :                 return;
     431        1157 :         case TRAVERSE_GET_BOUNDS:
     432        1157 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
     433        1157 :                 return;
     434       27049 :         case TRAVERSE_SORT:
     435             : #ifndef GPAC_DISABLE_3D
     436       27049 :                 if (tr_state->visual->type_3d) return;
     437             : #endif
     438             :                 break;
     439             :         default:
     440             :                 return;
     441             :         }
     442             : 
     443       27049 :         ctx = drawable_init_context_mpeg4(stack, tr_state);
     444       27049 :         if (!ctx) return;
     445             : 
     446             :         /*if rotated, object is transparent (doesn't fill bounds) and antialias must be used*/
     447       26629 :         if (tr_state->transform.m[1] || tr_state->transform.m[3]) {
     448             :         }
     449             :         else {
     450             : 
     451             :                 /*if alpha or not filled, transparent*/
     452       23970 :                 if (ctx->aspect.fill_color && (GF_COL_A(ctx->aspect.fill_color) != 0xFF)) {
     453             :                 }
     454             :                 /*if texture transparent, transparent*/
     455       20386 :                 else if (ctx->aspect.fill_texture && ctx->aspect.fill_texture->transparent) {
     456             :                 }
     457             :                 /*TODO check matrix for alpha*/
     458       20374 :                 else if (!tr_state->color_mat.identity) {
     459             :                 }
     460             :                 /*otherwise, not transparent*/
     461             :                 else {
     462       20366 :                         ctx->flags &= ~CTX_IS_TRANSPARENT;
     463             :                 }
     464             :                 /*if no line width, we skip antialiasing*/
     465       23970 :                 if (!ctx->aspect.pen_props.width) ctx->flags |= CTX_NO_ANTIALIAS;
     466             :         }
     467       26629 :         drawable_finalize_sort(ctx, tr_state, NULL);
     468             : }
     469             : 
     470         391 : void compositor_init_rectangle(GF_Compositor  *compositor, GF_Node *node)
     471             : {
     472         391 :         Drawable *stack = drawable_stack_new(compositor, node);
     473         391 :         stack->flags = DRAWABLE_USE_TRAVERSE_DRAW;
     474         391 :         gf_node_set_callback_function(node, TraverseRectangle);
     475         391 : }
     476             : 
     477             : 
     478             : #define CHECK_VALID_C2D(nbPts) if (!idx && cur_index+nbPts>=pt_count) { gf_path_reset(stack->path); return; }
     479             : //#define CHECK_VALID_C2D(nbPts)
     480             : #define GET_IDX(_i)     ((idx && (idx->count>_i) && (idx->vals[_i]>=0) ) ? (u32) idx->vals[_i] : _i)
     481             : 
     482         961 : void curve2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state, MFInt32 *idx)
     483             : {
     484             :         M_Curve2D *c2D;
     485             :         SFVec2f orig, ct_orig, ct_end, end;
     486             :         u32 cur_index, i, remain, type_count, pt_count;
     487             :         SFVec2f *pts;
     488             :         M_Coordinate2D *coord;
     489             : 
     490             :         c2D = (M_Curve2D *)node;
     491         961 :         coord = (M_Coordinate2D *)c2D->point;
     492         961 :         drawable_reset_path(stack);
     493         961 :         if (!coord) return;
     494             : 
     495         961 :         stack->path->fineness = c2D->fineness;
     496         961 :         if (tr_state->visual->compositor->fast)  stack->path->fineness /= 2;
     497             : 
     498             : 
     499         961 :         pts = coord->point.vals;
     500         961 :         if (!pts)
     501             :                 return;
     502             : 
     503         953 :         cur_index = c2D->type.count ? 1 : 0;
     504             :         /*if the first type is a moveTo skip initial moveTo*/
     505             :         i=0;
     506         953 :         if (cur_index) {
     507           0 :                 while (c2D->type.vals[i]==0) i++;
     508             :         }
     509         953 :         ct_orig = orig = pts[ GET_IDX(i) ];
     510             : 
     511         953 :         gf_path_add_move_to(stack->path, orig.x, orig.y);
     512             : 
     513         953 :         pt_count = coord->point.count;
     514         953 :         type_count = c2D->type.count;
     515       15050 :         for (; i<type_count; i++) {
     516             : 
     517       14097 :                 switch (c2D->type.vals[i]) {
     518             :                 /*moveTo, 1 point*/
     519         328 :                 case 0:
     520         328 :                         CHECK_VALID_C2D(0);
     521         328 :                         orig = pts[ GET_IDX(cur_index) ];
     522         328 :                         if (i) gf_path_add_move_to(stack->path, orig.x, orig.y);
     523         328 :                         cur_index += 1;
     524         328 :                         break;
     525             :                 /*lineTo, 1 point*/
     526        6997 :                 case 1:
     527        6997 :                         CHECK_VALID_C2D(0);
     528        6997 :                         end = pts[ GET_IDX(cur_index) ];
     529        6997 :                         gf_path_add_line_to(stack->path, end.x, end.y);
     530             :                         orig = end;
     531        6997 :                         cur_index += 1;
     532        6997 :                         break;
     533             :                 /*curveTo, 3 points*/
     534        3415 :                 case 2:
     535        3415 :                         CHECK_VALID_C2D(2);
     536        3415 :                         ct_orig = pts[ GET_IDX(cur_index) ];
     537        3415 :                         ct_end = pts[ GET_IDX(cur_index+1) ];
     538        3415 :                         end = pts[ GET_IDX(cur_index+2) ];
     539        3415 :                         gf_path_add_cubic_to(stack->path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
     540        3415 :                         cur_index += 3;
     541             :                         ct_orig = ct_end;
     542             :                         orig = end;
     543        3415 :                         break;
     544             :                 /*nextCurveTo, 2 points (cf spec)*/
     545          18 :                 case 3:
     546          18 :                         CHECK_VALID_C2D(1);
     547          18 :                         ct_orig.x = 2*orig.x - ct_orig.x;
     548          18 :                         ct_orig.y = 2*orig.y - ct_orig.y;
     549          18 :                         ct_end = pts[ GET_IDX(cur_index) ];
     550          18 :                         end = pts[ GET_IDX(cur_index+1) ];
     551          18 :                         gf_path_add_cubic_to(stack->path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y);
     552          18 :                         cur_index += 2;
     553             :                         ct_orig = ct_end;
     554             :                         orig = end;
     555          18 :                         break;
     556             : 
     557             :                 /*all XCurve2D specific*/
     558             : 
     559             :                 /*CW and CCW ArcTo*/
     560           9 :                 case 4:
     561             :                 case 5:
     562           9 :                         CHECK_VALID_C2D(2);
     563           9 :                         ct_orig = pts[ GET_IDX(cur_index) ];
     564           9 :                         ct_end = pts[ GET_IDX(cur_index+1) ];
     565           9 :                         end = pts[ GET_IDX(cur_index+2) ];
     566           9 :                         gf_path_add_arc_to(stack->path, end.x, end.y, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, (c2D->type.vals[i]==5) ? 1 : 0);
     567           9 :                         cur_index += 3;
     568             :                         ct_orig = ct_end;
     569             :                         orig = end;
     570           9 :                         break;
     571             :                 /*ClosePath*/
     572         251 :                 case 6:
     573         251 :                         gf_path_close(stack->path);
     574         251 :                         break;
     575             :                 /*quadratic CurveTo, 2 points*/
     576        3079 :                 case 7:
     577        3079 :                         CHECK_VALID_C2D(1);
     578        3079 :                         ct_end = pts[ GET_IDX(cur_index) ];
     579        3079 :                         end = pts[ GET_IDX(cur_index+1) ];
     580        3079 :                         gf_path_add_quadratic_to(stack->path, ct_end.x, ct_end.y, end.x, end.y);
     581        3079 :                         cur_index += 2;
     582             :                         ct_orig = ct_end;
     583             :                         orig = end;
     584        3079 :                         break;
     585             :                 }
     586             :         }
     587             : 
     588             :         /*what's left is an N-bezier spline*/
     589         953 :         if (!idx && (pt_count > cur_index) ) {
     590             :                 /*first moveto*/
     591          49 :                 if (!cur_index) cur_index++;
     592             : 
     593          49 :                 remain = pt_count - cur_index;
     594             : 
     595          49 :                 if (remain>1)
     596          33 :                         gf_path_add_bezier(stack->path, &pts[cur_index], remain);
     597             :         }
     598             : 
     599         953 :         gf_node_dirty_clear(node, 0);
     600         953 :         drawable_mark_modified(stack, tr_state);
     601             : }
     602             : 
     603       25446 : static void TraverseCurve2D(GF_Node *node, void *rs, Bool is_destroy)
     604             : {
     605             :         DrawableContext *ctx;
     606       25446 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
     607             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     608             : 
     609       25446 :         if (is_destroy) {
     610         579 :                 drawable_node_del(node);
     611         579 :                 return;
     612             :         }
     613       24867 :         if (gf_node_dirty_get(node)) {
     614         698 :                 curve2d_check_changes(node, stack, tr_state, NULL);
     615             :         }
     616             : 
     617       24867 :         switch (tr_state->traversing_mode) {
     618             : #ifndef GPAC_DISABLE_3D
     619         320 :         case TRAVERSE_DRAW_3D:
     620         320 :                 if (!stack->mesh) {
     621          37 :                         stack->mesh = new_mesh();
     622          37 :                         mesh_from_path(stack->mesh, stack->path);
     623             :                 }
     624         320 :                 visual_3d_draw_2d(stack, tr_state);
     625         320 :                 return;
     626             : #endif
     627          37 :         case TRAVERSE_PICK:
     628          37 :                 vrml_drawable_pick(stack, tr_state);
     629          37 :                 return;
     630         341 :         case TRAVERSE_GET_BOUNDS:
     631         341 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
     632         341 :                 return;
     633       24169 :         case TRAVERSE_SORT:
     634             : #ifndef GPAC_DISABLE_3D
     635       24169 :                 if (tr_state->visual->type_3d) return;
     636             : #endif
     637       24169 :                 ctx = drawable_init_context_mpeg4(stack, tr_state);
     638       24169 :                 if (!ctx) return;
     639       22560 :                 drawable_finalize_sort(ctx, tr_state, NULL);
     640       22560 :                 return;
     641             :         }
     642             : }
     643             : 
     644         579 : void compositor_init_curve2d(GF_Compositor  *compositor, GF_Node *node)
     645             : {
     646         579 :         drawable_stack_new(compositor, node);
     647         579 :         gf_node_set_callback_function(node, TraverseCurve2D);
     648         579 : }
     649             : 
     650             : 
     651             : 
     652             : /*
     653             :         Note on point set 2D: this is a very bad node and should be avoided in DEF/USE, since the size
     654             :         of the rectangle representing the pixel shall always be 1 pixel w/h, therefore
     655             :         the path object is likely not the same depending on transformation context...
     656             : 
     657             : */
     658             : 
     659          18 : static void get_point_size(GF_Matrix2D *mat, Fixed *w, Fixed *h)
     660             : {
     661             :         GF_Point2D pt;
     662          18 :         pt.x = mat->m[0] + mat->m[1];
     663          18 :         pt.y = mat->m[3] + mat->m[4];
     664          18 :         *w = *h = gf_divfix(FLT2FIX(1.41421356f) , gf_v2d_len(&pt));
     665          18 : }
     666             : 
     667         442 : static void pointset2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
     668             : {
     669             :         u32 i;
     670             :         Fixed w, h;
     671             :         M_Coordinate2D *coord;
     672             : 
     673         866 :         if (!gf_node_dirty_get(node)) return;
     674          18 :         coord = (M_Coordinate2D *) ((M_PointSet2D *)node)->coord;
     675             : 
     676          18 :         drawable_reset_path(stack);
     677             : 
     678          18 :         get_point_size(&tr_state->transform, &w, &h);
     679             :         /*for PS2D don't add to avoid too  much antialiasing, just try to fill the given pixel*/
     680          90 :         for (i=0; i < coord->point.count; i++)
     681          72 :                 gf_path_add_rect(stack->path, coord->point.vals[i].x, coord->point.vals[i].y, w, h);
     682             : 
     683          18 :         stack->path->flags |= GF_PATH_FILL_ZERO_NONZERO;
     684             : 
     685          18 :         gf_node_dirty_clear(node, 0);
     686          18 :         drawable_mark_modified(stack, tr_state);
     687             : }
     688             : 
     689         146 : static void PointSet2D_Draw(GF_Node *node, GF_TraverseState *tr_state)
     690             : {
     691             :         GF_Path *path;
     692             :         Fixed alpha, w, h;
     693             :         u32 i;
     694             :         SFColor col;
     695         146 :         DrawableContext *ctx = tr_state->ctx;
     696             :         M_PointSet2D *ps2D = (M_PointSet2D *)node;
     697         146 :         M_Coordinate2D *coord = (M_Coordinate2D*) ps2D->coord;
     698         146 :         M_Color *color = (M_Color *) ps2D->color;
     699             : 
     700             :         /*never outline PS2D*/
     701         146 :         ctx->flags |= CTX_PATH_STROKE;
     702         146 :         if (!color || color->color.count<coord->point.count) {
     703             :                 /*no texturing*/
     704         146 :                 visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state);
     705         146 :                 return;
     706             :         }
     707             : 
     708           0 :         get_point_size(&ctx->transform, &w, &h);
     709             : 
     710           0 :         path = gf_path_new();
     711           0 :         alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255;
     712           0 :         for (i = 0; i < coord->point.count; i++) {
     713           0 :                 col = color->color.vals[i];
     714           0 :                 ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue);
     715           0 :                 gf_path_add_rect_center(path, coord->point.vals[i].x, coord->point.vals[i].y, w, h);
     716           0 :                 visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state);
     717           0 :                 gf_path_reset(path);
     718           0 :                 ctx->flags &= ~CTX_PATH_FILLED;
     719             :         }
     720           0 :         gf_path_del(path);
     721             : }
     722             : 
     723         460 : static void TraversePointSet2D(GF_Node *node, void *rs, Bool is_destroy)
     724             : {
     725             :         DrawableContext *ctx;
     726             :         M_PointSet2D *ps2D = (M_PointSet2D *)node;
     727         460 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
     728             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     729             : 
     730         460 :         if (is_destroy) {
     731          18 :                 drawable_node_del(node);
     732          18 :                 return;
     733             :         }
     734             : 
     735         442 :         if (!ps2D->coord) return;
     736             : 
     737         442 :         pointset2d_check_changes(node, stack, tr_state);
     738             : 
     739         442 :         switch (tr_state->traversing_mode) {
     740         146 :         case TRAVERSE_DRAW_2D:
     741         146 :                 PointSet2D_Draw(node, tr_state);
     742         146 :                 return;
     743             : #ifndef GPAC_DISABLE_3D
     744         144 :         case TRAVERSE_DRAW_3D:
     745             :         {
     746             :                 DrawAspect2D asp;
     747         144 :                 if (!stack->mesh) {
     748           9 :                         stack->mesh = new_mesh();
     749           9 :                         mesh_new_ps(stack->mesh, ps2D->coord, ps2D->color);
     750             :                 }
     751             :                 memset(&asp, 0, sizeof(DrawAspect2D));
     752         144 :                 drawable_get_aspect_2d_mpeg4(node, &asp, tr_state);
     753         144 :                 visual_3d_set_material_2d_argb(tr_state->visual, asp.fill_color);
     754         144 :                 visual_3d_mesh_paint(tr_state, stack->mesh);
     755             :                 return;
     756             :         }
     757             : #endif
     758           0 :         case TRAVERSE_GET_BOUNDS:
     759           0 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
     760           0 :                 return;
     761             :         case TRAVERSE_PICK:
     762             :                 return;
     763         152 :         case TRAVERSE_SORT:
     764             : #ifndef GPAC_DISABLE_3D
     765         152 :                 if (tr_state->visual->type_3d) return;
     766             : #endif
     767         152 :                 ctx = drawable_init_context_mpeg4(stack, tr_state);
     768         152 :                 if (!ctx) return;
     769         152 :                 drawable_finalize_sort(ctx, tr_state, NULL);
     770         152 :                 break;
     771             :         default:
     772             :                 return;
     773             :         }
     774             : }
     775             : 
     776             : 
     777          18 : void compositor_init_pointset2d(GF_Compositor  *compositor, GF_Node *node)
     778             : {
     779          18 :         Drawable *stack = drawable_stack_new(compositor, node);
     780          18 :         stack->flags = DRAWABLE_USE_TRAVERSE_DRAW;
     781          18 :         gf_node_set_callback_function(node, TraversePointSet2D);
     782          18 : }
     783             : 
     784           0 : static void TraverseBitWrapper(GF_Node *node, void *rs, Bool is_destroy)
     785             : {
     786             :         GF_TraverseState *tr_state;
     787             :         M_BitWrapper *bitWrap;
     788             : 
     789           0 :         if (is_destroy) {
     790           0 :                 gf_node_set_private(node, NULL);
     791           0 :                 return;
     792             :         }
     793             : #ifdef GPAC_ENABLE_COVERAGE
     794           0 :         if (!rs) return;
     795             : #endif
     796             : 
     797             :         tr_state = (GF_TraverseState *)rs;
     798             :         // Traverse the node here
     799             :         bitWrap = (M_BitWrapper *)node;
     800           0 :         gf_node_traverse(bitWrap->node, tr_state);
     801             : }
     802             : 
     803           6 : void compositor_init_bitwrapper(GF_Compositor *compositor, GF_Node *node)
     804             : {
     805             :         M_BitWrapper *bit;
     806             :         bit = (M_BitWrapper *)node;
     807           6 :         if (!bit->node) return;
     808           0 :         gf_node_set_private(node, gf_node_get_private(bit->node));
     809           0 :         gf_node_set_callback_function(node, TraverseBitWrapper);
     810             : 
     811             : #ifdef GPAC_ENABLE_COVERAGE
     812           0 :         if (gf_sys_is_cov_mode()) {
     813             :                 TraverseBitWrapper(node, NULL, GF_FALSE);
     814             :         }
     815             : #endif
     816             : }
     817             : 
     818             : 
     819             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13