LCOV - code coverage report
Current view: top level - compositor - x3d_geometry.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 495 587 84.3 %
Date: 2021-04-29 23:48:07 Functions: 39 42 92.9 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Compositor sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : #include "nodes_stacks.h"
      28             : #include "visual_manager.h"
      29             : #include "drawable.h"
      30             : 
      31             : #ifndef GPAC_DISABLE_X3D
      32             : 
      33           3 : static void disk2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
      34             : {
      35           3 :         if (gf_node_dirty_get(node)) {
      36           1 :                 Fixed a = ((X_Disk2D *) node)->outerRadius * 2;
      37           1 :                 drawable_reset_path(stack);
      38           1 :                 gf_path_add_ellipse(stack->path, 0, 0, a, a);
      39           1 :                 a = ((X_Disk2D *) node)->innerRadius * 2;
      40           1 :                 if (a) gf_path_add_ellipse(stack->path, 0, 0, a, a);
      41           1 :                 gf_node_dirty_clear(node, 0);
      42           1 :                 drawable_mark_modified(stack, tr_state);
      43             :         }
      44           3 : }
      45             : 
      46           4 : static void TraverseDisk2D(GF_Node *node, void *rs, Bool is_destroy)
      47             : {
      48             :         DrawableContext *ctx;
      49           4 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
      50             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
      51             : 
      52           4 :         if (is_destroy) {
      53           1 :                 drawable_node_del(node);
      54           1 :                 return;
      55             :         }
      56             : 
      57           3 :         disk2d_check_changes(node, stack, tr_state);
      58             : 
      59           3 :         switch (tr_state->traversing_mode) {
      60             : #ifndef GPAC_DISABLE_3D
      61           2 :         case TRAVERSE_DRAW_3D:
      62           2 :                 if (!stack->mesh) {
      63           1 :                         stack->mesh = new_mesh();
      64             :                         /*FIXME - enable it with OpenGL-ES*/
      65           1 :                         mesh_from_path(stack->mesh, stack->path);
      66             :                 }
      67           2 :                 visual_3d_draw_2d(stack, tr_state);
      68           2 :                 return;
      69             : #endif
      70           1 :         case TRAVERSE_GET_BOUNDS:
      71           1 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
      72           1 :                 return;
      73           0 :         case TRAVERSE_PICK:
      74           0 :                 vrml_drawable_pick(stack, tr_state);
      75           0 :                 return;
      76           0 :         case TRAVERSE_SORT:
      77             : #ifndef GPAC_DISABLE_3D
      78           0 :                 if (tr_state->visual->type_3d) return;
      79             : #endif
      80           0 :                 ctx = drawable_init_context_mpeg4(stack, tr_state);
      81           0 :                 if (!ctx) return;
      82           0 :                 drawable_finalize_sort(ctx, tr_state, NULL);
      83           0 :                 return;
      84             :         }
      85             : }
      86             : 
      87           1 : void compositor_init_disk2d(GF_Compositor *compositor, GF_Node *node)
      88             : {
      89           1 :         drawable_stack_new(compositor, node);
      90           1 :         gf_node_set_callback_function(node, TraverseDisk2D);
      91           1 : }
      92             : 
      93           6 : static void arc2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
      94             : {
      95           6 :         if (gf_node_dirty_get(node)) {
      96           2 :                 drawable_reset_path(stack);
      97           2 :                 if (gf_node_get_tag(node)==TAG_X3D_Arc2D) {
      98             :                         X_Arc2D *a = (X_Arc2D *) node;
      99           1 :                         gf_path_add_arc(stack->path, a->radius, a->startAngle, a->endAngle, 0);
     100             :                 } else {
     101             :                         X_ArcClose2D *a = (X_ArcClose2D *) node;
     102           1 :                         gf_path_add_arc(stack->path, a->radius, a->startAngle, a->endAngle, !stricmp(a->closureType.buffer, "PIE") ? 2 : 1);
     103             :                 }
     104           2 :                 gf_node_dirty_clear(node, 0);
     105           2 :                 drawable_mark_modified(stack, tr_state);
     106             :         }
     107           6 : }
     108             : 
     109           8 : static void TraverseArc2D(GF_Node *node, void *rs, Bool is_destroy)
     110             : {
     111             :         DrawableContext *ctx;
     112           8 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
     113             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     114           8 :         if (is_destroy) {
     115           2 :                 drawable_node_del(node);
     116           2 :                 return;
     117             :         }
     118             : 
     119           6 :         arc2d_check_changes(node, stack, tr_state);
     120             : 
     121           6 :         switch (tr_state->traversing_mode) {
     122             : #ifndef GPAC_DISABLE_3D
     123           4 :         case TRAVERSE_DRAW_3D:
     124           4 :                 if (!stack->mesh) {
     125           2 :                         stack->mesh = new_mesh();
     126           2 :                         if (gf_node_get_tag(node)==TAG_X3D_Arc2D) {
     127           1 :                                 mesh_get_outline(stack->mesh, stack->path);
     128             :                         } else {
     129           1 :                                 mesh_from_path(stack->mesh, stack->path);
     130             :                         }
     131             :                 }
     132           4 :                 visual_3d_draw_2d(stack, tr_state);
     133           4 :                 return;
     134             : #endif
     135           2 :         case TRAVERSE_GET_BOUNDS:
     136           2 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
     137             : #ifndef GPAC_DISABLE_3D
     138           2 :                 gf_bbox_from_rect(&tr_state->bbox, &tr_state->bounds);
     139             : #endif
     140           2 :                 return;
     141           0 :         case TRAVERSE_PICK:
     142           0 :                 vrml_drawable_pick(stack, tr_state);
     143           0 :                 return;
     144           0 :         case TRAVERSE_SORT:
     145             : #ifndef GPAC_DISABLE_3D
     146           0 :                 if (tr_state->visual->type_3d) return;
     147             : #endif
     148           0 :                 ctx = drawable_init_context_mpeg4(stack, tr_state);
     149           0 :                 if (!ctx) return;
     150           0 :                 drawable_finalize_sort(ctx, tr_state, NULL);
     151           0 :                 return;
     152             :         }
     153             : }
     154             : 
     155           2 : void compositor_init_arc2d(GF_Compositor *compositor, GF_Node *node)
     156             : {
     157           2 :         drawable_stack_new(compositor, node);
     158           2 :         gf_node_set_callback_function(node, TraverseArc2D);
     159           2 : }
     160             : 
     161           3 : static void polyline2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
     162             : {
     163           3 :         if (gf_node_dirty_get(node)) {
     164             :                 u32 i;
     165             :                 X_Polyline2D *a = (X_Polyline2D *) node;
     166           1 :                 drawable_reset_path(stack);
     167           7 :                 for (i=0; i<a->lineSegments.count; i++) {
     168           6 :                         if (i) {
     169           5 :                                 gf_path_add_line_to(stack->path, a->lineSegments.vals[i].x, a->lineSegments.vals[i].y);
     170             :                         } else {
     171           1 :                                 gf_path_add_move_to(stack->path, a->lineSegments.vals[i].x, a->lineSegments.vals[i].y);
     172             :                         }
     173             :                 }
     174           1 :                 gf_node_dirty_clear(node, 0);
     175           1 :                 drawable_mark_modified(stack, tr_state);
     176             :         }
     177           3 : }
     178             : 
     179           4 : static void TraversePolyline2D(GF_Node *node, void *rs, Bool is_destroy)
     180             : {
     181             :         DrawableContext *ctx;
     182           4 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
     183             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     184           4 :         if (is_destroy) {
     185           1 :                 drawable_node_del(node);
     186           1 :                 return;
     187             :         }
     188             : 
     189           3 :         polyline2d_check_changes(node, stack, tr_state);
     190             : 
     191           3 :         switch (tr_state->traversing_mode) {
     192             : #ifndef GPAC_DISABLE_3D
     193           2 :         case TRAVERSE_DRAW_3D:
     194           2 :                 if (!stack->mesh) {
     195           1 :                         stack->mesh = new_mesh();
     196           1 :                         mesh_get_outline(stack->mesh, stack->path);
     197             :                 }
     198           2 :                 visual_3d_draw_2d(stack, tr_state);
     199           2 :                 return;
     200             : #endif
     201           1 :         case TRAVERSE_GET_BOUNDS:
     202           1 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
     203           1 :                 return;
     204           0 :         case TRAVERSE_PICK:
     205           0 :                 vrml_drawable_pick(stack, tr_state);
     206           0 :                 return;
     207           0 :         case TRAVERSE_SORT:
     208             : #ifndef GPAC_DISABLE_3D
     209           0 :                 if (tr_state->visual->type_3d) return;
     210             : #endif
     211           0 :                 ctx = drawable_init_context_mpeg4(stack, tr_state);
     212           0 :                 if (!ctx) return;
     213           0 :                 drawable_finalize_sort(ctx, tr_state, NULL);
     214           0 :                 return;
     215             :         }
     216             : }
     217             : 
     218           1 : void compositor_init_polyline2d(GF_Compositor *compositor, GF_Node *node)
     219             : {
     220           1 :         drawable_stack_new(compositor, node);
     221           1 :         gf_node_set_callback_function(node, TraversePolyline2D);
     222           1 : }
     223             : 
     224           4 : static void triangleset2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state)
     225             : {
     226           4 :         if (gf_node_dirty_get(node)) {
     227             :                 u32 i, count;
     228             :                 X_TriangleSet2D *p = (X_TriangleSet2D *)node;
     229           1 :                 drawable_reset_path(stack);
     230           1 :                 count = p->vertices.count;
     231           1 :                 while (count%3) count--;
     232           2 :                 for (i=0; i<count; i+=3) {
     233           2 :                         gf_path_add_move_to(stack->path, p->vertices.vals[i].x, p->vertices.vals[i].y);
     234           2 :                         gf_path_add_line_to(stack->path, p->vertices.vals[i+1].x, p->vertices.vals[i+1].y);
     235           2 :                         gf_path_add_line_to(stack->path, p->vertices.vals[i+2].x, p->vertices.vals[i+2].y);
     236           2 :                         gf_path_close(stack->path);
     237             :                 }
     238           1 :                 gf_node_dirty_clear(node, 0);
     239           1 :                 drawable_mark_modified(stack, tr_state);
     240             :         }
     241           4 : }
     242             : 
     243           5 : static void TraverseTriangleSet2D(GF_Node *node, void *rs, Bool is_destroy)
     244             : {
     245             :         DrawableContext *ctx;
     246           5 :         Drawable *stack = (Drawable *)gf_node_get_private(node);
     247             :         GF_TraverseState *tr_state = (GF_TraverseState *)rs;
     248             : 
     249           5 :         if (is_destroy) {
     250           1 :                 drawable_node_del(node);
     251           1 :                 return;
     252             :         }
     253             : 
     254           4 :         triangleset2d_check_changes(node, stack, tr_state);
     255             : 
     256           4 :         switch (tr_state->traversing_mode) {
     257             : #ifndef GPAC_DISABLE_3D
     258           3 :         case TRAVERSE_DRAW_3D:
     259           3 :                 if (!stack->mesh) {
     260             :                         SFColorRGBA col;
     261             :                         u32 i, count, idx;
     262             :                         GF_Vertex v1, v2, v3;
     263             :                         X_TriangleSet2D *p = (X_TriangleSet2D *)node;
     264             : 
     265           1 :                         stack->mesh = new_mesh();
     266           1 :                         stack->mesh->mesh_type = MESH_TRIANGLES;
     267             :                         col.red = col.green = col.blue = 0;
     268             :                         col.alpha = FIX_ONE;
     269           1 :                         v1.color = MESH_MAKE_COL(col);
     270           1 :                         v1.normal.x = v1.normal.y = 0;
     271           1 :                         v1.normal.z = MESH_NORMAL_UNIT;
     272           1 :                         v1.pos.z = 0;
     273           1 :                         v3 = v2 = v1;
     274           1 :                         count = p->vertices.count;
     275           1 :                         while (count%3) count--;
     276           2 :                         for (i=0; i<count; i+=3) {
     277           2 :                                 idx = stack->mesh->v_count;
     278           2 :                                 v1.pos.x = p->vertices.vals[i].x;
     279           2 :                                 v1.pos.y = p->vertices.vals[i].y;
     280           2 :                                 v2.pos.x = p->vertices.vals[i+1].x;
     281           2 :                                 v2.pos.y = p->vertices.vals[i+1].y;
     282           2 :                                 v3.pos.x = p->vertices.vals[i+2].x;
     283           2 :                                 v3.pos.y = p->vertices.vals[i+2].y;
     284           2 :                                 mesh_set_vertex_vx(stack->mesh, &v1);
     285           2 :                                 mesh_set_vertex_vx(stack->mesh, &v2);
     286           2 :                                 mesh_set_vertex_vx(stack->mesh, &v3);
     287           2 :                                 gf_vec_diff(v2.pos, v2.pos, v1.pos);
     288           2 :                                 gf_vec_diff(v3.pos, v3.pos, v1.pos);
     289           2 :                                 v1.pos = gf_vec_cross(v2.pos, v3.pos);
     290           2 :                                 if (v1.pos.z<0) {
     291           1 :                                         mesh_set_triangle(stack->mesh, idx, idx+2, idx+1);
     292             :                                 } else {
     293           1 :                                         mesh_set_triangle(stack->mesh, idx, idx+1, idx+2);
     294             :                                 }
     295             :                         }
     296           1 :                         stack->mesh->flags |= MESH_IS_2D;
     297           1 :                         mesh_update_bounds(stack->mesh);
     298             :                 }
     299           3 :                 visual_3d_draw_2d(stack, tr_state);
     300           3 :                 return;
     301             : #endif
     302           1 :         case TRAVERSE_GET_BOUNDS:
     303           1 :                 gf_path_get_bounds(stack->path, &tr_state->bounds);
     304           1 :                 return;
     305           0 :         case TRAVERSE_PICK:
     306           0 :                 vrml_drawable_pick(stack, tr_state);
     307           0 :                 return;
     308           0 :         case TRAVERSE_SORT:
     309             : #ifndef GPAC_DISABLE_3D
     310           0 :                 if (tr_state->visual->type_3d) return;
     311             : #endif
     312           0 :                 ctx = drawable_init_context_mpeg4(stack, tr_state);
     313           0 :                 if (!ctx) return;
     314           0 :                 drawable_finalize_sort(ctx, tr_state, NULL);
     315           0 :                 return;
     316             :         }
     317             : }
     318             : 
     319           1 : void compositor_init_triangle_set2d(GF_Compositor *compositor, GF_Node *node)
     320             : {
     321           1 :         drawable_stack_new(compositor, node);
     322           1 :         gf_node_set_callback_function(node, TraverseTriangleSet2D);
     323           1 : }
     324             : 
     325             : #ifndef GPAC_DISABLE_3D
     326             : 
     327           1 : static void build_polypoint2d(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
     328             : {
     329             :         u32 i;
     330             :         SFColorRGBA col;
     331             :         X_Polypoint2D *p = (X_Polypoint2D *)node;
     332             : 
     333           1 :         stack->mesh->mesh_type = MESH_POINTSET;
     334           1 :         col.red = col.green = col.blue = 0;
     335           1 :         col.alpha = FIX_ONE;
     336           7 :         for (i=0; i<p->point.count; i++) {
     337           6 :                 mesh_set_point(stack->mesh, p->point.vals[i].x, p->point.vals[i].y, 0, col);
     338           6 :                 mesh_set_index(stack->mesh, stack->mesh->v_count-1);
     339             :         }
     340           1 : }
     341             : 
     342           2 : static void TraversePolypoint2D(GF_Node *node, void *rs, Bool is_destroy)
     343             : {
     344           2 :         drawable_3d_base_traverse(node, rs, is_destroy, build_polypoint2d);
     345           2 : }
     346             : 
     347           1 : void compositor_init_polypoint2d(GF_Compositor *compositor, GF_Node *node)
     348             : {
     349           1 :         drawable_3d_new(node);
     350           1 :         gf_node_set_callback_function(node, TraversePolypoint2D);
     351           1 : }
     352             : 
     353           1 : static void build_line_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
     354             : {
     355             :         u32 i, j, c_idx;
     356             :         GenMFField *cols;
     357             :         GF_Vertex vx;
     358             :         Bool rgba_col;
     359             :         SFColorRGBA rgba;
     360             :         X_LineSet *p = (X_LineSet *)node;
     361           1 :         X_Coordinate *c = (X_Coordinate *) p->coord;
     362             : 
     363           1 :         stack->mesh->mesh_type = MESH_LINESET;
     364             : 
     365             :         cols = NULL;
     366             :         rgba_col = 0;
     367           1 :         if (p->color) {
     368           1 :                 if (gf_node_get_tag(p->color)==TAG_X3D_ColorRGBA) {
     369             :                         rgba_col = 1;
     370           0 :                         cols = (GenMFField *) & ((X_ColorRGBA *) p->color)->color;
     371             :                 } else {
     372           1 :                         cols = (GenMFField *) & ((M_Color *) p->color)->color;
     373             :                 }
     374             :         }
     375             :         c_idx = 0;
     376             :         memset(&vx, 0, sizeof(GF_Vertex));
     377           3 :         for (i=0; i<p->vertexCount.count; i++) {
     378           2 :                 if (p->vertexCount.vals[i]<2) continue;
     379             : 
     380           6 :                 for (j=0; j<(u32) p->vertexCount.vals[i]; j++) {
     381           7 :                         vx.pos = c->point.vals[c_idx];
     382           7 :                         if (cols && (cols->count>c_idx)) {
     383           7 :                                 if (rgba_col) {
     384           0 :                                         rgba = ((MFColorRGBA *)cols)->vals[c_idx];
     385             :                                 } else {
     386           7 :                                         rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[c_idx]);
     387             :                                 }
     388           7 :                                 vx.color = MESH_MAKE_COL(rgba);
     389             :                         }
     390           7 :                         mesh_set_vertex_vx(stack->mesh, &vx);
     391           7 :                         if (j) {
     392           5 :                                 mesh_set_index(stack->mesh, stack->mesh->v_count-2);
     393           5 :                                 mesh_set_index(stack->mesh, stack->mesh->v_count-1);
     394             :                         }
     395           7 :                         c_idx++;
     396           7 :                         if (c_idx==c->point.count) break;
     397             :                 }
     398             :         }
     399           1 :         if (cols) stack->mesh->flags |= MESH_HAS_COLOR;
     400           1 :         mesh_update_bounds(stack->mesh);
     401           1 : }
     402             : 
     403           5 : static void TraverseLineSet(GF_Node *node, void *rs, Bool is_destroy)
     404             : {
     405           5 :         drawable_3d_base_traverse(node, rs, is_destroy, build_line_set);
     406           5 : }
     407             : 
     408             : 
     409           1 : void compositor_init_lineset(GF_Compositor *compositor, GF_Node *node)
     410             : {
     411           1 :         drawable_3d_new(node);
     412           1 :         gf_node_set_callback_function(node, TraverseLineSet);
     413           1 : }
     414             : 
     415           2 : static void BuildTriangleSet(GF_Mesh *mesh, GF_Node *_coords, GF_Node *_color, GF_Node *_txcoords, GF_Node *_normal, MFInt32 *indices, Bool normalPerVertex, Bool ccw, Bool solid)
     416             : {
     417             :         u32 i, count, generate_tx;
     418             :         GF_Vertex vx;
     419             :         GenMFField *cols;
     420             :         MFVec3f *norms;
     421             :         MFVec2f *txcoords;
     422             :         Bool rgba_col;
     423             :         SFColorRGBA rgba;
     424             :         X_Coordinate *c = (X_Coordinate *) _coords;
     425             : 
     426           2 :         mesh_reset(mesh);
     427             : 
     428             :         cols = NULL;
     429             :         rgba_col = 0;
     430           2 :         if (_color) {
     431           2 :                 if (gf_node_get_tag(_color)==TAG_X3D_ColorRGBA) {
     432             :                         rgba_col = 1;
     433           0 :                         cols = (GenMFField *) & ((X_ColorRGBA *) _color)->color;
     434             :                 } else {
     435           2 :                         cols = (GenMFField *) & ((M_Color *) _color)->color;
     436             :                 }
     437             :         }
     438             :         norms = NULL;
     439           2 :         if (_normal) norms = & ((M_Normal *)_normal)->vector;
     440             :         txcoords = NULL;
     441             :         generate_tx = 0;
     442             :         /*FIXME - this can't work with multitexturing*/
     443           2 :         if (_txcoords) {
     444           0 :                 switch (gf_node_get_tag(_txcoords)) {
     445           0 :                 case TAG_X3D_TextureCoordinate:
     446             :                 case TAG_MPEG4_TextureCoordinate:
     447           0 :                         txcoords = & ((M_TextureCoordinate *)_txcoords)->point;
     448             :                         break;
     449           0 :                 case TAG_X3D_TextureCoordinateGenerator:
     450             :                         generate_tx = 1;
     451             :                         break;
     452             :                 }
     453             :         }
     454             : 
     455           2 :         if (indices) {
     456           1 :                 count = indices->count;
     457             :         } else {
     458           1 :                 count = c->point.count;
     459             :         }
     460           0 :         while (count%3) count--;
     461             :         memset(&vx, 0, sizeof(GF_Vertex));
     462          18 :         for (i=0; i<count; i++) {
     463             :                 u32 idx;
     464          18 :                 if (indices) {
     465          12 :                         if (indices->count<=i) return;
     466          12 :                         idx = indices->vals[i];
     467             :                 } else {
     468             :                         idx = i;
     469             :                 }
     470          18 :                 vx.pos = c->point.vals[idx];
     471          18 :                 if (cols && (cols->count>idx)) {
     472          18 :                         if (rgba_col) {
     473           0 :                                 rgba = ((MFColorRGBA *)cols)->vals[idx];
     474             :                         } else {
     475          18 :                                 rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[idx]);
     476             :                         }
     477          18 :                         vx.color = MESH_MAKE_COL(rgba);
     478             :                 }
     479          18 :                 if (norms && (norms->count>idx)) {
     480           0 :                         SFVec3f n = norms->vals[idx];
     481           0 :                         gf_vec_norm(&n);
     482           0 :                         MESH_SET_NORMAL(vx, n);
     483             :                 }
     484          18 :                 if (txcoords) {
     485           0 :                         if (txcoords->count>idx) vx.texcoords = txcoords->vals[idx];
     486             :                 }
     487             :                 /*X3D says nothing about default texture mapping here...*/
     488          18 :                 else if (!generate_tx) {
     489          18 :                         switch (i%3) {
     490           6 :                         case 2:
     491           6 :                                 vx.texcoords.x = FIX_ONE;
     492           6 :                                 vx.texcoords.y = 0;
     493             :                                 break;
     494           6 :                         case 1:
     495           6 :                                 vx.texcoords.x = FIX_ONE/2;
     496           6 :                                 vx.texcoords.y = FIX_ONE;
     497             :                                 break;
     498           6 :                         case 0:
     499           6 :                                 vx.texcoords.x = 0;
     500           6 :                                 vx.texcoords.y = 0;
     501             :                                 break;
     502             :                         }
     503             :                 }
     504          18 :                 mesh_set_vertex_vx(mesh, &vx);
     505             :         }
     506           6 :         for (i=0; i<mesh->v_count; i+=3) {
     507           6 :                 mesh_set_triangle(mesh, i, i+1, i+2);
     508             :         }
     509           2 :         if (generate_tx) mesh_generate_tex_coords(mesh, _txcoords);
     510             : 
     511           2 :         if (!ccw) mesh->flags |= MESH_IS_CW;
     512           2 :         if (cols) mesh->flags |= MESH_HAS_COLOR;
     513           2 :         if (rgba_col) mesh->flags |= MESH_HAS_ALPHA;
     514           2 :         if (!_normal) mesh_recompute_normals(mesh);
     515           2 :         if (solid) mesh->flags |= MESH_IS_SOLID;
     516           2 :         mesh_update_bounds(mesh);
     517           2 :         gf_mesh_build_aabbtree(mesh);
     518             : }
     519             : 
     520           1 : static void build_triangle_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
     521             : {
     522             :         X_TriangleSet *ts = (X_TriangleSet *)node;
     523           1 :         if (!ts->coord) return;
     524           1 :         BuildTriangleSet(stack->mesh, ts->coord, ts->color, ts->texCoord, ts->normal, NULL, ts->normalPerVertex, ts->ccw, ts->solid);
     525             : }
     526             : 
     527           5 : static void TraverseTriangleSet(GF_Node *node, void *rs, Bool is_destroy)
     528             : {
     529           5 :         drawable_3d_base_traverse(node, rs, is_destroy, build_triangle_set);
     530           5 : }
     531             : 
     532             : 
     533           1 : void compositor_init_triangle_set(GF_Compositor *compositor, GF_Node *node)
     534             : {
     535           1 :         drawable_3d_new(node);
     536           1 :         gf_node_set_callback_function(node, TraverseTriangleSet);
     537           1 : }
     538             : 
     539             : 
     540           1 : static void build_indexed_triangle_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
     541             : {
     542             :         X_IndexedTriangleSet *its = (X_IndexedTriangleSet*)node;
     543           1 :         if (!its->coord) return;
     544           1 :         BuildTriangleSet(stack->mesh, its->coord, its->color, its->texCoord, its->normal, &its->index, its->normalPerVertex, its->ccw, its->solid);
     545             : }
     546             : 
     547           5 : static void TraverseIndexedTriangleSet(GF_Node *node, void *rs, Bool is_destroy)
     548             : {
     549           5 :         drawable_3d_base_traverse(node, rs, is_destroy, build_indexed_triangle_set);
     550           5 : }
     551             : 
     552           0 : static void ITS_SetIndex(GF_Node *node, GF_Route *route)
     553             : {
     554           0 :         if (node) {
     555             :                 X_IndexedTriangleSet *its = (X_IndexedTriangleSet*)node;
     556           0 :                 gf_sg_vrml_field_copy(&its->index, &its->set_index, GF_SG_VRML_MFINT32);
     557           0 :                 gf_sg_vrml_mf_reset(&its->set_index, GF_SG_VRML_MFINT32);
     558             :         }
     559           0 : }
     560             : 
     561           1 : void compositor_init_indexed_triangle_set(GF_Compositor *compositor, GF_Node *node)
     562             : {
     563             :         X_IndexedTriangleSet *its = (X_IndexedTriangleSet*)node;
     564           1 :         drawable_3d_new(node);
     565           1 :         gf_node_set_callback_function(node, TraverseIndexedTriangleSet);
     566           1 :         its->on_set_index = ITS_SetIndex;
     567             : 
     568             : #ifdef GPAC_ENABLE_COVERAGE
     569           1 :         if (gf_sys_is_cov_mode()) {
     570             :                 ITS_SetIndex(NULL, NULL);
     571             :         }
     572             : #endif
     573             : 
     574           1 : }
     575             : 
     576             : 
     577           2 : static void BuildTriangleStripSet(GF_Mesh *mesh, GF_Node *_coords, GF_Node *_color, GF_Node *_txcoords, GF_Node *_normal, MFInt32 *stripList, MFInt32 *indices, Bool normalPerVertex, Bool ccw, Bool solid)
     578             : {
     579             :         u32 strip, i, cur_idx, generate_tx;
     580             :         GF_Vertex vx;
     581             :         GenMFField *cols;
     582             :         MFVec3f *norms;
     583             :         MFVec2f *txcoords;
     584             :         Bool rgba_col;
     585             :         SFColorRGBA rgba;
     586             :         X_Coordinate *c = (X_Coordinate *) _coords;
     587             : 
     588           2 :         mesh_reset(mesh);
     589             : 
     590             :         cols = NULL;
     591             :         rgba_col = 0;
     592           2 :         if (_color) {
     593           2 :                 if (gf_node_get_tag(_color)==TAG_X3D_ColorRGBA) {
     594             :                         rgba_col = 1;
     595           0 :                         cols = (GenMFField *) & ((X_ColorRGBA *) _color)->color;
     596             :                 } else {
     597           2 :                         cols = (GenMFField *) & ((M_Color *) _color)->color;
     598             :                 }
     599             :         }
     600             :         norms = NULL;
     601           2 :         if (_normal) norms = & ((M_Normal *)_normal)->vector;
     602             :         txcoords = NULL;
     603             :         generate_tx = 0;
     604             :         /*FIXME - this can't work with multitexturing*/
     605           2 :         if (_txcoords) {
     606           1 :                 switch (gf_node_get_tag(_txcoords)) {
     607           0 :                 case TAG_X3D_TextureCoordinate:
     608             :                 case TAG_MPEG4_TextureCoordinate:
     609           0 :                         txcoords = & ((M_TextureCoordinate *)_txcoords)->point;
     610           0 :                         break;
     611           1 :                 case TAG_X3D_TextureCoordinateGenerator:
     612             :                         generate_tx = 1;
     613           1 :                         break;
     614             :                 }
     615             :         }
     616             :         memset(&vx, 0, sizeof(GF_Vertex));
     617             :         cur_idx = 0;
     618           5 :         for (strip= 0; strip<stripList->count; strip++) {
     619           3 :                 u32 start_idx = mesh->v_count;
     620           3 :                 if (stripList->vals[strip] < 3) continue;
     621             : 
     622          12 :                 for (i=0; i<(u32) stripList->vals[strip]; i++) {
     623             :                         u32 idx;
     624          14 :                         if (indices) {
     625           8 :                                 if (indices->count<=cur_idx) return;
     626           8 :                                 if (indices->vals[cur_idx] == -1) {
     627           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[X3D] bad formatted X3D triangle strip\n"));
     628             :                                         return;
     629             :                                 }
     630           8 :                                 idx = indices->vals[cur_idx];
     631             :                         } else {
     632             :                                 idx = cur_idx;
     633             :                         }
     634             : 
     635          14 :                         vx.pos = c->point.vals[idx];
     636             : 
     637          14 :                         if (cols && (cols->count>idx)) {
     638          14 :                                 if (rgba_col) {
     639           0 :                                         rgba = ((MFColorRGBA *)cols)->vals[idx];
     640             :                                 } else {
     641          14 :                                         rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[idx]);
     642             :                                 }
     643          14 :                                 vx.color = MESH_MAKE_COL(rgba);
     644             :                         }
     645             :                         /*according to X3D spec, if normal field is set, it is ALWAYS as normal per vertex*/
     646          14 :                         if (norms && (norms->count>idx)) {
     647           0 :                                 SFVec3f n = norms->vals[idx];
     648           0 :                                 gf_vec_norm(&n);
     649           0 :                                 MESH_SET_NORMAL(vx, n);
     650             :                         }
     651          14 :                         if (txcoords) {
     652           0 :                                 if (txcoords->count>idx) vx.texcoords = txcoords->vals[idx];
     653             :                         }
     654             :                         /*X3D says nothing about default texture mapping here...*/
     655          14 :                         else if (!generate_tx) {
     656           6 :                                 switch (idx%3) {
     657           2 :                                 case 2:
     658           2 :                                         vx.texcoords.x = FIX_ONE;
     659           2 :                                         vx.texcoords.y = 0;
     660           2 :                                         break;
     661           2 :                                 case 1:
     662           2 :                                         vx.texcoords.x = FIX_ONE/2;
     663           2 :                                         vx.texcoords.y = FIX_ONE;
     664           2 :                                         break;
     665           2 :                                 case 0:
     666           2 :                                         vx.texcoords.x = 0;
     667           2 :                                         vx.texcoords.y = 0;
     668           2 :                                         break;
     669             :                                 }
     670             :                         }
     671          14 :                         if (i>2) {
     672             :                                 /*duplicate last 2 vertices (we really need independent vertices to handle normals per face)*/
     673           5 :                                 mesh_set_vertex_vx(mesh, &mesh->vertices[mesh->v_count-2]);
     674           5 :                                 mesh_set_vertex_vx(mesh, &mesh->vertices[mesh->v_count-2]);
     675             :                         }
     676          14 :                         mesh_set_vertex_vx(mesh, &vx);
     677             : 
     678          14 :                         cur_idx ++;
     679          14 :                         if (indices) {
     680           8 :                                 if (cur_idx>=indices->count) break;
     681           6 :                         } else if (cur_idx==c->point.count) break;
     682             : 
     683             :                 }
     684          11 :                 for (i=start_idx; i<mesh->v_count; i+=3) {
     685           8 :                         mesh_set_triangle(mesh, i, i+1, i+2);
     686             :                 }
     687             :                 /*get rid of -1*/
     688           3 :                 if (indices && (cur_idx<indices->count) && (indices->vals[cur_idx]==-1)) cur_idx++;
     689             :         }
     690           2 :         if (generate_tx) mesh_generate_tex_coords(mesh, _txcoords);
     691             : 
     692           2 :         if (cols) mesh->flags |= MESH_HAS_COLOR;
     693           2 :         if (rgba_col) mesh->flags |= MESH_HAS_ALPHA;
     694           2 :         if (_normal) {
     695           0 :                 if (!ccw) mesh->flags |= MESH_IS_CW;
     696             :         }
     697             :         /*reorder everything to CCW*/
     698             :         else {
     699             :                 u32 cur_face = 0;
     700           2 :                 mesh_recompute_normals(mesh);
     701          10 :                 for (i=0; i<mesh->i_count; i+= 3) {
     702           8 :                         if ((ccw && (cur_face%2)) || (!ccw && !(cur_face%2))) {
     703             :                                 SFVec3f v;
     704             :                                 u32 idx;
     705           4 :                                 MESH_GET_NORMAL(v, mesh->vertices[mesh->indices[i]]);
     706           4 :                                 v = gf_vec_scale(v,-1);
     707           4 :                                 MESH_SET_NORMAL(mesh->vertices[mesh->indices[i]], v);
     708           4 :                                 mesh->vertices[mesh->indices[i+1]].normal = mesh->vertices[mesh->indices[i]].normal;
     709           4 :                                 mesh->vertices[mesh->indices[i+2]].normal = mesh->vertices[mesh->indices[i]].normal;
     710           4 :                                 idx = mesh->indices[i+2];
     711           4 :                                 mesh->indices[i+2] = mesh->indices[i+1];
     712           4 :                                 mesh->indices[i+1] = idx;
     713             :                         }
     714           8 :                         cur_face++;
     715             :                 }
     716           2 :                 if (normalPerVertex) {
     717             :                         cur_face = 0;
     718           3 :                         for (strip=0; strip<stripList->count; strip++) {
     719             :                                 SFVec3f n_0, n_1, n_2, n_avg;
     720             :                                 u32 nb_face;
     721           3 :                                 if (stripList->vals[strip] < 3) continue;
     722           3 :                                 if (stripList->vals[strip] <= 3) {
     723           0 :                                         cur_face ++;
     724           0 :                                         continue;
     725             :                                 }
     726             : 
     727             :                                 /*first face normal*/
     728           3 :                                 MESH_GET_NORMAL(n_0, mesh->vertices[mesh->indices[3*cur_face]]);
     729             :                                 /*second face normal*/
     730           3 :                                 MESH_GET_NORMAL(n_1, mesh->vertices[mesh->indices[3*(cur_face+1)]]);
     731             : 
     732           3 :                                 gf_vec_add(n_avg, n_0, n_1);
     733           3 :                                 gf_vec_norm(&n_avg);
     734             :                                 /*assign to second point of first face and first of second face*/
     735           3 :                                 MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face+1]], n_avg);
     736           3 :                                 MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*(cur_face+1)]], n_avg);
     737           3 :                                 nb_face = stripList->vals[strip] - 2;
     738             :                                 cur_face++;
     739           5 :                                 for (i=1; i<nb_face-1; i++) {
     740             :                                         /*get normal (use second pt of current face since first has been updated)*/
     741           2 :                                         MESH_GET_NORMAL(n_2, mesh->vertices[mesh->indices[3*cur_face + 1]]);
     742           2 :                                         gf_vec_add(n_avg, n_0, n_1);
     743           2 :                                         gf_vec_add(n_avg, n_avg, n_2);
     744           2 :                                         gf_vec_norm(&n_avg);
     745             :                                         /*last of prev face*/
     746           2 :                                         MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face - 1]], n_avg);
     747             :                                         /*second of current face*/
     748           2 :                                         mesh->vertices[mesh->indices[3*cur_face + 1]].normal = mesh->vertices[mesh->indices[3*cur_face - 1]].normal;
     749             :                                         /*first of next face*/
     750           2 :                                         mesh->vertices[mesh->indices[3*cur_face + 3]].normal = mesh->vertices[mesh->indices[3*cur_face - 1]].normal;
     751           2 :                                         n_0 = n_1;
     752           2 :                                         n_1 = n_2;
     753             :                                         cur_face++;
     754             :                                 }
     755             :                         }
     756             :                 }
     757             :         }
     758           2 :         if (solid) mesh->flags |= MESH_IS_SOLID;
     759           2 :         mesh_update_bounds(mesh);
     760           2 :         gf_mesh_build_aabbtree(mesh);
     761             : }
     762             : 
     763           1 : static void build_triangle_strip_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
     764             : {
     765             :         X_TriangleStripSet *tss = (X_TriangleStripSet *)node;
     766           1 :         if (!tss->coord) return;
     767           1 :         BuildTriangleStripSet(stack->mesh, tss->coord, tss->color, tss->texCoord, tss->normal, &tss->stripCount, NULL, tss->normalPerVertex, tss->ccw, tss->solid);
     768             : }
     769             : 
     770           5 : static void TraverseTriangleStripSet(GF_Node *node, void *rs, Bool is_destroy)
     771             : {
     772           5 :         drawable_3d_base_traverse(node, rs, is_destroy, build_triangle_strip_set);
     773           5 : }
     774             : 
     775           1 : void compositor_init_triangle_strip_set(GF_Compositor *compositor, GF_Node *node)
     776             : {
     777           1 :         drawable_3d_new(node);
     778           1 :         gf_node_set_callback_function(node, TraverseTriangleStripSet);
     779           1 : }
     780             : 
     781           1 : static void build_indexed_triangle_strip_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
     782             : {
     783             :         MFInt32 stripList;
     784             :         u32 i, nb_strips;
     785             :         X_IndexedTriangleStripSet *itss = (X_IndexedTriangleStripSet *)node;
     786             : 
     787           1 :         if (!itss->coord) return;
     788             : 
     789           1 :         stripList.count = 0;
     790           1 :         stripList.vals = NULL;
     791             :         nb_strips = 0;
     792          10 :         for (i=0; i<itss->index.count; i++) {
     793           9 :                 if (itss->index.vals[i]==-1) {
     794           1 :                         if (nb_strips>=3) {
     795             :                                 u32 *out_nb;
     796           1 :                                 gf_sg_vrml_mf_append(&stripList, GF_SG_VRML_MFINT32, (void **) &out_nb);
     797           1 :                                 *out_nb = nb_strips;
     798             :                         }
     799             :                         nb_strips = 0;
     800             :                 } else {
     801           8 :                         nb_strips++;
     802             :                 }
     803             :         }
     804           1 :         if (nb_strips>=3) {
     805             :                 u32 *out_nb;
     806           1 :                 gf_sg_vrml_mf_append(&stripList, GF_SG_VRML_MFINT32, (void **) &out_nb);
     807           1 :                 *out_nb = nb_strips;
     808             :         }
     809           1 :         BuildTriangleStripSet(stack->mesh, itss->coord, itss->color, itss->texCoord, itss->normal, &stripList, &itss->index, itss->normalPerVertex, itss->ccw, itss->solid);
     810           1 :         gf_sg_vrml_mf_reset(&stripList, GF_SG_VRML_MFINT32);
     811             : }
     812             : 
     813           5 : static void TraverseIndexedTriangleStripSet(GF_Node *node, void *rs, Bool is_destroy)
     814             : {
     815           5 :         drawable_3d_base_traverse(node, rs, is_destroy, build_indexed_triangle_strip_set);
     816           5 : }
     817             : 
     818           0 : static void ITSS_SetIndex(GF_Node *node, GF_Route *route)
     819             : {
     820           0 :         if (node) {
     821             :                 X_IndexedTriangleStripSet *itss = (X_IndexedTriangleStripSet*)node;
     822           0 :                 gf_sg_vrml_field_copy(&itss->index, &itss->set_index, GF_SG_VRML_MFINT32);
     823           0 :                 gf_sg_vrml_mf_reset(&itss->set_index, GF_SG_VRML_MFINT32);
     824             :         }
     825           0 : }
     826             : 
     827           1 : void compositor_init_indexed_triangle_strip_set(GF_Compositor *compositor, GF_Node *node)
     828             : {
     829             :         X_IndexedTriangleStripSet *itss = (X_IndexedTriangleStripSet*)node;
     830           1 :         drawable_3d_new(node);
     831           1 :         gf_node_set_callback_function(node, TraverseIndexedTriangleStripSet);
     832           1 :         itss->on_set_index = ITSS_SetIndex;
     833             : 
     834             : #ifdef GPAC_ENABLE_COVERAGE
     835           1 :         if (gf_sys_is_cov_mode()) {
     836             :                 ITSS_SetIndex(NULL, NULL);
     837             :         }
     838             : #endif
     839           1 : }
     840             : 
     841             : 
     842           2 : static void BuildTriangleFanSet(GF_Mesh *mesh, GF_Node *_coords, GF_Node *_color, GF_Node *_txcoords, GF_Node *_normal, MFInt32 *fanList, MFInt32 *indices, Bool normalPerVertex, Bool ccw, Bool solid)
     843             : {
     844             :         u32 fan, i, cur_idx, generate_tx;
     845             :         GF_Vertex vx;
     846             :         GenMFField *cols;
     847             :         MFVec3f *norms;
     848             :         MFVec2f *txcoords;
     849             :         Bool rgba_col;
     850             :         SFColorRGBA rgba;
     851             :         X_Coordinate *c = (X_Coordinate *) _coords;
     852           2 :         mesh_reset(mesh);
     853             : 
     854             :         cols = NULL;
     855             :         rgba_col = 0;
     856           2 :         if (_color) {
     857           2 :                 if (gf_node_get_tag(_color)==TAG_X3D_ColorRGBA) {
     858             :                         rgba_col = 1;
     859           0 :                         cols = (GenMFField *) & ((X_ColorRGBA *) _color)->color;
     860             :                 } else {
     861           2 :                         cols = (GenMFField *) & ((M_Color *) _color)->color;
     862             :                 }
     863             :         }
     864             :         norms = NULL;
     865           2 :         if (_normal) norms = & ((M_Normal *)_normal)->vector;
     866             :         txcoords = NULL;
     867             :         generate_tx = 0;
     868             :         /*FIXME - this can't work with multitexturing*/
     869           2 :         if (_txcoords) {
     870           0 :                 switch (gf_node_get_tag(_txcoords)) {
     871           0 :                 case TAG_X3D_TextureCoordinate:
     872             :                 case TAG_MPEG4_TextureCoordinate:
     873           0 :                         txcoords = & ((M_TextureCoordinate *)_txcoords)->point;
     874           0 :                         break;
     875           0 :                 case TAG_X3D_TextureCoordinateGenerator:
     876             :                         generate_tx = 1;
     877           0 :                         break;
     878             :                 }
     879             :         }
     880             : 
     881             :         memset(&vx, 0, sizeof(GF_Vertex));
     882             :         cur_idx = 0;
     883           5 :         for (fan= 0; fan<fanList->count; fan++) {
     884           3 :                 u32 start_idx = mesh->v_count;
     885           3 :                 if (fanList->vals[fan] < 3) continue;
     886             : 
     887          13 :                 for (i=0; i<(u32) fanList->vals[fan]; i++) {
     888             :                         u32 idx;
     889          15 :                         if (indices) {
     890           8 :                                 if (indices->count<=cur_idx) return;
     891           8 :                                 if (indices->vals[cur_idx] == -1) {
     892           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[X3D] bad formatted X3D triangle set\n"));
     893             :                                         return;
     894             :                                 }
     895           8 :                                 idx = indices->vals[cur_idx];
     896             :                         } else {
     897             :                                 idx = cur_idx;
     898             :                         }
     899          15 :                         vx.pos = c->point.vals[idx];
     900             : 
     901          15 :                         if (cols && (cols->count>idx)) {
     902          15 :                                 if (rgba_col) {
     903           0 :                                         rgba = ((MFColorRGBA *)cols)->vals[idx];
     904             :                                 } else {
     905          15 :                                         rgba = gf_sg_sfcolor_to_rgba( ((MFColor *)cols)->vals[idx]);
     906             :                                 }
     907          15 :                                 vx.color = MESH_MAKE_COL(rgba);
     908             :                         }
     909             :                         /*according to X3D spec, if normal field is set, it is ALWAYS as normal per vertex*/
     910          15 :                         if (norms && (norms->count>idx)) {
     911           0 :                                 SFVec3f n = norms->vals[idx];
     912           0 :                                 gf_vec_norm(&n);
     913           0 :                                 MESH_SET_NORMAL(vx, n);
     914             :                         }
     915          15 :                         if (txcoords) {
     916           0 :                                 if (txcoords->count>idx) vx.texcoords = txcoords->vals[idx];
     917             :                         }
     918             :                         /*X3D says nothing about default texture mapping here...*/
     919          15 :                         else if (!generate_tx) {
     920          15 :                                 switch (idx%3) {
     921           4 :                                 case 2:
     922           4 :                                         vx.texcoords.x = FIX_ONE;
     923           4 :                                         vx.texcoords.y = 0;
     924           4 :                                         break;
     925           4 :                                 case 1:
     926           4 :                                         vx.texcoords.x = FIX_ONE/2;
     927           4 :                                         vx.texcoords.y = FIX_ONE;
     928           4 :                                         break;
     929           7 :                                 case 0:
     930           7 :                                         vx.texcoords.x = 0;
     931           7 :                                         vx.texcoords.y = 0;
     932           7 :                                         break;
     933             :                                 }
     934             :                         }
     935          15 :                         mesh_set_vertex_vx(mesh, &vx);
     936             : 
     937          15 :                         cur_idx ++;
     938          15 :                         if (indices) {
     939           8 :                                 if (cur_idx>=indices->count) break;
     940           7 :                         } else if (cur_idx==c->point.count) break;
     941             : 
     942          13 :                         if (i>1) {
     943           7 :                                 mesh_set_vertex_vx(mesh, &mesh->vertices[start_idx]);
     944           7 :                                 mesh_set_vertex_vx(mesh, &vx);
     945             :                         }
     946             :                 }
     947          13 :                 for (i=start_idx; i<mesh->v_count; i+=3) {
     948          10 :                         mesh_set_triangle(mesh, i, i+1, i+2);
     949             :                 }
     950             :                 /*get rid of -1*/
     951           3 :                 if (indices && (cur_idx<indices->count) && (indices->vals[cur_idx]==-1)) cur_idx++;
     952             :         }
     953           2 :         if (generate_tx) mesh_generate_tex_coords(mesh, _txcoords);
     954             : 
     955           2 :         if (cols) mesh->flags |= MESH_HAS_COLOR;
     956           2 :         if (rgba_col) mesh->flags |= MESH_HAS_ALPHA;
     957           2 :         if (!ccw) mesh->flags |= MESH_IS_CW;
     958           2 :         if (!_normal) {
     959           2 :                 mesh_recompute_normals(mesh);
     960           2 :                 if (normalPerVertex) {
     961             :                         u32 cur_face = 0;
     962           3 :                         for (fan=0; fan<fanList->count; fan++) {
     963             :                                 SFVec3f n_0, n_1, n_avg, n_tot;
     964             :                                 u32 nb_face, start_face;
     965           3 :                                 if (fanList->vals[fan] < 3) continue;
     966           3 :                                 if (fanList->vals[fan] == 3) {
     967           0 :                                         cur_face++;
     968           0 :                                         continue;
     969             :                                 }
     970             : 
     971             :                                 start_face = cur_face;
     972             : 
     973             :                                 /*first face normal*/
     974           3 :                                 MESH_GET_NORMAL(n_0, mesh->vertices[mesh->indices[3*cur_face]]);
     975           3 :                                 n_tot = n_0;
     976           3 :                                 cur_face++;
     977           3 :                                 nb_face = fanList->vals[fan] - 2;
     978           9 :                                 for (i=1; i<nb_face; i++) {
     979           6 :                                         MESH_GET_NORMAL(n_1, mesh->vertices[mesh->indices[3*cur_face + 1]]);
     980           6 :                                         gf_vec_add(n_avg, n_0, n_1);
     981           6 :                                         gf_vec_norm(&n_avg);
     982           6 :                                         MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*cur_face + 1]], n_avg);
     983           6 :                                         gf_vec_add(n_tot, n_tot, n_1);
     984           6 :                                         n_0 = n_1;
     985           6 :                                         cur_face++;
     986             :                                 }
     987             :                                 /*and assign center normal*/
     988           3 :                                 gf_vec_norm(&n_tot);
     989          12 :                                 for (i=0; i<nb_face; i++) {
     990           9 :                                         MESH_SET_NORMAL(mesh->vertices[mesh->indices[3*(i+start_face)]], n_tot);
     991             :                                 }
     992             :                         }
     993             :                 }
     994             :         }
     995           2 :         if (solid) mesh->flags |= MESH_IS_SOLID;
     996           2 :         mesh_update_bounds(mesh);
     997           2 :         gf_mesh_build_aabbtree(mesh);
     998             : }
     999             : 
    1000           1 : static void build_triangle_fan_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
    1001             : {
    1002             :         X_TriangleFanSet *tfs = (X_TriangleFanSet *)node;
    1003           1 :         if (!tfs->coord) return;
    1004           1 :         BuildTriangleFanSet(stack->mesh, tfs->coord, tfs->color, tfs->texCoord, tfs->normal, &tfs->fanCount, NULL, tfs->normalPerVertex, tfs->ccw, tfs->solid);
    1005             : }
    1006             : 
    1007           5 : static void TraverseTriangleFanSet(GF_Node *node, void *rs, Bool is_destroy)
    1008             : {
    1009           5 :         drawable_3d_base_traverse(node, rs, is_destroy, build_triangle_fan_set);
    1010           5 : }
    1011             : 
    1012           1 : void compositor_init_triangle_fan_set(GF_Compositor *compositor, GF_Node *node)
    1013             : {
    1014           1 :         drawable_3d_new(node);
    1015           1 :         gf_node_set_callback_function(node, TraverseTriangleFanSet);
    1016           1 : }
    1017             : 
    1018           1 : static void build_indexed_triangle_fan_set(GF_Node *node, Drawable3D *stack, GF_TraverseState *tr_state)
    1019             : {
    1020             :         MFInt32 fanList;
    1021             :         u32 i, nb_fans;
    1022             :         X_IndexedTriangleFanSet *itfs = (X_IndexedTriangleFanSet *)node;
    1023           1 :         gf_node_dirty_clear(node, 0);
    1024           1 :         if (!itfs->coord) return;
    1025             : 
    1026           1 :         fanList.count = 0;
    1027           1 :         fanList.vals = NULL;
    1028             :         nb_fans = 0;
    1029          10 :         for (i=0; i<itfs->index.count; i++) {
    1030           9 :                 if (itfs->index.vals[i]==-1) {
    1031           1 :                         if (nb_fans>=3) {
    1032             :                                 u32 *out_nb;
    1033           1 :                                 gf_sg_vrml_mf_append(&fanList, GF_SG_VRML_MFINT32, (void **) &out_nb);
    1034           1 :                                 *out_nb = nb_fans;
    1035             :                         }
    1036             :                         nb_fans = 0;
    1037             :                 } else {
    1038           8 :                         nb_fans++;
    1039             :                 }
    1040             :         }
    1041           1 :         if (nb_fans>=3) {
    1042             :                 u32 *out_nb;
    1043           1 :                 gf_sg_vrml_mf_append(&fanList, GF_SG_VRML_MFINT32, (void **) &out_nb);
    1044           1 :                 *out_nb = nb_fans;
    1045             :         }
    1046           1 :         BuildTriangleFanSet(stack->mesh, itfs->coord, itfs->color, itfs->texCoord, itfs->normal, &fanList, &itfs->index, itfs->normalPerVertex, itfs->ccw, itfs->solid);
    1047           1 :         gf_sg_vrml_mf_reset(&fanList, GF_SG_VRML_MFINT32);
    1048             : }
    1049             : 
    1050           5 : static void TraverseIndexedTriangleFanSet(GF_Node *node, void *rs, Bool is_destroy)
    1051             : {
    1052           5 :         drawable_3d_base_traverse(node, rs, is_destroy, build_indexed_triangle_fan_set);
    1053           5 : }
    1054             : 
    1055           0 : static void ITFS_SetIndex(GF_Node *node, GF_Route *route)
    1056             : {
    1057           0 :         if (node) {
    1058             :                 X_IndexedTriangleFanSet *itfs = (X_IndexedTriangleFanSet *)node;
    1059           0 :                 gf_sg_vrml_field_copy(&itfs->index, &itfs->set_index, GF_SG_VRML_MFINT32);
    1060           0 :                 gf_sg_vrml_mf_reset(&itfs->set_index, GF_SG_VRML_MFINT32);
    1061             :         }
    1062           0 : }
    1063             : 
    1064           1 : void compositor_init_indexed_triangle_fan_set(GF_Compositor *compositor, GF_Node *node)
    1065             : {
    1066             :         X_IndexedTriangleFanSet *itfs = (X_IndexedTriangleFanSet *)node;
    1067           1 :         drawable_3d_new(node);
    1068           1 :         gf_node_set_callback_function(node, TraverseIndexedTriangleFanSet);
    1069           1 :         itfs->on_set_index = ITFS_SetIndex;
    1070             : 
    1071             : #ifdef GPAC_ENABLE_COVERAGE
    1072           1 :         if (gf_sys_is_cov_mode()) {
    1073             :                 ITFS_SetIndex(NULL, NULL);
    1074             :         }
    1075             : #endif
    1076           1 : }
    1077             : 
    1078             : #endif /*GPAC_DISABLE_3D*/
    1079             : 
    1080             : #endif /*GPAC_DISABLE_X3D*/

Generated by: LCOV version 1.13