LCOV - code coverage report
Current view: top level - compositor - mesh.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 1037 1231 84.2 %
Date: 2021-04-29 23:48:07 Functions: 41 42 97.6 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2012
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / Scene Compositor sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #include <gpac/internal/mesh.h>
      27             : 
      28             : #include <gpac/nodes_mpeg4.h>
      29             : #include <gpac/nodes_x3d.h>
      30             : #include <gpac/color.h>
      31             : 
      32             : #ifndef GPAC_DISABLE_3D
      33             : 
      34             : 
      35             : /*for GPAC_HAS_GLU and glDeleteBuffersARB */
      36             : #include "gl_inc.h"
      37             : 
      38             : /*when highspeeds, amount of subdivisions for bezier and ellipse will be devided by this factor*/
      39             : #define HIGH_SPEED_RATIO        2
      40             : 
      41             : 
      42             : /*size alloc for meshes doubles memory at each gf_realloc rather than using a fix-size increment
      43             :  (this really speeds up large meshes constructing). Final memory usage is adjusted when updating mesh bounds
      44             : */
      45             : #define MESH_CHECK_VERTEX(m)            \
      46             :         if (m->v_count == m->v_alloc) {   \
      47             :                 m->v_alloc *= 2;     \
      48             :                 m->vertices = (GF_Vertex *)gf_realloc(m->vertices, sizeof(GF_Vertex)*m->v_alloc);      \
      49             :         }       \
      50             :  
      51             : #define MESH_CHECK_IDX(m)               \
      52             :         if (m->i_count == m->i_alloc) {   \
      53             :                 m->i_alloc *= 2;     \
      54             :                 m->indices = (IDX_TYPE*)gf_realloc(m->indices, sizeof(IDX_TYPE)*m->i_alloc);   \
      55             :         }       \
      56             :  
      57             : 
      58             : 
      59      100707 : static void del_aabb_node(AABBNode *node)
      60             : {
      61      100707 :         if (node->pos) del_aabb_node(node->pos);
      62      100707 :         if (node->neg) del_aabb_node(node->neg);
      63      100707 :         gf_free(node);
      64      100707 : }
      65             : 
      66        4301 : void mesh_reset(GF_Mesh *mesh)
      67             : {
      68        4301 :         mesh->v_count = 0;
      69        4301 :         mesh->i_count = 0;
      70        4301 :         mesh->flags = 0;
      71        4301 :         mesh->mesh_type = 0;
      72        4301 :         memset(&mesh->bounds.min_edge, 0, sizeof(SFVec3f));
      73        4301 :         memset(&mesh->bounds.max_edge, 0, sizeof(SFVec3f));
      74        4301 :         if (mesh->aabb_root) del_aabb_node(mesh->aabb_root);
      75        4301 :         mesh->aabb_root = NULL;
      76        4301 :         if (mesh->aabb_indices) gf_free(mesh->aabb_indices);
      77        4301 :         mesh->aabb_indices = NULL;
      78             : 
      79             : 
      80        4301 :         if (mesh->vbo) {
      81         149 :                 glDeleteBuffers(1, &mesh->vbo);
      82         149 :                 mesh->vbo = 0;
      83             :         }
      84        4301 :         if (mesh->vbo_idx) {
      85         149 :                 glDeleteBuffers(1, &mesh->vbo_idx);
      86         149 :                 mesh->vbo_idx = 0;
      87             :         }
      88        4301 : }
      89             : 
      90       22237 : void mesh_free(GF_Mesh *mesh)
      91             : {
      92       22237 :         if (mesh->vertices) gf_free(mesh->vertices);
      93       22237 :         if (mesh->indices) gf_free(mesh->indices);
      94       22237 :         if (mesh->aabb_root) del_aabb_node(mesh->aabb_root);
      95       22237 :         mesh->aabb_root = NULL;
      96       22237 :         if (mesh->aabb_indices) gf_free(mesh->aabb_indices);
      97       22237 :         gf_free(mesh);
      98       22237 : }
      99             : 
     100       22240 : GF_Mesh *new_mesh()
     101             : {
     102       22240 :         GF_Mesh *mesh = (GF_Mesh *)gf_malloc(sizeof(GF_Mesh));
     103       22240 :         if (mesh) {
     104             :                 memset(mesh, 0, sizeof(GF_Mesh));
     105       22240 :                 mesh->v_alloc = 8;
     106       22240 :                 mesh->vertices = (GF_Vertex*)gf_malloc(sizeof(GF_Vertex)*mesh->v_alloc);
     107       22240 :                 mesh->i_alloc = 8;
     108       22240 :                 mesh->indices = (IDX_TYPE*)gf_malloc(sizeof(IDX_TYPE)*mesh->i_alloc);
     109             :         }
     110       22240 :         return mesh;
     111             : }
     112             : 
     113         648 : static void mesh_fit_alloc(GF_Mesh *m)
     114             : {
     115         648 :         if (m->v_count && (m->v_count < m->v_alloc)) {
     116         441 :                 m->v_alloc = m->v_count;
     117         441 :                 m->vertices = (GF_Vertex *)gf_realloc(m->vertices, sizeof(GF_Vertex)*m->v_alloc);
     118             :         }
     119         648 :         if (m->i_count && (m->i_count  < m->i_alloc)) {
     120         431 :                 m->i_alloc = m->i_count;
     121         431 :                 m->indices = (IDX_TYPE*)gf_realloc(m->indices, sizeof(IDX_TYPE)*m->i_alloc);
     122             :         }
     123         648 : }
     124             : 
     125             : 
     126         648 : void mesh_update_bounds(GF_Mesh *mesh)
     127             : {
     128             :         u32 i;
     129             :         Fixed mx, my, mz, Mx, My, Mz;
     130             :         mx = my = mz = FIX_MAX;
     131             :         Mx = My = Mz = FIX_MIN;
     132             : 
     133         648 :         mesh_fit_alloc(mesh);
     134             : 
     135      646228 :         for (i=0; i<mesh->v_count; i++) {
     136      645580 :                 SFVec3f *v = &mesh->vertices[i].pos;
     137      645580 :                 if (mx>v->x) mx=v->x;
     138      645580 :                 if (my>v->y) my=v->y;
     139      645580 :                 if (mz>v->z) mz=v->z;
     140      645580 :                 if (Mx<v->x) Mx=v->x;
     141      645580 :                 if (My<v->y) My=v->y;
     142      645580 :                 if (Mz<v->z) Mz=v->z;
     143             :         }
     144         648 :         mesh->bounds.min_edge.x = mx;
     145         648 :         mesh->bounds.min_edge.y = my;
     146         648 :         mesh->bounds.min_edge.z = mz;
     147         648 :         mesh->bounds.max_edge.x = Mx;
     148         648 :         mesh->bounds.max_edge.y = My;
     149         648 :         mesh->bounds.max_edge.z = Mz;
     150         648 :         gf_bbox_refresh(&mesh->bounds);
     151         648 : }
     152             : 
     153         156 : void mesh_clone(GF_Mesh *dest, GF_Mesh *orig)
     154             : {
     155         156 :         if (dest->v_alloc<orig->v_alloc) {
     156           1 :                 dest->v_alloc = orig->v_alloc;
     157           1 :                 dest->vertices = (GF_Vertex *)gf_realloc(dest->vertices, sizeof(GF_Vertex)*dest->v_alloc);
     158             :         }
     159         156 :         dest->v_count = orig->v_count;
     160         156 :         memcpy(dest->vertices, orig->vertices, sizeof(GF_Vertex)*dest->v_count);
     161             : 
     162         156 :         if (dest->i_alloc < orig->i_alloc) {
     163           1 :                 dest->i_alloc = orig->i_alloc;
     164           1 :                 dest->indices = (IDX_TYPE*)gf_realloc(dest->indices, sizeof(IDX_TYPE)*dest->i_alloc);
     165             :         }
     166         156 :         dest->i_count = orig->i_count;
     167         156 :         memcpy(dest->indices, orig->indices, sizeof(IDX_TYPE)*dest->i_count);
     168             : 
     169         156 :         dest->mesh_type = orig->mesh_type;
     170         156 :         dest->flags = orig->flags;
     171         156 :         dest->bounds = orig->bounds;
     172             :         /*and reset AABB*/
     173         156 :         if (dest->aabb_root) del_aabb_node(dest->aabb_root);
     174         156 :         dest->aabb_root = NULL;
     175         156 :         if (dest->aabb_indices) gf_free(dest->aabb_indices);
     176         156 :         dest->aabb_indices = NULL;
     177         156 : }
     178             : 
     179             : 
     180      141064 : static GFINLINE GF_Vertex set_vertex(Fixed x, Fixed y, Fixed z, Fixed nx, Fixed ny, Fixed nz, Fixed u, Fixed v)
     181             : {
     182             :         SFVec3f nor;
     183             :         GF_Vertex res;
     184             :         res.pos.x = x;
     185             :         res.pos.y = y;
     186             :         res.pos.z = z;
     187      141064 :         nor.x = nx;
     188      141064 :         nor.y = ny;
     189      141064 :         nor.z = nz;
     190      141064 :         gf_vec_norm(&nor);
     191      141064 :         MESH_SET_NORMAL(res, nor);
     192             : 
     193             :         res.texcoords.x = u;
     194             :         res.texcoords.y = v;
     195             : #ifdef MESH_USE_SFCOLOR
     196             :         res.color.blue = res.color.red = res.color.green = res.color.alpha = FIX_ONE;
     197             : #else
     198             :         res.color = 0xFFFFFFFF;
     199             : #endif
     200      141064 :         return res;
     201             : }
     202      141064 : void mesh_set_vertex(GF_Mesh *mesh, Fixed x, Fixed y, Fixed z, Fixed nx, Fixed ny, Fixed nz, Fixed u, Fixed v)
     203             : {
     204      141064 :         MESH_CHECK_VERTEX(mesh);
     205      141064 :         mesh->vertices[mesh->v_count] = set_vertex(x, y, z, nx, ny, nz, u, v);
     206      141064 :         mesh->v_count++;
     207      141064 : }
     208             : 
     209       41732 : void mesh_set_vertex_v(GF_Mesh *mesh, SFVec3f pt, SFVec3f nor, SFVec2f tx, SFColorRGBA col)
     210             : {
     211       41732 :         if (!mesh) return;
     212       41732 :         MESH_CHECK_VERTEX(mesh);
     213       41732 :         if (!mesh->vertices) return;
     214       41732 :         mesh->vertices[mesh->v_count].pos = pt;
     215       41732 :         mesh->vertices[mesh->v_count].texcoords = tx;
     216       41732 :         mesh->vertices[mesh->v_count].color = MESH_MAKE_COL(col);
     217       41732 :         gf_vec_norm(&nor);
     218       41732 :         MESH_SET_NORMAL(mesh->vertices[mesh->v_count], nor);
     219       41732 :         mesh->v_count++;
     220             : }
     221             : 
     222       92838 : void mesh_set_vertex_vx(GF_Mesh *mesh, GF_Vertex *vx)
     223             : {
     224       92838 :         MESH_CHECK_VERTEX(mesh);
     225       92838 :         mesh->vertices[mesh->v_count] = *vx;
     226       92838 :         mesh->v_count++;
     227       92838 : }
     228             : 
     229       12568 : void mesh_set_point(GF_Mesh *mesh, Fixed x, Fixed y, Fixed z, SFColorRGBA col)
     230             : {
     231       12568 :         MESH_CHECK_VERTEX(mesh);
     232       12568 :         mesh->vertices[mesh->v_count].pos.x = x;
     233       12568 :         mesh->vertices[mesh->v_count].pos.y = y;
     234       12568 :         mesh->vertices[mesh->v_count].pos.z = z;
     235       12568 :         mesh->vertices[mesh->v_count].normal.x = mesh->vertices[mesh->v_count].normal.y = mesh->vertices[mesh->v_count].normal.z = 0;
     236       12568 :         mesh->vertices[mesh->v_count].texcoords.x = mesh->vertices[mesh->v_count].texcoords.y = 0;
     237       12568 :         mesh->vertices[mesh->v_count].color = MESH_MAKE_COL(col);
     238       12568 :         mesh->v_count++;
     239       12568 : }
     240      568611 : void mesh_set_index(GF_Mesh *mesh, u32 idx)
     241             : {
     242      568611 :         MESH_CHECK_IDX(mesh);
     243      568611 :         mesh->indices[mesh->i_count] = (IDX_TYPE) idx;
     244      568611 :         mesh->i_count++;
     245      568611 : }
     246      126821 : void mesh_set_triangle(GF_Mesh *mesh, u32 v1_idx, u32 v2_idx, u32 v3_idx)
     247             : {
     248      126821 :         mesh_set_index(mesh, v1_idx);
     249      126821 :         mesh_set_index(mesh, v2_idx);
     250      126821 :         mesh_set_index(mesh, v3_idx);
     251      126821 : }
     252           0 : void mesh_set_line(GF_Mesh *mesh, u32 v1_idx, u32 v2_idx)
     253             : {
     254        7449 :         mesh_set_index(mesh, v1_idx);
     255        7449 :         mesh_set_index(mesh, v2_idx);
     256           0 : }
     257             : 
     258           6 : void mesh_recompute_normals(GF_Mesh *mesh)
     259             : {
     260             :         u32 i;
     261           6 :         if (mesh->mesh_type) return;
     262             : 
     263          24 :         for (i=0; i<mesh->i_count; i+=3) {
     264             :                 SFVec3f v1, v2, v3;
     265          24 :                 gf_vec_diff(v1, mesh->vertices[mesh->indices[i+1]].pos, mesh->vertices[mesh->indices[i]].pos);
     266          24 :                 gf_vec_diff(v2, mesh->vertices[mesh->indices[i+2]].pos, mesh->vertices[mesh->indices[i]].pos);
     267          24 :                 v3 = gf_vec_cross(v1, v2);
     268          24 :                 gf_vec_norm(&v3);
     269          24 :                 MESH_SET_NORMAL(mesh->vertices[mesh->indices[i]], v3);
     270          24 :                 MESH_SET_NORMAL(mesh->vertices[mesh->indices[i+1]], v3);
     271          24 :                 MESH_SET_NORMAL(mesh->vertices[mesh->indices[i+2]], v3);
     272             :         }
     273             : }
     274             : 
     275             : #if !defined(GPAC_DISABLE_VRML) && !defined(GPAC_DISABLE_X3D)
     276           1 : void mesh_generate_tex_coords(GF_Mesh *mesh, GF_Node *__texCoords)
     277             : {
     278             :         u32 i;
     279             :         X_TextureCoordinateGenerator *txgen = (X_TextureCoordinateGenerator *)__texCoords;
     280             : 
     281           1 :         if (!strcmp(txgen->mode.buffer, "SPHERE-LOCAL")) {
     282           0 :                 for (i=0; i<mesh->v_count; i++) {
     283           0 :                         GF_Vertex *vx = &mesh->vertices[i];
     284           0 :                         vx->texcoords.x = (vx->normal.x+FIX_ONE) / 2;
     285           0 :                         vx->texcoords.y = (vx->normal.y+FIX_ONE) / 2;
     286             :                 }
     287             :         }
     288           1 :         else if (!strcmp(txgen->mode.buffer, "COORD")) {
     289          12 :                 for (i=0; i<mesh->v_count; i++) {
     290          12 :                         GF_Vertex *vx = &mesh->vertices[i];
     291          12 :                         vx->texcoords.x = vx->pos.x;
     292          12 :                         vx->texcoords.y = vx->pos.y;
     293             :                 }
     294             :         }
     295           1 : }
     296             : #endif /*GPAC_DISABLE_VRML*/
     297             : 
     298             : 
     299          54 : void mesh_new_box(GF_Mesh *mesh, SFVec3f size)
     300             : {
     301          54 :         Fixed hx = size.x / 2;
     302          54 :         Fixed hy = size.y / 2;
     303          54 :         Fixed hz = size.z / 2;
     304             : 
     305          54 :         mesh_reset(mesh);
     306             :         /*back face (horiz flip of texcoords)*/
     307          54 :         mesh_set_vertex(mesh,  hx, -hy, -hz,  0,  0, -FIX_ONE, 0, 0);
     308          54 :         mesh_set_vertex(mesh, -hx, -hy, -hz,  0,  0, -FIX_ONE, FIX_ONE, 0);
     309          54 :         mesh_set_vertex(mesh, -hx,  hy, -hz,  0,  0, -FIX_ONE, FIX_ONE, FIX_ONE);
     310          54 :         mesh_set_vertex(mesh,  hx,  hy, -hz,  0,  0, -FIX_ONE, 0, FIX_ONE);
     311          54 :         mesh_set_triangle(mesh, 0, 1, 2);
     312          54 :         mesh_set_triangle(mesh, 0, 2, 3);
     313             :         /*top face*/
     314          54 :         mesh_set_vertex(mesh, -hx,  hy,  hz,  0,  FIX_ONE,  0, 0, 0);
     315          54 :         mesh_set_vertex(mesh,  hx,  hy,  hz,  0,  FIX_ONE,  0, FIX_ONE, 0);
     316          54 :         mesh_set_vertex(mesh,  hx,  hy, -hz,  0,  FIX_ONE,  0, FIX_ONE, FIX_ONE);
     317          54 :         mesh_set_vertex(mesh, -hx,  hy, -hz,  0,  FIX_ONE,  0, 0, FIX_ONE);
     318          54 :         mesh_set_triangle(mesh, 4, 5, 6);
     319          54 :         mesh_set_triangle(mesh, 4, 6, 7);
     320             :         /*front face*/
     321          54 :         mesh_set_vertex(mesh, -hx, -hy,  hz,  0,  0,  FIX_ONE, 0, 0);
     322          54 :         mesh_set_vertex(mesh,  hx, -hy,  hz,  0,  0,  FIX_ONE, FIX_ONE, 0);
     323          54 :         mesh_set_vertex(mesh,  hx,  hy,  hz,  0,  0,  FIX_ONE, FIX_ONE, FIX_ONE);
     324          54 :         mesh_set_vertex(mesh, -hx,  hy,  hz,  0,  0,  FIX_ONE, 0, FIX_ONE);
     325          54 :         mesh_set_triangle(mesh, 8, 9, 10);
     326          54 :         mesh_set_triangle(mesh, 8, 10, 11);
     327             :         /*left face*/
     328          54 :         mesh_set_vertex(mesh, -hx, -hy, -hz, -FIX_ONE,  0,  0, 0, 0);
     329          54 :         mesh_set_vertex(mesh, -hx, -hy,  hz, -FIX_ONE,  0,  0, FIX_ONE, 0);
     330          54 :         mesh_set_vertex(mesh, -hx,  hy,  hz, -FIX_ONE,  0,  0, FIX_ONE, FIX_ONE);
     331          54 :         mesh_set_vertex(mesh, -hx,  hy, -hz, -FIX_ONE,  0,  0, 0, FIX_ONE);
     332          54 :         mesh_set_triangle(mesh, 12, 13, 14);
     333          54 :         mesh_set_triangle(mesh, 12, 14, 15);
     334             :         /*bottom face*/
     335          54 :         mesh_set_vertex(mesh, -hx, -hy, -hz,  0, -FIX_ONE,  0, 0, 0);
     336          54 :         mesh_set_vertex(mesh,  hx, -hy, -hz,  0, -FIX_ONE,  0, FIX_ONE, 0);
     337          54 :         mesh_set_vertex(mesh,  hx, -hy,  hz,  0, -FIX_ONE,  0, FIX_ONE, FIX_ONE);
     338          54 :         mesh_set_vertex(mesh, -hx, -hy,  hz,  0, -FIX_ONE,  0, 0, FIX_ONE);
     339          54 :         mesh_set_triangle(mesh, 16, 17, 18);
     340          54 :         mesh_set_triangle(mesh, 16, 18, 19);
     341             :         /*right face*/
     342          54 :         mesh_set_vertex(mesh,  hx, -hy,  hz,  FIX_ONE,  0,  0, 0, 0);
     343          54 :         mesh_set_vertex(mesh,  hx, -hy, -hz,  FIX_ONE,  0,  0, FIX_ONE, 0);
     344          54 :         mesh_set_vertex(mesh,  hx,  hy, -hz,  FIX_ONE,  0,  0, FIX_ONE, FIX_ONE);
     345          54 :         mesh_set_vertex(mesh,  hx,  hy,  hz,  FIX_ONE,  0,  0, 0, FIX_ONE);
     346          54 :         mesh_set_triangle(mesh, 20, 21, 22);
     347          54 :         mesh_set_triangle(mesh, 20, 22, 23);
     348             : 
     349             : 
     350          54 :         mesh->flags |= MESH_IS_SOLID;
     351          54 :         mesh->bounds.min_edge.x = -hx;
     352          54 :         mesh->bounds.min_edge.y = -hy;
     353          54 :         mesh->bounds.min_edge.z = -hz;
     354          54 :         mesh->bounds.max_edge.x = hx;
     355          54 :         mesh->bounds.max_edge.y = hy;
     356          54 :         mesh->bounds.max_edge.z = hz;
     357          54 :         gf_bbox_refresh(&mesh->bounds);
     358          54 :         gf_mesh_build_aabbtree(mesh);
     359          54 : }
     360             : 
     361         605 : void mesh_new_unit_bbox(GF_Mesh *mesh)
     362             : {
     363             :         SFColorRGBA col;
     364             :         Fixed s = FIX_ONE/2;
     365             : 
     366             :         memset(&col, 0, sizeof(SFColor));
     367         605 :         col.alpha = 1;
     368         605 :         mesh_reset(mesh);
     369         605 :         mesh->mesh_type = MESH_LINESET;
     370         605 :         mesh_set_point(mesh, -s, -s, -s,  col);
     371         605 :         mesh_set_point(mesh, s, -s, -s,  col);
     372         605 :         mesh_set_point(mesh, s, s, -s,  col);
     373         605 :         mesh_set_point(mesh, -s, s, -s,  col);
     374         605 :         mesh_set_point(mesh, -s, -s, s,  col);
     375         605 :         mesh_set_point(mesh, s, -s, s,  col);
     376         605 :         mesh_set_point(mesh, s, s, s,  col);
     377         605 :         mesh_set_point(mesh, -s, s, s,  col);
     378             : 
     379             :         mesh_set_line(mesh, 0, 1);
     380             :         mesh_set_line(mesh, 1, 2);
     381             :         mesh_set_line(mesh, 2, 3);
     382             :         mesh_set_line(mesh, 3, 0);
     383             :         mesh_set_line(mesh, 4, 5);
     384             :         mesh_set_line(mesh, 5, 6);
     385             :         mesh_set_line(mesh, 6, 7);
     386             :         mesh_set_line(mesh, 7, 4);
     387             :         mesh_set_line(mesh, 0, 4);
     388             :         mesh_set_line(mesh, 1, 5);
     389             :         mesh_set_line(mesh, 2, 6);
     390             :         mesh_set_line(mesh, 3, 7);
     391         605 :         gf_bbox_refresh(&mesh->bounds);
     392         605 : }
     393             : 
     394             : 
     395          33 : static void compute_cylinder(Fixed height, Fixed radius, s32 numFacets, SFVec3f *coords, SFVec2f *texcoords)
     396             : {
     397             :         Fixed angle, t, u;
     398             :         s32 i;
     399          33 :         t = height / 2;
     400         825 :         for (i=0; i<numFacets; ++i) {
     401         792 :                 angle = i*GF_2PI / numFacets - GF_PI2;
     402         792 :                 coords[i].y = t;
     403         792 :                 coords[i].x = gf_mulfix(radius, gf_cos(angle));
     404         792 :                 coords[i].z = gf_mulfix(radius , gf_sin(angle));
     405         792 :                 u = FIX_ONE - i*FIX_ONE/numFacets;
     406         792 :                 texcoords[i].x = u;
     407         792 :                 texcoords[i].y = FIX_ONE;
     408             :         }
     409          33 : }
     410             : 
     411             : #define CYLINDER_SUBDIV 24
     412          21 : void mesh_new_cylinder(GF_Mesh *mesh, Fixed height, Fixed radius, Bool bottom, Bool side, Bool top, Bool low_res)
     413             : {
     414             :         u32 nfacets, i, c_idx;
     415             :         SFVec3f *coords;
     416             :         SFVec2f *texcoords;
     417             : 
     418          21 :         mesh_reset(mesh);
     419          21 :         if (!bottom && !side && !top) return;
     420             : 
     421             :         nfacets = CYLINDER_SUBDIV;
     422          21 :         if (low_res) nfacets /= HIGH_SPEED_RATIO;
     423          21 :         coords = (SFVec3f*) gf_malloc(sizeof(SFVec3f) * nfacets);
     424          21 :         texcoords = (SFVec2f*)gf_malloc(sizeof(SFVec2f) * nfacets);
     425             : 
     426          21 :         compute_cylinder(height, radius, nfacets, coords, texcoords);
     427             : 
     428          21 :         if (side) {
     429         432 :                 for (i=0; i<nfacets; ++i) {
     430             :                         /*top*/
     431         864 :                         mesh_set_vertex(mesh, coords[i].x, coords[i].y, coords[i].z,
     432         432 :                                         coords[i].x, 0, coords[i].z,
     433         432 :                                         texcoords[i].x, FIX_ONE);
     434             : 
     435             :                         /*bottom*/
     436         432 :                         mesh_set_vertex(mesh, coords[i].x, -1*coords[i].y, coords[i].z,
     437             :                                         coords[i].x, 0, coords[i].z,
     438             :                                         texcoords[i].x, 0);
     439             : 
     440             : 
     441             :                         /*top circle is counterclockwise, reverse coords*/
     442         432 :                         if (i) {
     443         414 :                                 mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-1, mesh->v_count-3);
     444         414 :                                 mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-2, mesh->v_count-1);
     445             :                         }
     446             :                 }
     447             : 
     448             :                 /*top*/
     449          18 :                 mesh_set_vertex(mesh, coords[0].x, coords[0].y, coords[0].z,
     450             :                                 coords[0].x, 0, coords[0].z,
     451          18 :                                 texcoords[0].x - FIX_ONE, FIX_ONE);
     452             : 
     453             :                 /*bottom*/
     454          18 :                 mesh_set_vertex(mesh, coords[0].x, -1*coords[0].y, coords[0].z,
     455             :                                 coords[0].x, 0, coords[0].z,
     456          18 :                                 texcoords[0].x - FIX_ONE, 0);
     457             : 
     458          18 :                 mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-1, mesh->v_count-3);
     459          18 :                 mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-2, mesh->v_count-1);
     460             :         }
     461             : 
     462          21 :         if (bottom) {
     463             :                 Fixed angle = 0;
     464          15 :                 Fixed aincr = GF_2PI / nfacets;
     465             : 
     466          15 :                 mesh_set_vertex(mesh, 0, -height/2, 0, 0, -FIX_ONE, 0, FIX_ONE/2, FIX_ONE/2);
     467          15 :                 c_idx = mesh->v_count-1;
     468         375 :                 for (i=0; i<nfacets; ++i, angle += aincr) {
     469         720 :                         mesh_set_vertex(mesh, coords[i].x, -1*coords[i].y, coords[i].z,
     470             :                                         0, -FIX_ONE, 0,
     471         720 :                                         (FIX_ONE + gf_sin(angle))/2, FIX_ONE - (FIX_ONE + gf_cos(angle))/2);
     472         360 :                         if (i) mesh_set_triangle(mesh, c_idx, mesh->v_count-2, mesh->v_count-1);
     473             :                 }
     474             : 
     475          30 :                 mesh_set_vertex(mesh, coords[0].x, -1*coords[0].y, coords[0].z,
     476             :                                 0, -FIX_ONE, 0,
     477          30 :                                 (FIX_ONE + gf_sin(angle))/2, FIX_ONE - (FIX_ONE + gf_cos(angle))/2);
     478          15 :                 mesh_set_triangle(mesh, c_idx, mesh->v_count-2, mesh->v_count-1);
     479             :         }
     480             : 
     481          21 :         if (top) {
     482          15 :                 Fixed aincr = GF_2PI / nfacets;
     483          15 :                 Fixed angle = GF_PI + aincr;
     484             : 
     485          15 :                 mesh_set_vertex(mesh, 0, height/2, 0, 0, FIX_ONE, 0, FIX_ONE/2, FIX_ONE/2);
     486          15 :                 c_idx = mesh->v_count-1;
     487         375 :                 for (i=nfacets; i>0; --i, angle += aincr) {
     488             : 
     489         720 :                         mesh_set_vertex(mesh, coords[i - 1].x, coords[i - 1].y, coords[i - 1].z,
     490             :                                         0, FIX_ONE, 0,
     491         720 :                                         (FIX_ONE + gf_sin(angle))/2, FIX_ONE - (FIX_ONE + gf_cos(angle))/2);
     492         360 :                         if (i) mesh_set_triangle(mesh, c_idx, mesh->v_count-2, mesh->v_count-1);
     493             :                 }
     494          30 :                 mesh_set_vertex(mesh, coords[nfacets - 1].x, coords[nfacets - 1].y, coords[nfacets - 1].z,
     495             :                                 0, FIX_ONE, 0,
     496          30 :                                 (FIX_ONE + gf_sin(angle))/2, FIX_ONE - (FIX_ONE + gf_cos(angle))/2);
     497          15 :                 mesh_set_triangle(mesh, c_idx, mesh->v_count-2, mesh->v_count-1);
     498             :         }
     499          21 :         gf_free(texcoords);
     500          21 :         gf_free(coords);
     501             : 
     502          21 :         if (top && bottom && side) mesh->flags |= MESH_IS_SOLID;
     503             : 
     504          21 :         mesh->bounds.min_edge.x = mesh->bounds.min_edge.z = -radius;
     505          21 :         mesh->bounds.max_edge.x = mesh->bounds.max_edge.z = radius;
     506          21 :         mesh->bounds.max_edge.y = (side || (top && bottom)) ? height/2 : 0;
     507          21 :         mesh->bounds.min_edge.y = -mesh->bounds.max_edge.y;
     508          21 :         gf_bbox_refresh(&mesh->bounds);
     509             : 
     510          21 :         gf_mesh_build_aabbtree(mesh);
     511             : }
     512             : 
     513             : #define CONE_SUBDIV     24
     514          12 : void mesh_new_cone(GF_Mesh *mesh, Fixed height, Fixed radius, Bool bottom, Bool side, Bool low_res)
     515             : {
     516             :         u32 nfacets, i, c_idx;
     517             :         SFVec3f *coords;
     518             :         SFVec2f *texcoords;
     519             : 
     520          12 :         mesh_reset(mesh);
     521          12 :         if (!bottom && !side) return;
     522             : 
     523             :         nfacets = CONE_SUBDIV;
     524          12 :         if (low_res) nfacets /= HIGH_SPEED_RATIO;
     525          12 :         coords = (SFVec3f*)gf_malloc(sizeof(SFVec3f) * nfacets);
     526          12 :         texcoords = (SFVec2f*)gf_malloc(sizeof(SFVec2f) * nfacets);
     527             : 
     528          12 :         compute_cylinder(height, radius, nfacets, coords, texcoords);
     529             : 
     530          12 :         if (side) {
     531          12 :                 Fixed Ny = gf_muldiv(radius, radius, height);
     532             : 
     533         300 :                 for (i = 0; i < nfacets; ++i) {
     534             :                         /*top*/
     535         576 :                         mesh_set_vertex(mesh, 0, coords[i].y, 0,
     536         288 :                                         coords[i].x, Ny, coords[i].z,
     537         288 :                                         texcoords[i].x, FIX_ONE);
     538             : 
     539             :                         /*base*/
     540         288 :                         mesh_set_vertex(mesh, coords[i].x, -1*coords[i].y, coords[i].z,
     541             :                                         coords[i].x, Ny, coords[i].z,
     542             :                                         texcoords[i].x, 0);
     543         288 :                         if (i) {
     544         276 :                                 mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-1, mesh->v_count-3);
     545             :                         }
     546             :                 }
     547             :                 /*top*/
     548          12 :                 mesh_set_vertex(mesh, 0, coords[0].y, 0, coords[0].x, Ny, coords[0].z, texcoords[0].x - FIX_ONE, FIX_ONE);
     549             :                 /*base*/
     550          12 :                 mesh_set_vertex(mesh, coords[0].x, -1*coords[0].y, coords[0].z,
     551             :                                 coords[0].x, Ny, coords[0].z,
     552          12 :                                 texcoords[0].x - FIX_ONE, 0);
     553             : 
     554          12 :                 mesh_set_triangle(mesh, mesh->v_count-4, mesh->v_count-1, mesh->v_count-3);
     555             :         }
     556             : 
     557          12 :         if (bottom) {
     558             :                 Fixed angle = 0;
     559           9 :                 Fixed aincr = GF_2PI / nfacets;
     560             : 
     561           9 :                 mesh_set_vertex(mesh, 0, -height/2, 0, 0, -FIX_ONE, 0, FIX_ONE/2, FIX_ONE/2);
     562           9 :                 c_idx = mesh->v_count - 1;
     563         225 :                 for (i=0; i<nfacets; ++i, angle += aincr) {
     564         432 :                         mesh_set_vertex(mesh, coords[i].x, -1*coords[i].y, coords[i].z,
     565             :                                         0, -FIX_ONE, 0,
     566         432 :                                         (FIX_ONE + gf_sin(angle))/2, FIX_ONE - (FIX_ONE + gf_cos(angle))/2);
     567             : 
     568         216 :                         if (i)
     569         207 :                                 mesh_set_triangle(mesh, c_idx, mesh->v_count-2, mesh->v_count-1);
     570             :                 }
     571          18 :                 mesh_set_vertex(mesh, coords[0].x, -1*coords[0].y, coords[0].z,
     572             :                                 0, -FIX_ONE, 0,
     573          18 :                                 (FIX_ONE + gf_sin(angle))/2, FIX_ONE - (FIX_ONE + gf_cos(angle))/2);
     574           9 :                 mesh_set_triangle(mesh, c_idx, mesh->v_count-2, mesh->v_count-1);
     575             :         }
     576          12 :         gf_free(texcoords);
     577          12 :         gf_free(coords);
     578             : 
     579          12 :         if (bottom && side) mesh->flags |= MESH_IS_SOLID;
     580             : 
     581          12 :         mesh->bounds.min_edge.x = mesh->bounds.min_edge.z = -radius;
     582          12 :         mesh->bounds.max_edge.x = mesh->bounds.max_edge.z = radius;
     583          12 :         mesh->bounds.max_edge.y = height/2;
     584          12 :         mesh->bounds.min_edge.y = -mesh->bounds.max_edge.y;
     585          12 :         gf_bbox_refresh(&mesh->bounds);
     586             : 
     587          12 :         gf_mesh_build_aabbtree(mesh);
     588             : 
     589             : }
     590             : 
     591          13 : void compute_sphere(Fixed radius, SFVec3f *coords, SFVec2f *texcoords, u32 num_steps, GF_MeshSphereAngles *sphere_angles)
     592             : {
     593             :         Fixed r, angle, x, y, z;
     594             :         u32 i, j;
     595             : 
     596         685 :         for (i=0; i<num_steps; i++) {
     597         672 :                 if (!sphere_angles) {
     598         672 :                         angle = (i * GF_PI / (num_steps-1) ) - GF_PI2;
     599             :                 } else {
     600           0 :                         angle = (i * (sphere_angles->max_phi - sphere_angles->min_phi) / (num_steps-1) ) + sphere_angles->min_phi;
     601             :                 }
     602         672 :                 y = gf_sin(angle);
     603         672 :                 r = gf_sqrt(FIX_ONE - gf_mulfix(y, y));
     604       36384 :                 for (j = 0; j<num_steps; j++) {
     605       35712 :                         if (!sphere_angles) {
     606       35712 :                                 angle = GF_2PI * j / num_steps - GF_PI2;
     607             :                         } else {
     608           0 :                                 angle = (j * (sphere_angles->max_theta - sphere_angles->min_theta) / (num_steps-1) ) + sphere_angles->min_theta;
     609             :                         }
     610       35712 :                         x = gf_mulfix(gf_cos(angle), r);
     611       35712 :                         z = gf_mulfix(gf_sin(angle), r);
     612       35712 :                         coords[i * num_steps + j].x = gf_mulfix(radius, x);
     613       35712 :                         coords[i * num_steps + j].y = gf_mulfix(radius, y);
     614       35712 :                         coords[i * num_steps + j].z = gf_mulfix(radius, z);
     615       35712 :                         if (radius>0) {
     616       25344 :                                 if (!sphere_angles){
     617       25344 :                                         texcoords[i * num_steps + j].x = FIX_ONE - j*FIX_ONE/num_steps;
     618       25344 :                                         texcoords[i * num_steps + j].y = i*FIX_ONE/num_steps;
     619             :                                 }else{
     620           0 :                                         texcoords[i * num_steps + j].x = j*FIX_ONE/(num_steps-1);
     621           0 :                                         texcoords[i * num_steps + j].y = FIX_ONE - i*FIX_ONE/(num_steps-1);
     622             : 
     623             :                                 }
     624             :                         }else {
     625       10368 :                                 if (!sphere_angles){
     626       10368 :                                         texcoords[i * num_steps + j].x = j*FIX_ONE/(num_steps);
     627       10368 :                                         texcoords[i * num_steps + j].y = FIX_ONE - i*FIX_ONE/(num_steps);
     628             :                                 }else{
     629           0 :                                         texcoords[i * num_steps + j].x = j*FIX_ONE/(num_steps-1);
     630           0 :                                         texcoords[i * num_steps + j].y = FIX_ONE - i*FIX_ONE/(num_steps-1);
     631             :                                 }
     632             :                         }
     633             :                 }
     634             :         }
     635             : 
     636          13 : }
     637             : 
     638          13 : void mesh_new_sphere(GF_Mesh *mesh, Fixed radius, Bool low_res, GF_MeshSphereAngles *sphere_angles)
     639             : {
     640             :         u32 i, j, num_steps, npts;
     641             :         SFVec3f *coords;
     642             :         SFVec2f *texcoords;
     643             : 
     644             :         num_steps = 48;
     645             :         //this is 360 VR, use a large number of subdivisions (1 seg for 5 degrees should be enough )
     646          13 :         if (radius<0) num_steps = 72;
     647             : 
     648          13 :         if (low_res) num_steps /= 2;
     649          13 :         if (sphere_angles) {
     650             :                 Fixed min_subd1, min_subd2;
     651           0 :                 min_subd1 = gf_divfix(sphere_angles->max_phi - sphere_angles->min_phi, GF_PI);
     652           0 :                 min_subd2 = gf_divfix(sphere_angles->max_theta - sphere_angles->min_theta, GF_2PI);
     653           0 :                 if (min_subd1<0) min_subd1 = -min_subd1;
     654           0 :                 if (min_subd2<0) min_subd2 = -min_subd2;
     655           0 :                 if (min_subd2<min_subd1) min_subd1=min_subd2;
     656           0 :                 num_steps = FIX2INT(num_steps * min_subd1);
     657             :         }
     658          13 :         npts = num_steps * num_steps;
     659             : 
     660          13 :         coords = (SFVec3f*)gf_malloc(sizeof(SFVec3f)*npts);
     661          13 :         texcoords = (SFVec2f*)gf_malloc(sizeof(SFVec2f)*npts);
     662          13 :         compute_sphere(radius, coords, texcoords, num_steps, sphere_angles);
     663             : 
     664         672 :         for (i=0; i<num_steps-1; i++) {
     665         659 :                 u32 n = i * num_steps;
     666             :                 Fixed last_tx_coord;
     667       35699 :                 for (j=0; j<num_steps; j++) {
     668       70080 :                         mesh_set_vertex(mesh, coords[n + j + num_steps].x, coords[n + j + num_steps].y, coords[n + j + num_steps].z,
     669       35040 :                                         coords[n + j + num_steps].x, coords[n + j + num_steps].y, coords[n + j + num_steps].z,
     670       35040 :                                         texcoords[n + j + num_steps].x, texcoords[n + j + num_steps].y);
     671             : 
     672       70080 :                         mesh_set_vertex(mesh, coords[n + j].x, coords[n + j].y, coords[n + j].z,
     673       35040 :                                         coords[n + j].x, coords[n + j].y, coords[n + j].z,
     674       35040 :                                         texcoords[n + j].x, texcoords[n + j].y);
     675             : 
     676       35040 :                         if (j) {
     677       34381 :                                 mesh_set_triangle(mesh, mesh->v_count-3, mesh->v_count-4, mesh->v_count-2);
     678       34381 :                                 mesh_set_triangle(mesh, mesh->v_count-3, mesh->v_count-2, mesh->v_count-1);
     679             :                         }
     680             :                 
     681             :                 }
     682         659 :                 if (!sphere_angles) {
     683         659 :                         last_tx_coord = (radius>0) ? 0 : FIX_ONE;
     684        1318 :                         mesh_set_vertex(mesh, coords[n + num_steps].x, coords[n + num_steps].y, coords[n + num_steps].z,
     685         659 :                                         coords[n + num_steps].x, coords[n + num_steps].y, coords[n  + num_steps].z,
     686         659 :                                         last_tx_coord, texcoords[n + num_steps].y);
     687        1318 :                         mesh_set_vertex(mesh, coords[n].x, coords[n].y, coords[n].z,
     688         659 :                                         coords[n].x, coords[n].y, coords[n].z,
     689         659 :                                         last_tx_coord, texcoords[n].y);
     690             : 
     691         659 :                         mesh_set_triangle(mesh, mesh->v_count-3, mesh->v_count-4, mesh->v_count-2);
     692         659 :                         mesh_set_triangle(mesh, mesh->v_count-3, mesh->v_count-2, mesh->v_count-1);
     693             :                 }
     694             :         }
     695             : 
     696          13 :         gf_free(coords);
     697          13 :         gf_free(texcoords);
     698          13 :         if (!sphere_angles) {
     699          13 :                 mesh->flags |= MESH_IS_SOLID;
     700             :         }
     701          13 :         if (radius<0) radius = -radius;
     702             : 
     703          13 :         mesh->bounds.min_edge.x = mesh->bounds.min_edge.y = mesh->bounds.min_edge.z = -radius;
     704          13 :         mesh->bounds.max_edge.x = mesh->bounds.max_edge.y = mesh->bounds.max_edge.z = radius;
     705             : 
     706          13 :         gf_bbox_refresh(&mesh->bounds);
     707             : 
     708          13 :         if (radius != FIX_ONE) gf_mesh_build_aabbtree(mesh);
     709          13 : }
     710             : 
     711        2042 : void mesh_new_rectangle(GF_Mesh *mesh, SFVec2f size, SFVec2f *orig, Bool flip)
     712             : {
     713             :         Fixed tmin, tmax;
     714        2042 :         Fixed x = - size.x / 2;
     715        2042 :         Fixed y = size.y / 2;
     716        2042 :         if (orig) {
     717        1182 :                 x = orig->x;
     718        1182 :                 y = orig->y;
     719             :         }
     720        2042 :         mesh_reset(mesh);
     721             : 
     722        2042 :         tmin = flip ? FIX_ONE : 0;
     723        2042 :         tmax = flip ? 0 : FIX_ONE;
     724             : 
     725        2042 :         mesh_set_vertex(mesh, x, y-size.y,  0,  0,  0,  FIX_ONE, 0, tmin);
     726        2042 :         mesh_set_vertex(mesh, x+size.x, y-size.y,  0,  0,  0,  FIX_ONE, FIX_ONE, tmin);
     727        2042 :         mesh_set_vertex(mesh, x+size.x, y,  0,  0,  0,  FIX_ONE, FIX_ONE, tmax);
     728        2042 :         mesh_set_vertex(mesh, x,  y,  0,  0,  0,  FIX_ONE, 0, tmax);
     729             : 
     730        2042 :         mesh_set_triangle(mesh, 0, 1, 2);
     731        2042 :         mesh_set_triangle(mesh, 0, 2, 3);
     732             : 
     733        2042 :         mesh->flags |= MESH_IS_2D;
     734             : 
     735        2042 :         mesh->bounds.min_edge.x = x;
     736        2042 :         mesh->bounds.min_edge.y = y-size.y;
     737        2042 :         mesh->bounds.min_edge.z = 0;
     738        2042 :         mesh->bounds.max_edge.x = x+size.x;
     739        2042 :         mesh->bounds.max_edge.y = y;
     740        2042 :         mesh->bounds.max_edge.z = 0;
     741        2042 :         gf_bbox_refresh(&mesh->bounds);
     742        2042 : }
     743             : 
     744             : #define ELLIPSE_SUBDIV          32
     745         181 : void mesh_new_ellipse(GF_Mesh *mesh, Fixed a_dia, Fixed b_dia, Bool low_res)
     746             : {
     747             :         Fixed step, cur, end, cosa, sina;
     748         181 :         a_dia /= 2;
     749         181 :         b_dia /= 2;
     750             : 
     751             :         /*no begin/end draw since we always use generic 2D node drawing methods*/
     752             :         end = GF_2PI;
     753             :         step = end / ELLIPSE_SUBDIV;
     754         181 :         if (low_res) step *= HIGH_SPEED_RATIO;
     755             : 
     756         181 :         mesh_reset(mesh);
     757             : 
     758             :         /*center*/
     759         181 :         mesh_set_vertex(mesh, 0, 0, 0, 0, 0, FIX_ONE, FIX_ONE/2, FIX_ONE/2);
     760        5973 :         for (cur=0; cur<end; cur += step) {
     761        5792 :                 cosa = gf_cos(cur);
     762        5792 :                 sina = gf_sin(cur);
     763             : 
     764       11584 :                 mesh_set_vertex(mesh, gf_mulfix(a_dia, cosa), gf_mulfix(b_dia, sina), 0,
     765             :                                 0, 0, FIX_ONE,
     766       11584 :                                 (FIX_ONE + cosa)/2, (FIX_ONE + sina)/2);
     767             : 
     768        5792 :                 if (cur) mesh_set_triangle(mesh, 0, mesh->v_count-2, mesh->v_count-1);
     769             :         }
     770         181 :         mesh_set_vertex(mesh, a_dia, 0, 0, 0, 0, FIX_ONE, FIX_ONE, FIX_ONE/2);
     771         181 :         mesh_set_triangle(mesh, 0, mesh->v_count-2, mesh->v_count-1);
     772             : 
     773         181 :         mesh->flags |= MESH_IS_2D;
     774         181 :         mesh->bounds.min_edge.x = -a_dia;
     775         181 :         mesh->bounds.min_edge.y = -b_dia;
     776         181 :         mesh->bounds.min_edge.z = 0;
     777         181 :         mesh->bounds.max_edge.x = a_dia;
     778         181 :         mesh->bounds.max_edge.y = b_dia;
     779         181 :         mesh->bounds.max_edge.z = 0;
     780         181 :         gf_bbox_refresh(&mesh->bounds);
     781         181 : }
     782             : 
     783          75 : void mesh_from_path_intern(GF_Mesh *mesh, GF_Path *path, Bool make_ccw)
     784             : {
     785             :         u32 i, nbPts;
     786             :         Fixed w, h;
     787             :         GF_Rect bounds;
     788             :         Bool isCW = 0;
     789             : 
     790          75 :         gf_path_flatten(path);
     791          75 :         gf_path_get_bounds(path, &bounds);
     792             : 
     793          75 :         mesh_reset(mesh);
     794          75 :         if (path->n_contours==1) {
     795          54 :                 u32 type = gf_polygone2d_get_convexity(path->points, path->n_points);
     796          54 :                 switch (type) {
     797             :                 /*degenrated polygon - skip*/
     798             :                 case GF_POLYGON_CONVEX_LINE:
     799          24 :                         return;
     800           0 :                 case GF_POLYGON_CONVEX_CW:
     801             :                         isCW = make_ccw;
     802          24 :                 case GF_POLYGON_CONVEX_CCW:
     803          24 :                         w = bounds.width;
     804          24 :                         h = bounds.height;
     805             : 
     806             :                         /*add all vertices*/
     807         594 :                         for (i=0; i<path->n_points-1; i++) {
     808         570 :                                 GF_Point2D pt = path->points[i];
     809         570 :                                 mesh_set_vertex(mesh, pt.x, pt.y, 0, 0, 0, FIX_ONE, gf_divfix(pt.x - bounds.x, w), gf_divfix(bounds.y - pt.y, h));
     810             :                         }
     811             :                         nbPts = path->n_points - 1;
     812             :                         /*take care of already closed path*/
     813          24 :                         if ( (path->points[i].x != path->points[0].x) || (path->points[i].y != path->points[0].y)) {
     814           7 :                                 GF_Point2D pt = path->points[i];
     815           7 :                                 mesh_set_vertex(mesh, pt.x, pt.y, 0, 0, 0, FIX_ONE, gf_divfix(pt.x - bounds.x, w), gf_divfix(bounds.y - pt.y, h));
     816           7 :                                 nbPts = path->n_points;
     817             :                         }
     818             :                         /*make it CCW*/
     819         553 :                         for (i=1; i<nbPts-1; i++) {
     820         529 :                                 if (isCW) {
     821           0 :                                         mesh_set_triangle(mesh, 0, nbPts-i, nbPts-i-1);
     822             :                                 } else {
     823         529 :                                         mesh_set_triangle(mesh, 0, i, i+1);
     824             :                                 }
     825             :                         }
     826          24 :                         mesh->bounds.min_edge.x = bounds.x;
     827          24 :                         mesh->bounds.min_edge.y = bounds.y-bounds.height;
     828          24 :                         mesh->bounds.min_edge.z = 0;
     829          24 :                         mesh->bounds.max_edge.x = bounds.x+bounds.width;
     830          24 :                         mesh->bounds.max_edge.y = bounds.y;
     831          24 :                         mesh->bounds.max_edge.z = 0;
     832          24 :                         gf_bbox_refresh(&mesh->bounds);
     833          24 :                         return;
     834             :                 default:
     835             :                         break;
     836             :                 }
     837          21 :         }
     838             :         /*we need to tesselate the path*/
     839             : #ifdef GPAC_HAS_GLU
     840          51 :         gf_mesh_tesselate_path(mesh, path, 0);
     841             : #endif
     842             : }
     843             : 
     844          75 : void mesh_from_path(GF_Mesh *mesh, GF_Path *path)
     845             : {
     846          75 :         mesh_from_path_intern(mesh, path, 1);
     847          75 : }
     848             : 
     849             : 
     850           2 : void mesh_get_outline(GF_Mesh *mesh, GF_Path *path)
     851             : {
     852             :         u32 i, j, cur, nb_pts;
     853           2 :         mesh_reset(mesh);
     854             : 
     855           2 :         mesh->mesh_type = MESH_LINESET;
     856           2 :         mesh->flags |= (MESH_IS_2D | MESH_NO_TEXTURE);
     857             : 
     858           2 :         gf_path_flatten(path);
     859             : 
     860             :         cur = 0;
     861           4 :         for (i=0; i<path->n_contours; i++) {
     862           2 :                 nb_pts = 1+path->contours[i] - cur;
     863          74 :                 for (j=0; j<nb_pts; j++) {
     864          72 :                         GF_Point2D pt = path->points[j+cur];
     865          72 :                         if (j) mesh_set_line(mesh, mesh->v_count-1, mesh->v_count);
     866          72 :                         mesh_set_vertex(mesh, pt.x, pt.y, 0, 0, 0, FIX_ONE, 0, 0);
     867             :                 }
     868           2 :                 cur += nb_pts;
     869             :         }
     870           2 :         mesh_update_bounds(mesh);
     871           2 : }
     872             : 
     873             : 
     874             : #ifndef GPAC_DISABLE_VRML
     875             : 
     876             : 
     877             : #define COL_TO_RGBA(res, col) { res.red = col.red; res.green = col.green; res.blue = col.blue; res.alpha = FIX_ONE; }
     878             : 
     879             : 
     880             : #define MESH_GET_COL(thecol, index)     {\
     881             :         if (colorRGB && ((u32) index < colorRGB->color.count) ) COL_TO_RGBA(thecol, colorRGB->color.vals[index])       \
     882             :         else if (colorRGBA && (u32) index < colorRGBA->color.count) thecol = colorRGBA->color.vals[index]; \
     883             :         } \
     884             :  
     885          21 : void mesh_new_ils(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex, GF_Node *__color, MFInt32 *colorIndex, Bool colorPerVertex, Bool do_close)
     886             : {
     887             :         u32 i, n, count, c_count, col_count;
     888             :         u32 index;
     889             :         u32 first_idx, last_idx;
     890             :         Bool move_to;
     891             :         SFVec3f pt;
     892             :         SFColorRGBA colRGBA;
     893             :         Bool has_color, has_coord;
     894             :         M_Coordinate2D *coord2D = (M_Coordinate2D*) __coord;
     895             :         M_Coordinate *coord = (M_Coordinate*) __coord;
     896             :         M_Color *colorRGB = (M_Color *) __color;
     897             : #ifndef GPAC_DISABLE_X3D
     898             :         X_ColorRGBA *colorRGBA = (X_ColorRGBA *) __color;
     899             : #endif
     900             : 
     901          21 :         if (__coord && (gf_node_get_tag(__coord) == TAG_MPEG4_Coordinate2D)) {
     902             :                 coord = NULL;
     903             :         } else {
     904             :                 coord2D = NULL;
     905             :         }
     906             : 
     907          21 :         colRGBA.red = colRGBA.green = colRGBA.blue = colRGBA.alpha = 0;
     908             : 
     909          21 :         if (!coord2D && !coord) return;
     910          21 :         c_count = coord2D ? coord2D->point.count : coord->point.count;
     911          21 :         if (!c_count) return;
     912             : 
     913          21 :         count = coordIndex->count;
     914             :         has_coord = count ? 1 : 0;
     915          21 :         if (!has_coord) count = c_count;
     916             : 
     917          21 :         if (!colorIndex->vals) colorIndex = coordIndex;
     918          21 :         col_count = colorIndex->count ? colorIndex->count : c_count;
     919             :         /*not enough color indices, use coord ones*/
     920          21 :         if (colorPerVertex && (col_count<count) ) {
     921             :                 colorIndex = coordIndex;
     922             :                 col_count = count;
     923             :         }
     924             :         has_color = 0;
     925          21 :         if (__color) {
     926             : #ifndef GPAC_DISABLE_X3D
     927           8 :                 if (gf_node_get_tag(__color)==TAG_X3D_ColorRGBA) {
     928             :                         colorRGB = NULL;
     929           0 :                         has_color = (colorRGBA->color.count) ? 1 : 0;
     930             :                 } else
     931             : #endif
     932             :                 {
     933             : #ifndef GPAC_DISABLE_X3D
     934             :                         colorRGBA = NULL;
     935             : #endif
     936           8 :                         has_color = (colorRGB->color.count) ? 1 : 0;
     937             :                 }
     938             :         }
     939             : 
     940          21 :         mesh_reset(mesh);
     941          21 :         mesh->mesh_type = MESH_LINESET;
     942          21 :         if (has_color) mesh->flags |= MESH_HAS_COLOR;
     943             : 
     944             :         n = 0;
     945          21 :         if (has_color && !colorPerVertex) {
     946           1 :                 index = colorIndex->count ? colorIndex->vals[0] : 0;
     947             : #ifndef GPAC_DISABLE_X3D
     948           1 :                 if ((u32) index < col_count) MESH_GET_COL(colRGBA, index);
     949             : #endif
     950             :         }
     951             :         move_to = 1;
     952             : 
     953             :         first_idx = last_idx = 0;
     954         220 :         for (i=0; i<count; i++) {
     955         220 :                 if (has_coord && coordIndex->vals[i] == -1) {
     956             :                         /*close color per vertex*/
     957          40 :                         if (!move_to && do_close && !gf_vec_equal(mesh->vertices[first_idx].pos, mesh->vertices[last_idx].pos) ) {
     958             :                                 mesh_set_line(mesh, last_idx, first_idx);
     959             :                         }
     960             :                         move_to = 1;
     961          40 :                         n++;
     962          40 :                         if (has_color && !colorPerVertex) {
     963           5 :                                 if (n<colorIndex->count) index = colorIndex->vals[n];
     964           0 :                                 else if (n<col_count) index = n;
     965             :                                 else index = 0;
     966             : #ifndef GPAC_DISABLE_X3D
     967           5 :                                 MESH_GET_COL(colRGBA, index);
     968             : #endif
     969             :                         }
     970             :                 } else {
     971         180 :                         if (has_color && colorPerVertex) {
     972         126 :                                 if (i<colorIndex->count) index = colorIndex->vals[i];
     973           0 :                                 else if (i<col_count) index = i;
     974             :                                 else index=0;
     975             : #ifndef GPAC_DISABLE_X3D
     976         126 :                                 MESH_GET_COL(colRGBA, index);
     977             : #endif
     978             :                         }
     979         180 :                         if (has_coord) index = coordIndex->vals[i];
     980             :                         else index = i;
     981         180 :                         if (index < c_count) {
     982         180 :                                 if (coord2D) {
     983          36 :                                         pt.x = coord2D->point.vals[index].x;
     984          36 :                                         pt.y = coord2D->point.vals[index].y;
     985             :                                         pt.z = 0;
     986             :                                 } else {
     987         144 :                                         pt = coord->point.vals[index];
     988             :                                 }
     989         180 :                                 mesh_set_point(mesh, pt.x, pt.y, pt.z, colRGBA);
     990         180 :                                 last_idx = mesh->v_count - 1;
     991         180 :                                 if (move_to) {
     992             :                                         first_idx = last_idx;
     993             :                                         move_to = 0;
     994             :                                 } else {
     995         119 :                                         mesh_set_line(mesh, last_idx-1, last_idx);
     996             :                                 }
     997             :                         }
     998             :                 }
     999             :         }
    1000             :         /*close color per vertex*/
    1001          21 :         if (do_close && !gf_vec_equal(mesh->vertices[first_idx].pos, mesh->vertices[last_idx].pos) ) {
    1002             :                 mesh_set_line(mesh, last_idx, first_idx);
    1003             :         }
    1004          21 :         if (coord2D) mesh->flags |= MESH_IS_2D;
    1005             : #ifndef GPAC_DISABLE_X3D
    1006          21 :         if (colorRGBA) mesh->flags |= MESH_HAS_ALPHA;
    1007             : #endif
    1008          21 :         mesh_update_bounds(mesh);
    1009             : }
    1010             : 
    1011          16 : void mesh_new_ps(GF_Mesh *mesh, GF_Node *__coord, GF_Node *__color)
    1012             : {
    1013             :         u32 c_count, i;
    1014             :         Bool has_color;
    1015             :         SFVec3f pt;
    1016             :         SFColorRGBA colRGBA;
    1017             :         M_Coordinate2D *coord2D = (M_Coordinate2D*) __coord;
    1018             :         M_Coordinate *coord = (M_Coordinate*) __coord;
    1019             :         M_Color *colorRGB = (M_Color *) __color;
    1020             : #ifndef GPAC_DISABLE_X3D
    1021             :         X_ColorRGBA *colorRGBA = (X_ColorRGBA *) __color;
    1022             : #endif
    1023             : 
    1024          16 :         if (__coord && (gf_node_get_tag(__coord) == TAG_MPEG4_Coordinate2D)) {
    1025             :                 coord = NULL;
    1026             :         } else {
    1027             :                 coord2D = NULL;
    1028             :         }
    1029             : 
    1030          16 :         if (!coord2D && !coord) return;
    1031          16 :         c_count = coord2D ? coord2D->point.count : coord->point.count;
    1032          16 :         if (!c_count) return;
    1033             : 
    1034          16 :         mesh_reset(mesh);
    1035          16 :         mesh->mesh_type = MESH_POINTSET;
    1036             : 
    1037             :         has_color = 0;
    1038          16 :         if (__color) {
    1039             : #ifndef GPAC_DISABLE_X3D
    1040           0 :                 if (gf_node_get_tag(__color)==TAG_X3D_ColorRGBA) {
    1041             :                         colorRGB = NULL;
    1042           0 :                         has_color = (colorRGBA->color.count) ? 1 : 0;
    1043             :                 } else
    1044             : #endif
    1045             :                 {
    1046             : #ifndef GPAC_DISABLE_X3D
    1047             :                         colorRGBA = NULL;
    1048             : #endif
    1049           0 :                         has_color = (colorRGB->color.count) ? 1 : 0;
    1050             :                 }
    1051             :         }
    1052          16 :         if (has_color) mesh->flags |= MESH_HAS_COLOR;
    1053             : 
    1054          16 :         colRGBA.red = colRGBA.green = colRGBA.blue = colRGBA.alpha = FIX_ONE;
    1055             : 
    1056         108 :         for (i=0; i<c_count; ++i) {
    1057             : #ifndef GPAC_DISABLE_X3D
    1058          92 :                 if (has_color) MESH_GET_COL(colRGBA, i);
    1059             : #endif
    1060          92 :                 if (coord2D) {
    1061          36 :                         pt.x = coord2D->point.vals[i].x;
    1062          36 :                         pt.y = coord2D->point.vals[i].y;
    1063             :                         pt.z = 0;
    1064             :                 } else {
    1065          56 :                         pt = coord->point.vals[i];
    1066             :                 }
    1067          92 :                 mesh_set_point(mesh, pt.x, pt.y, pt.z, colRGBA);
    1068          92 :                 mesh_set_index(mesh, mesh->v_count-1);
    1069             :         }
    1070          16 :         mesh_update_bounds(mesh);
    1071             : }
    1072             : 
    1073             : /*structures used for normal smoothing*/
    1074             : struct face_info
    1075             : {
    1076             :         /*face normal*/
    1077             :         SFVec3f nor;
    1078             :         u32 idx_alloc;
    1079             :         /*nb pts in face*/
    1080             :         u32 idx_count;
    1081             :         /*indexes of face vertices in the pt_info structure*/
    1082             :         u32 *idx;
    1083             : };
    1084             : /*for each pt in the mesh*/
    1085             : struct pt_info
    1086             : {
    1087             :         u32 face_alloc;
    1088             :         /*number of faces this point belongs to*/
    1089             :         u32 face_count;
    1090             :         /*idx of face in face_info structure*/
    1091             :         u32 *faces;
    1092             : };
    1093             : 
    1094       65768 : void register_point_in_face(struct face_info *fi, u32 pt_index)
    1095             : {
    1096       65768 :         if (fi->idx_count==fi->idx_alloc) {
    1097       19830 :                 fi->idx_alloc += 10;
    1098       19830 :                 fi->idx = (u32*)gf_realloc(fi->idx, sizeof(u32)*fi->idx_alloc);
    1099             :         }
    1100       65768 :         fi->idx[fi->idx_count] = pt_index;
    1101       65768 :         fi->idx_count++;
    1102       65768 : }
    1103             : 
    1104       65768 : void register_face_in_point(struct pt_info *pi, u32 face_index)
    1105             : {
    1106       65768 :         if (pi->face_count==pi->face_alloc) {
    1107       13602 :                 pi->face_alloc += 10;
    1108       13602 :                 pi->faces = (u32*)gf_realloc(pi->faces, sizeof(u32)*pi->face_alloc);
    1109             :         }
    1110       65768 :         pi->faces[pi->face_count] = face_index;
    1111       65768 :         pi->face_count++;
    1112       65768 : }
    1113             : 
    1114       65640 : static GFINLINE SFVec3f smooth_face_normals(struct pt_info *pts, u32 nb_pts, struct face_info *faces, u32 nb_faces,
    1115             :         u32 pt_idx_in_face, u32 face_idx, Fixed creaseAngleCos)
    1116             : {
    1117             :         u32 i=0;
    1118             :         SFVec3f nor;
    1119       65640 :         struct face_info *fi = &faces[face_idx];
    1120       65640 :         struct pt_info *pi = &pts[fi->idx[pt_idx_in_face]];
    1121             : 
    1122       65640 :         nor = fi->nor;
    1123             :         /*for each face adjacent this point/face*/
    1124      346362 :         for (i=0; i<pi->face_count; i++) {
    1125             :                 /*current face, skip*/
    1126      346362 :                 if (pi->faces[i]==face_idx) continue;
    1127      280578 :                 if (gf_vec_dot(fi->nor, faces[pi->faces[i]].nor) > creaseAngleCos) {
    1128      278980 :                         gf_vec_add(nor, nor, faces[pi->faces[i]].nor);
    1129             :                 }
    1130             : 
    1131             :         }
    1132       65640 :         gf_vec_norm(&nor);
    1133       65640 :         return nor;
    1134             : }
    1135             : 
    1136             : 
    1137             : #define GET_IDX(idx, array) \
    1138             :                 if (idx<array->count && (array->vals[idx]>=0) ) index = array->vals[idx];        \
    1139             :                 else if (idx<c_count) index = idx;   \
    1140             :                 else index = 0; \
    1141             :  
    1142          59 : void mesh_new_ifs_intern(GF_Mesh *mesh, GF_Node *__coord, MFInt32 *coordIndex,
    1143             :                          GF_Node *__color, MFInt32 *colorIndex, Bool colorPerVertex,
    1144             :                          GF_Node *__normal, MFInt32 *normalIndex, Bool normalPerVertex,
    1145             :                          GF_Node *__texCoords, MFInt32 *texCoordIndex,
    1146             :                          Fixed creaseAngle)
    1147             : {
    1148             :         u32 i, idx, count, c_count, nor_count;
    1149             :         u32 index;
    1150             :         Bool smooth_normals;
    1151             :         SFVec2f tx;
    1152             :         u32 s_axis, t_axis;
    1153             :         SFVec3f pt, nor, bounds, center;
    1154             :         SFColorRGBA colRGBA;
    1155             :         Bool has_color, has_coord, has_normal, has_tex, gen_tex_coords;
    1156             :         GF_Mesh **faces;
    1157             :         struct face_info *faces_info;
    1158             :         struct pt_info *pts_info;
    1159             :         u32 face_count, cur_face;
    1160             :         M_Coordinate2D *coord2D = (M_Coordinate2D*) __coord;
    1161             :         M_Coordinate *coord = (M_Coordinate*) __coord;
    1162             :         M_Color *colorRGB = (M_Color *) __color;
    1163             : #ifndef GPAC_DISABLE_X3D
    1164             :         X_ColorRGBA *colorRGBA = (X_ColorRGBA *) __color;
    1165             : #endif
    1166             :         M_Normal *normal = (M_Normal*) __normal;
    1167             :         M_TextureCoordinate *txcoord = (M_TextureCoordinate*) __texCoords;
    1168             : 
    1169             :         nor.x = nor.y = nor.z = 0;
    1170             :         center = pt = bounds = nor;
    1171          59 :         tx.x = tx.y = 0;
    1172             : 
    1173          59 :         if (__coord && (gf_node_get_tag(__coord) == TAG_MPEG4_Coordinate2D)) {
    1174             :                 coord = NULL;
    1175             :         } else {
    1176             :                 coord2D = NULL;
    1177          27 :                 if (!__coord)
    1178           6 :                         return;
    1179             :                 /*not supported yet*/
    1180             : #ifndef GPAC_DISABLE_X3D
    1181          21 :                 if (gf_node_get_tag(__coord) == TAG_X3D_CoordinateDouble)
    1182             :                         return;
    1183             : #endif
    1184             :         }
    1185             :         gen_tex_coords = 0;
    1186             : #ifndef GPAC_DISABLE_X3D
    1187          53 :         if (__texCoords && (gf_node_get_tag(__texCoords)==TAG_X3D_TextureCoordinateGenerator)) {
    1188             :                 gen_tex_coords = 1;
    1189             :                 txcoord = NULL;
    1190             :         }
    1191             : #endif
    1192             : 
    1193          53 :         if (!coord2D && !coord) return;
    1194          53 :         c_count = coord2D ? coord2D->point.count : coord->point.count;
    1195          53 :         if (!c_count) return;
    1196             : 
    1197          53 :         if (normal && normalIndex) {
    1198           0 :                 if (!normalIndex->vals) normalIndex = coordIndex;
    1199           0 :                 nor_count = normalIndex->count ? normalIndex->count : c_count;
    1200           0 :                 has_normal = normal->vector.count ? 1 : 0;
    1201             :         } else {
    1202             :                 nor_count = 0;
    1203             :                 nor.x = nor.y = 0;
    1204             :                 nor.z = FIX_ONE;
    1205             :                 has_normal = 0;
    1206             :         }
    1207             : 
    1208             :         has_tex = txcoord ? 1 : 0;
    1209          53 :         if (has_tex && !texCoordIndex->vals) texCoordIndex = coordIndex;
    1210             : 
    1211          53 :         mesh_reset(mesh);
    1212             :         memset(&colRGBA, 0, sizeof(SFColorRGBA));
    1213             :         /*compute bounds - note we assume all points in the IFS coordinate are used*/
    1214             :         s_axis = t_axis = 0;
    1215          53 :         if (!has_tex) {
    1216        7450 :                 for (i=0; i<c_count; i++) {
    1217        7450 :                         if (coord2D) mesh_set_point(mesh, coord2D->point.vals[i].x, coord2D->point.vals[i].y, 0, colRGBA);
    1218        7274 :                         else mesh_set_point(mesh, coord->point.vals[i].x, coord->point.vals[i].y, coord->point.vals[i].z, colRGBA);
    1219             :                 }
    1220          53 :                 mesh_update_bounds(mesh);
    1221          53 :                 gf_vec_diff(bounds, mesh->bounds.max_edge, mesh->bounds.min_edge);
    1222             :                 center = mesh->bounds.min_edge;
    1223          53 :                 if ( (bounds.x >= bounds.y) && (bounds.x >= bounds.z) ) {
    1224             :                         s_axis = 0;
    1225          42 :                         t_axis = (bounds.y >= bounds.z) ? 1 : 2;
    1226             :                 }
    1227          11 :                 else if ( (bounds.y >= bounds.x) && (bounds.y >= bounds.z) ) {
    1228             :                         s_axis = 1;
    1229          11 :                         t_axis = (bounds.x >= bounds.z) ? 0 : 2;
    1230             :                 }
    1231             :                 else {
    1232             :                         s_axis = 2;
    1233           0 :                         t_axis = (bounds.x >= bounds.y) ? 0 : 1;
    1234             :                 }
    1235             :         }
    1236             : 
    1237             :         has_color = 0;
    1238          53 :         if (__color) {
    1239             : #ifndef GPAC_DISABLE_X3D
    1240          10 :                 if (gf_node_get_tag(__color)==TAG_X3D_ColorRGBA) {
    1241             :                         colorRGB = NULL;
    1242           2 :                         has_color = (colorRGBA->color.count) ? 1 : 0;
    1243             :                 } else
    1244             : #endif
    1245             :                 {
    1246             : #ifndef GPAC_DISABLE_X3D
    1247             :                         colorRGBA = NULL;
    1248             : #endif
    1249           8 :                         has_color = (colorRGB->color.count) ? 1 : 0;
    1250             :                 }
    1251             :         }
    1252             :         idx = 0;
    1253          53 :         if (has_color) {
    1254          10 :                 if (!colorPerVertex) {
    1255           2 :                         index = colorIndex->count ? colorIndex->vals[0] : 0;
    1256             : #ifndef GPAC_DISABLE_X3D
    1257           2 :                         MESH_GET_COL(colRGBA, index);
    1258             : #endif
    1259             :                 } else {
    1260           8 :                         if (!colorIndex->vals) colorIndex = coordIndex;
    1261             :                 }
    1262             :         }
    1263             : 
    1264          53 :         if (has_normal && !normalPerVertex) {
    1265           0 :                 index = normalIndex->count ? normalIndex->vals[0] : 0;
    1266           0 :                 if (index < nor_count) nor = normal->vector.vals[index];
    1267             :         }
    1268             : 
    1269          53 :         count = coordIndex->count;
    1270             :         has_coord = count ? 1 : 0;
    1271          53 :         if (!has_coord) count = c_count;
    1272             : 
    1273          53 :         smooth_normals = (!has_normal && coord && (creaseAngle > FIX_EPSILON)) ? 1 : 0;
    1274             : 
    1275             :         /*build face list*/
    1276          53 :         if (!has_coord) {
    1277             :                 face_count = 1;
    1278             :         } else {
    1279             :                 face_count = 0;
    1280       55400 :                 for (i=0; i<count; i++) {
    1281       55400 :                         if (coordIndex->vals[i] == -1) face_count++;
    1282             :                 }
    1283             :                 /*don't forget last face*/
    1284          23 :                 if (coordIndex->vals[count-1] != -1) face_count++;
    1285             :         }
    1286             : 
    1287          53 :         faces = (GF_Mesh**)gf_malloc(sizeof(GF_Mesh *)*face_count);
    1288       13917 :         for (i=0; i<face_count; i++) {
    1289       13864 :                 faces[i] = new_mesh();
    1290       13864 :                 if (coord2D) faces[i]->flags = MESH_IS_2D;
    1291             :         }
    1292             :         faces_info = NULL;
    1293             :         pts_info = NULL;
    1294             : 
    1295             :         /*alloc face & normals tables*/
    1296          53 :         if (smooth_normals) {
    1297          11 :                 faces_info = (struct face_info*)gf_malloc(sizeof(struct face_info)*face_count);
    1298             :                 memset(faces_info, 0, sizeof(struct face_info)*face_count);
    1299          11 :                 pts_info = (struct pt_info*)gf_malloc(sizeof(struct pt_info)*c_count);
    1300             :                 memset(pts_info, 0, sizeof(struct pt_info)*c_count);
    1301             :         }
    1302             : 
    1303             :         cur_face = 0;
    1304       55617 :         for (i=0; i<count; i++) {
    1305       55564 :                 if (has_coord && coordIndex->vals[i] == -1) {
    1306       13832 :                         idx++;
    1307       13832 :                         if (has_color && !colorPerVertex) {
    1308          12 :                                 GET_IDX(idx, colorIndex);
    1309             : #ifndef GPAC_DISABLE_X3D
    1310          12 :                                 MESH_GET_COL(colRGBA, index);
    1311             : #endif
    1312             :                         }
    1313       13832 :                         if (has_normal && !normalPerVertex) {
    1314           0 :                                 GET_IDX(idx, normalIndex);
    1315           0 :                                 if (index < nor_count) nor = normal->vector.vals[index];
    1316             :                         }
    1317       13832 :                         if (faces[cur_face]->v_count<3) faces[cur_face]->v_count=0;
    1318             :                         /*compute face normal - watchout for colinear vectors*/
    1319       13832 :                         else if (smooth_normals) {
    1320             :                                 SFVec3f v1, v2, fn;
    1321             :                                 u32 k=2;
    1322       13772 :                                 gf_vec_diff(v1, faces[cur_face]->vertices[1].pos, faces[cur_face]->vertices[0].pos);
    1323       27544 :                                 while (k<faces[cur_face]->v_count) {
    1324       13772 :                                         gf_vec_diff(v2, faces[cur_face]->vertices[k].pos, faces[cur_face]->vertices[0].pos);
    1325       13772 :                                         fn = gf_vec_cross(v1, v2);
    1326       13772 :                                         if (gf_vec_len(fn)) {
    1327       13772 :                                                 gf_vec_norm(&fn);
    1328       13772 :                                                 faces_info[cur_face].nor = fn;
    1329       13772 :                                                 break;
    1330             :                                         }
    1331           0 :                                         k++;
    1332             :                                 }
    1333             :                         }
    1334       13832 :                         cur_face++;
    1335             :                 } else {
    1336       41732 :                         if (has_color && colorPerVertex) {
    1337         192 :                                 GET_IDX(i, colorIndex);
    1338             : #ifndef GPAC_DISABLE_X3D
    1339         192 :                                 MESH_GET_COL(colRGBA, index);
    1340             : #endif
    1341             :                         }
    1342       41732 :                         if (has_normal && normalPerVertex) {
    1343           0 :                                 GET_IDX(i, normalIndex);
    1344           0 :                                 if (index < normal->vector.count) {
    1345           0 :                                         nor = normal->vector.vals[index];
    1346             :                                 }
    1347             :                         }
    1348             : 
    1349       41732 :                         if (has_coord) index = coordIndex->vals[i];
    1350             :                         else index = i;
    1351       41732 :                         if (index < c_count) {
    1352       41732 :                                 if (coord2D) {
    1353         176 :                                         pt.x = coord2D->point.vals[index].x;
    1354         176 :                                         pt.y = coord2D->point.vals[index].y;
    1355             :                                         pt.z = 0;
    1356             :                                 } else {
    1357       41556 :                                         pt = coord->point.vals[index];
    1358             :                                 }
    1359             :                                 /*update face to point and point to face structures*/
    1360       41732 :                                 if (smooth_normals) {
    1361       41316 :                                         register_point_in_face(&faces_info[cur_face], index);
    1362       41316 :                                         register_face_in_point(&pts_info[index], cur_face);
    1363             :                                 }
    1364             :                         }
    1365             : 
    1366       41732 :                         if (has_tex) {
    1367           0 :                                 GET_IDX(i, texCoordIndex);
    1368           0 :                                 if (index < txcoord->point.count) tx = txcoord->point.vals[index];
    1369             :                         } else {
    1370             :                                 SFVec3f v;
    1371       41732 :                                 gf_vec_diff(v, pt, center);
    1372       41732 :                                 tx.x = tx.y = 0;
    1373       41732 :                                 if (s_axis==0) tx.x = gf_divfix(v.x, bounds.x);
    1374       41316 :                                 else if (s_axis==1) tx.x = gf_divfix(v.y, bounds.y);
    1375           0 :                                 else if (s_axis==2) tx.x = gf_divfix(v.z, bounds.z);
    1376       41732 :                                 if (t_axis==0) tx.y = gf_divfix(v.x, bounds.x);
    1377       41732 :                                 else if (t_axis==1) tx.y = gf_divfix(v.y, bounds.y);
    1378       41316 :                                 else if (t_axis==2) tx.y = gf_divfix(v.z, bounds.z);
    1379             :                         }
    1380             : 
    1381       41732 :                         mesh_set_vertex_v(faces[cur_face], pt, nor, tx, colRGBA);
    1382             :                 }
    1383             :         }
    1384             : 
    1385             :         /*generate normals*/
    1386          53 :         if (!has_normal && coord) {
    1387             :                 u32 j;
    1388          21 :                 if (smooth_normals) {
    1389             :                         Fixed cosCrease;
    1390             :                         /*we only support 0->PI, whatever exceeds is smoothest*/
    1391          11 :                         if (creaseAngle>GF_PI) cosCrease = -FIX_ONE;
    1392          11 :                         else cosCrease = gf_cos(creaseAngle);
    1393             : 
    1394       13783 :                         for (i=0; i<face_count; i++) {
    1395       41316 :                                 for (j=0; j<faces[i]->v_count; j++) {
    1396       41316 :                                         SFVec3f n = smooth_face_normals(pts_info, c_count, faces_info, face_count, j, i, cosCrease);
    1397       41316 :                                         MESH_SET_NORMAL(faces[i]->vertices[j], n);
    1398             :                                 }
    1399             :                         }
    1400             : 
    1401          11 :                         if (faces_info) {
    1402       13772 :                                 for (i=0; i<face_count; i++) if (faces_info[i].idx) gf_free(faces_info[i].idx);
    1403          11 :                                 gf_free(faces_info);
    1404             :                         }
    1405          11 :                         if (pts_info) {
    1406        7194 :                                 for (i=0; i<c_count; i++) if (pts_info[i].faces) gf_free(pts_info[i].faces);
    1407          11 :                                 gf_free(pts_info);
    1408             :                         }
    1409          11 :                         mesh->flags |= MESH_IS_SMOOTHED;
    1410             :                 } else {
    1411          60 :                         for (i=0; i<face_count; i++) {
    1412             :                                 SFVec3f v1, v2, n;
    1413          60 :                                 if (! faces[i] || ! faces[i]->vertices) continue;
    1414          60 :                                 gf_vec_diff(v1, faces[i]->vertices[1].pos, faces[i]->vertices[0].pos);
    1415          60 :                                 gf_vec_diff(v2, faces[i]->vertices[2].pos, faces[i]->vertices[0].pos);
    1416          60 :                                 n = gf_vec_cross(v1, v2);
    1417          60 :                                 if (!n.x && !n.y && !n.z) n.z = FIX_ONE;
    1418          60 :                                 else gf_vec_norm(&n);
    1419         240 :                                 for (j=0; j<faces[i]->v_count; j++)
    1420         240 :                                         MESH_SET_NORMAL(faces[i]->vertices[j], n);
    1421             :                         }
    1422             :                 }
    1423             :         }
    1424             : 
    1425          53 :         mesh_reset(mesh);
    1426          53 :         mesh->mesh_type = MESH_TRIANGLES;
    1427          53 :         if (has_color) mesh->flags |= MESH_HAS_COLOR;
    1428             : 
    1429       13864 :         for (i=0; i<face_count; i++) {
    1430       13864 :                 if (! faces[i]) continue;
    1431       13864 :                 if (faces[i]->v_count) TesselateFaceMesh(mesh, faces[i]);
    1432       13864 :                 mesh_free(faces[i]);
    1433             :         }
    1434          53 :         gf_free(faces);
    1435          53 :         mesh_update_bounds(mesh);
    1436             : 
    1437          53 :         if (!coord2D) gf_mesh_build_aabbtree(mesh);
    1438             : 
    1439             : #ifndef GPAC_DISABLE_X3D
    1440          53 :         if (colorRGBA) mesh->flags |= MESH_HAS_ALPHA;
    1441          53 :         if (gen_tex_coords) mesh_generate_tex_coords(mesh, __texCoords);
    1442             : #endif
    1443             : }
    1444             : 
    1445          32 : void mesh_new_ifs2d(GF_Mesh *mesh, GF_Node *node)
    1446             : {
    1447             :         M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node;
    1448          64 :         mesh_new_ifs_intern(mesh, ifs2D->coord, &ifs2D->coordIndex,
    1449          32 :                             ifs2D->color, &ifs2D->colorIndex, ifs2D->colorPerVertex,
    1450             :                             NULL, NULL, 0, ifs2D->texCoord, &ifs2D->texCoordIndex, 0);
    1451             : 
    1452          32 :         mesh->flags |= MESH_IS_2D;
    1453          32 : }
    1454             : 
    1455          27 : void mesh_new_ifs(GF_Mesh *mesh, GF_Node *node)
    1456             : {
    1457             :         M_IndexedFaceSet *ifs = (M_IndexedFaceSet *)node;
    1458          54 :         mesh_new_ifs_intern(mesh, ifs->coord, &ifs->coordIndex, ifs->color, &ifs->colorIndex, ifs->colorPerVertex,
    1459          27 :                             ifs->normal, &ifs->normalIndex, ifs->normalPerVertex, ifs->texCoord, &ifs->texCoordIndex, ifs->creaseAngle);
    1460             : 
    1461          27 :         if (ifs->solid) mesh->flags |= MESH_IS_SOLID;
    1462          27 :         if (!ifs->ccw) mesh->flags |= MESH_IS_CW;
    1463          27 : }
    1464             : 
    1465           7 : void mesh_new_elevation_grid(GF_Mesh *mesh, GF_Node *node)
    1466             : {
    1467             :         u32 i, j, face_count, pt_count, zDimension, xDimension, cur_face, idx, pt_idx;
    1468             :         Bool has_normal, has_txcoord, has_color, smooth_normals;
    1469             :         GF_Mesh **faces;
    1470             :         GF_Vertex vx;
    1471             :         SFVec3f v1, v2, n;
    1472             :         struct face_info *faces_info;
    1473             :         struct pt_info *pts_info;
    1474             :         M_ElevationGrid *eg = (M_ElevationGrid *) node;
    1475           7 :         M_Normal *norm = (M_Normal *)eg->normal;
    1476           7 :         M_Color *colorRGB = (M_Color *)eg->color;
    1477             : #ifndef GPAC_DISABLE_X3D
    1478             :         X_ColorRGBA *colorRGBA = (X_ColorRGBA *)eg->color;
    1479             : #endif
    1480             :         SFColorRGBA rgba;
    1481           7 :         M_TextureCoordinate *txc = (M_TextureCoordinate *)eg->texCoord;
    1482             : 
    1483           7 :         mesh_reset(mesh);
    1484           7 :         if (!eg->height.count || (eg->xDimension<2) || (eg->zDimension<2)) return;
    1485             : 
    1486             :         memset(&vx, 0, sizeof(GF_Vertex));
    1487             :         memset(&rgba, 0, sizeof(SFColorRGBA));
    1488           7 :         has_txcoord = txc ? txc->point.count : 0;
    1489           7 :         has_normal = norm ? norm->vector.count : 0;
    1490             :         has_color = 0;
    1491           7 :         if (eg->color) {
    1492             : #ifndef GPAC_DISABLE_X3D
    1493           0 :                 if (gf_node_get_tag(eg->color)==TAG_X3D_ColorRGBA) {
    1494             :                         colorRGB = NULL;
    1495           0 :                         has_color = colorRGBA->color.count ? 1 : 0;
    1496             :                 } else
    1497             : #endif
    1498             :                 {
    1499             : #ifndef GPAC_DISABLE_X3D
    1500             :                         colorRGBA = NULL;
    1501             : #endif
    1502           0 :                         has_color = colorRGB->color.count ? 1 : 0;
    1503             :                 }
    1504             :         }
    1505           7 :         face_count = (eg->xDimension-1) * (eg->zDimension-1);
    1506           7 :         pt_count = eg->xDimension * eg->zDimension;
    1507           7 :         if (pt_count>eg->height.count) return;
    1508             : 
    1509           7 :         smooth_normals = (!has_normal && (eg->creaseAngle > FIX_EPSILON)) ? 1 : 0;
    1510             : 
    1511             :         faces = NULL;
    1512             :         faces_info = NULL;
    1513             :         pts_info = NULL;
    1514             : 
    1515           7 :         zDimension = (u32) eg->zDimension;
    1516           7 :         xDimension = (u32) eg->xDimension;
    1517             :         cur_face = 0;
    1518             :         pt_idx = 0;
    1519             : 
    1520             :         /*basic case: nothing specified but the points*/
    1521           7 :         if (!smooth_normals && !has_color && !has_normal && !has_txcoord) {
    1522           0 :                 for (j=0; j<zDimension; j++) {
    1523           0 :                         for (i=0; i<xDimension; i++) {
    1524           0 :                                 vx.pos.z = eg->zSpacing * j;
    1525           0 :                                 vx.pos.y = eg->height.vals[i +j*xDimension];
    1526           0 :                                 vx.pos.x = eg->xSpacing * i;
    1527           0 :                                 vx.texcoords.x = INT2FIX(i) / (xDimension - 1);
    1528           0 :                                 vx.texcoords.y = INT2FIX(j) / (zDimension - 1);
    1529             : 
    1530           0 :                                 mesh_set_vertex_vx(mesh, &vx);
    1531             :                         }
    1532             :                 }
    1533           0 :                 for (j=0; j<zDimension-1; j++) {
    1534           0 :                         u32 z0 = (j)*xDimension;
    1535           0 :                         u32 z1 = (j+1)*xDimension;
    1536           0 :                         for (i=0; i<xDimension-1; i++) {
    1537           0 :                                 mesh_set_triangle(mesh, i+z0, i+z1, i+z1+1);
    1538           0 :                                 mesh_set_triangle(mesh, i+z0, i+z1+1, i+z0+1);
    1539             : 
    1540           0 :                                 gf_vec_diff(v1, mesh->vertices[i+z0].pos, mesh->vertices[i+z0+1].pos);
    1541           0 :                                 gf_vec_diff(v2, mesh->vertices[i+z1+1].pos, mesh->vertices[i+z0+1].pos);
    1542           0 :                                 n = gf_vec_cross(v1, v2);
    1543           0 :                                 gf_vec_norm(&n);
    1544           0 :                                 MESH_SET_NORMAL(mesh->vertices[i+z0], n);
    1545           0 :                                 MESH_SET_NORMAL(mesh->vertices[i+z0+1], n);
    1546           0 :                                 MESH_SET_NORMAL(mesh->vertices[i+z1], n);
    1547           0 :                                 MESH_SET_NORMAL(mesh->vertices[i+z1+1], n);
    1548             :                         }
    1549             :                 }
    1550           0 :                 mesh->mesh_type = MESH_TRIANGLES;
    1551           0 :                 mesh_update_bounds(mesh);
    1552           0 :                 if (!eg->ccw) mesh->flags |= MESH_IS_CW;
    1553           0 :                 if (eg->solid) mesh->flags |= MESH_IS_SOLID;
    1554           0 :                 gf_mesh_build_aabbtree(mesh);
    1555           0 :                 return;
    1556             :         }
    1557             : 
    1558             :         /*alloc face & normals tables*/
    1559           7 :         if (smooth_normals) {
    1560           7 :                 faces = (GF_Mesh **)gf_malloc(sizeof(GF_Mesh *)*face_count);
    1561           7 :                 if (!faces) return;
    1562           7 :                 faces_info = (struct face_info*)gf_malloc(sizeof(struct face_info)*face_count);
    1563           7 :                 if (!faces_info) return;
    1564             :                 memset(faces_info, 0, sizeof(struct face_info)*face_count);
    1565           7 :                 pts_info = (struct pt_info*)gf_malloc(sizeof(struct pt_info)*pt_count);
    1566           7 :                 if (!pts_info) return;
    1567             :                 memset(pts_info, 0, sizeof(struct pt_info)*pt_count);
    1568           7 :                 faces[cur_face] = new_mesh();
    1569           7 :                 if (!faces[cur_face]) return;
    1570             :         }
    1571             : 
    1572          77 :         for (j=0; j<zDimension-1; j++) {
    1573         770 :                 for (i = 0; i < xDimension-1; i++) {
    1574             :                         u32 k, l;
    1575             :                         /*get face color*/
    1576         770 :                         if (has_color && !eg->colorPerVertex) {
    1577           0 :                                 idx = i + j * (xDimension-1);
    1578             : #ifndef GPAC_DISABLE_X3D
    1579           0 :                                 MESH_GET_COL(rgba, idx);
    1580             : #endif
    1581           0 :                                 vx.color = MESH_MAKE_COL(rgba);
    1582             :                         }
    1583             :                         /*get face normal*/
    1584         770 :                         if (has_normal && !eg->normalPerVertex) {
    1585           0 :                                 idx = i + j * (xDimension-1);
    1586           0 :                                 if (idx<norm->vector.count) {
    1587           0 :                                         n = norm->vector.vals[idx];
    1588           0 :                                         gf_vec_norm(&n);
    1589           0 :                                         MESH_SET_NORMAL(vx, n);
    1590             :                                 }
    1591             :                         }
    1592             : 
    1593        1540 :                         for (k=0; k<2; k++) {
    1594        1540 :                                 vx.pos.z = eg->zSpacing * (j+k);
    1595        4620 :                                 for (l=0; l<2; l++) {
    1596             : 
    1597        3080 :                                         vx.pos.y = eg->height.vals[(i+l) +(j+k)*xDimension];
    1598        3080 :                                         vx.pos.x = eg->xSpacing * (i+l);
    1599             : 
    1600             :                                         /*get color per vertex*/
    1601        3080 :                                         if (has_color && eg->colorPerVertex) {
    1602             :                                                 idx = i+l + (j+k) * xDimension;
    1603             : #ifndef GPAC_DISABLE_X3D
    1604           0 :                                                 MESH_GET_COL(rgba, idx);
    1605             : #endif
    1606           0 :                                                 vx.color = MESH_MAKE_COL(rgba);
    1607             :                                         }
    1608             :                                         /*get tex coord*/
    1609        3080 :                                         if (!has_txcoord) {
    1610        3080 :                                                 vx.texcoords.x = INT2FIX(i+l) / (xDimension - 1);
    1611        3080 :                                                 vx.texcoords.y = INT2FIX(j+k) / (zDimension - 1);
    1612             :                                         } else {
    1613             :                                                 idx = (i+l) +(j+k)*xDimension;
    1614           0 :                                                 if (idx<txc->point.count) vx.texcoords = txc->point.vals[idx];
    1615             :                                         }
    1616             :                                         /*get normal per vertex*/
    1617        3080 :                                         if (has_normal && eg->normalPerVertex) {
    1618             :                                                 idx = (i+l) + (j+k) * xDimension;
    1619           0 :                                                 if (idx<norm->vector.count) {
    1620           0 :                                                         n = norm->vector.vals[idx];
    1621           0 :                                                         gf_vec_norm(&n);
    1622           0 :                                                         MESH_SET_NORMAL(vx, n);
    1623             :                                                 }
    1624             :                                         }
    1625             :                                         /*update face to point and point to face structures*/
    1626        3080 :                                         if (smooth_normals) {
    1627        3080 :                                                 mesh_set_vertex_vx(faces[cur_face], &vx);
    1628        3080 :                                                 register_point_in_face(&faces_info[cur_face], (i+l) + (j+k)*xDimension);
    1629        3080 :                                                 register_face_in_point(&pts_info[(i+l) + (j+k)*xDimension], cur_face);
    1630             :                                         } else {
    1631           0 :                                                 mesh_set_vertex_vx(mesh, &vx);
    1632             :                                         }
    1633             :                                 }
    1634             : 
    1635             :                         }
    1636             : 
    1637             :                         /*compute face normal*/
    1638         770 :                         if (smooth_normals) {
    1639         770 :                                 mesh_set_triangle(faces[cur_face], 0, 2, 3);
    1640         770 :                                 mesh_set_triangle(faces[cur_face], 0, 3, 1);
    1641         770 :                                 gf_vec_diff(v1, faces[cur_face]->vertices[0].pos, faces[cur_face]->vertices[1].pos);
    1642         770 :                                 gf_vec_diff(v2, faces[cur_face]->vertices[3].pos, faces[cur_face]->vertices[1].pos);
    1643         770 :                                 faces_info[cur_face].nor = gf_vec_cross(v1, v2);
    1644         770 :                                 gf_vec_norm(&faces_info[cur_face].nor);
    1645             :                                 /*done with face*/
    1646         770 :                                 cur_face++;
    1647         770 :                                 if (cur_face<face_count) {
    1648         763 :                                         faces[cur_face] = new_mesh();
    1649         763 :                                         if (!faces[cur_face]) return;
    1650             :                                 }
    1651             :                         } else {
    1652           0 :                                 mesh_set_triangle(mesh, pt_idx+0, pt_idx+2, pt_idx+3);
    1653           0 :                                 mesh_set_triangle(mesh, pt_idx+0, pt_idx+3, pt_idx+1);
    1654             : 
    1655           0 :                                 if (!has_normal) {
    1656           0 :                                         gf_vec_diff(v1, mesh->vertices[pt_idx+0].pos, mesh->vertices[pt_idx+1].pos);
    1657           0 :                                         gf_vec_diff(v2, mesh->vertices[pt_idx+3].pos, mesh->vertices[pt_idx+1].pos);
    1658           0 :                                         n = gf_vec_cross(v1, v2);
    1659           0 :                                         gf_vec_norm(&n);
    1660           0 :                                         MESH_SET_NORMAL(mesh->vertices[pt_idx+0], n);
    1661           0 :                                         MESH_SET_NORMAL(mesh->vertices[pt_idx+1], n);
    1662           0 :                                         MESH_SET_NORMAL(mesh->vertices[pt_idx+2], n);
    1663           0 :                                         MESH_SET_NORMAL(mesh->vertices[pt_idx+3], n);
    1664             :                                 }
    1665           0 :                                 pt_idx+=4;
    1666             :                         }
    1667             :                 }
    1668             :         }
    1669             : 
    1670             :         /*generate normals*/
    1671           7 :         if (smooth_normals) {
    1672             :                 Fixed cosCrease;
    1673             :                 /*we only support 0->PI, whatever exceeds is smoothest*/
    1674           7 :                 if (eg->creaseAngle>GF_PI) cosCrease = -FIX_ONE;
    1675           7 :                 else cosCrease = gf_cos(eg->creaseAngle);
    1676             : 
    1677         777 :                 for (i=0; i<face_count; i++) {
    1678        3080 :                         for (j=0; j<faces[i]->v_count; j++) {
    1679        3080 :                                 n = smooth_face_normals(pts_info, pt_count, faces_info, face_count, j, i, cosCrease);
    1680        3080 :                                 MESH_SET_NORMAL(faces[i]->vertices[j], n);
    1681             :                         }
    1682             :                 }
    1683             : 
    1684           7 :                 if (faces_info) {
    1685         770 :                         for (i=0; i<face_count; i++) if (faces_info[i].idx) gf_free(faces_info[i].idx);
    1686           7 :                         gf_free(faces_info);
    1687             :                 }
    1688           7 :                 if (pts_info) {
    1689         924 :                         for (i=0; i<pt_count; i++) if (pts_info[i].faces) gf_free(pts_info[i].faces);
    1690           7 :                         gf_free(pts_info);
    1691             :                 }
    1692           7 :                 mesh->flags |= MESH_IS_SMOOTHED;
    1693             : 
    1694             : 
    1695         777 :                 for (i=0; i<face_count; i++) {
    1696         770 :                         if (faces[i]->v_count) {
    1697             :                                 u32 init_idx;
    1698             :                                 GF_Mesh *face = faces[i];
    1699         770 :                                 init_idx = mesh->v_count;
    1700             :                                 /*quads only*/
    1701         770 :                                 mesh_set_vertex_vx(mesh, &face->vertices[0]);
    1702         770 :                                 mesh_set_vertex_vx(mesh, &face->vertices[1]);
    1703         770 :                                 mesh_set_vertex_vx(mesh, &face->vertices[2]);
    1704         770 :                                 mesh_set_vertex_vx(mesh, &face->vertices[3]);
    1705         770 :                                 mesh_set_triangle(mesh, init_idx, init_idx + 2, init_idx + 3);
    1706         770 :                                 mesh_set_triangle(mesh, init_idx, init_idx + 3, init_idx + 1);
    1707             :                         }
    1708         770 :                         mesh_free(faces[i]);
    1709             :                 }
    1710             : 
    1711             :                 /*destroy faces*/
    1712           7 :                 gf_free(faces);
    1713             :         }
    1714             : 
    1715           7 :         mesh->mesh_type = MESH_TRIANGLES;
    1716           7 :         if (has_color) mesh->flags |= MESH_HAS_COLOR;
    1717           7 :         mesh_update_bounds(mesh);
    1718           7 :         if (!eg->ccw) mesh->flags |= MESH_IS_CW;
    1719           7 :         if (eg->solid) mesh->flags |= MESH_IS_SOLID;
    1720             : #ifndef GPAC_DISABLE_X3D
    1721           7 :         if (colorRGBA) mesh->flags |= MESH_HAS_ALPHA;
    1722             : #endif
    1723           7 :         gf_mesh_build_aabbtree(mesh);
    1724             : }
    1725             : 
    1726             : 
    1727             : typedef struct
    1728             : {
    1729             :         SFVec3f yaxis, zaxis, xaxis;
    1730             : } SCP;
    1731             : 
    1732             : typedef struct
    1733             : {
    1734             :         SFVec3f pt, yaxis, zaxis, xaxis;
    1735             :         u32 max_idx;
    1736             : } SCPInfo;
    1737             : 
    1738             : #define REGISTER_POINT_FACE(FACE_IDX) \
    1739             :         {       u32 fidx;       \
    1740             :                 fidx = FACE_IDX; \
    1741             :                 mesh_set_vertex_vx(faces[fidx], &vx);       \
    1742             :                 if (smooth_normals) {   \
    1743             :                         register_point_in_face(&faces_info[fidx], pidx);    \
    1744             :                         register_face_in_point(&pts_info[pidx], fidx);      \
    1745             :                 } \
    1746             :         } \
    1747             :  
    1748             : 
    1749             : #define NEAR_ZERO(__x) (ABS(__x)<=FIX_EPSILON)
    1750             : 
    1751           9 : static void mesh_extrude_path_intern(GF_Mesh *mesh, GF_Path *path, MFVec3f *thespine, Fixed creaseAngle, Fixed min_cx, Fixed min_cy, Fixed width_cx, Fixed width_cy, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool tx_along_spine)
    1752             : {
    1753             :         GF_Mesh **faces;
    1754             :         GF_Vertex vx;
    1755             :         struct face_info *faces_info;
    1756             :         struct pt_info *pts_info;
    1757             :         GF_Matrix mx;
    1758             :         SCP *SCPs, SCPbegin, SCPend;
    1759             :         SCPInfo *SCPi;
    1760             :         Bool smooth_normals, spine_closed, check_first_spine_vec, do_close;
    1761             :         u32 i, j, k, nb_scp, nb_spine, face_count, pt_count, faces_per_cross, begin_face, end_face, face_spines, pts_per_cross, cur_pts_in_cross,cur, nb_pts, convexity;
    1762             :         SFVec3f *spine, v1, v2, n, spine_vec;
    1763             :         Fixed cross_len, spine_len, cur_cross, cur_spine;
    1764             :         SFRotation r;
    1765             :         SFVec2f scale;
    1766             : 
    1767           9 :         if (!path->n_contours) return;
    1768           9 :         if (path->n_points<2) return;
    1769           9 :         if (thespine->count<2) return;
    1770             : 
    1771             :         spine_closed = 0;
    1772           9 :         if (gf_vec_equal(thespine->vals[0], thespine->vals[thespine->count-1])) spine_closed = 1;
    1773           1 :         if (spine_closed && (thespine->count==2)) return;
    1774             : 
    1775           9 :         gf_path_flatten(path);
    1776             : 
    1777             :         memset(&vx, 0, sizeof(GF_Vertex));
    1778             :         pts_per_cross = 0;
    1779             :         cross_len = 0;
    1780             :         cur = 0;
    1781          18 :         for (i=0; i<path->n_contours; i++) {
    1782           9 :                 nb_pts = 1 + path->contours[i] - cur;
    1783           9 :                 pts_per_cross += nb_pts;
    1784             :                 v1.z = 0;
    1785         237 :                 for (j=1; j<nb_pts; j++) {
    1786         228 :                         v1.x = path->points[j+cur].x - path->points[j-1+cur].x;
    1787         228 :                         v1.y = path->points[j+cur].y - path->points[j-1+cur].y;
    1788         228 :                         cross_len += gf_vec_len(v1);
    1789             :                 }
    1790             :         }
    1791             : 
    1792           9 :         faces_per_cross = pts_per_cross - path->n_contours;
    1793             :         begin_face = end_face = 0;
    1794           9 :         face_spines = face_count = (thespine->count-1)*faces_per_cross;
    1795           9 :         if (begin_cap) {
    1796             :                 begin_face = face_count;
    1797           8 :                 face_count ++;
    1798             :         }
    1799           9 :         if (end_cap) {
    1800             :                 end_face = face_count;
    1801           0 :                 face_count ++;
    1802             :         }
    1803             : 
    1804           9 :         pt_count = pts_per_cross * thespine->count;
    1805           9 :         smooth_normals = NEAR_ZERO(creaseAngle) ? 0 : 1;
    1806             : 
    1807           9 :         faces = (GF_Mesh**)gf_malloc(sizeof(GF_Mesh *)*face_count);
    1808           9 :         for (i=0; i<face_count; i++) faces[i] = new_mesh();
    1809             :         faces_info = NULL;
    1810             :         pts_info = NULL;
    1811             : 
    1812             :         /*alloc face & normals tables*/
    1813           9 :         if (smooth_normals) {
    1814           9 :                 faces_info = (struct face_info*)gf_malloc(sizeof(struct face_info)*face_count);
    1815             :                 memset(faces_info, 0, sizeof(struct face_info)*face_count);
    1816           9 :                 pts_info = (struct pt_info*)gf_malloc(sizeof(struct pt_info)*pt_count);
    1817             :                 memset(pts_info, 0, sizeof(struct pt_info)*pt_count);
    1818             :         }
    1819             : 
    1820             : 
    1821           9 :         spine = thespine->vals;
    1822           9 :         nb_spine = thespine->count;
    1823           9 :         SCPs = (SCP *)gf_malloc(sizeof(SCP) * nb_spine);
    1824             :         memset(SCPs, 0, sizeof(SCP) * nb_spine);
    1825           9 :         SCPi = (SCPInfo *) gf_malloc(sizeof(SCPInfo) * nb_spine);
    1826             :         memset(SCPi, 0, sizeof(SCPInfo) * nb_spine);
    1827             : 
    1828             :         /*collect all # SCPs:
    1829             :         1- if a spine has identical consecutive points with # orientation, these points use the same SCPs
    1830             :         2- if 2 segs of the spine are colinear, they also use the same SCP
    1831             :         */
    1832           9 :         SCPi[0].pt = spine[0];
    1833           9 :         SCPi[0].max_idx = 0;
    1834             :         nb_scp=1;
    1835             :         spine_len = 0;
    1836             :         check_first_spine_vec = 1;
    1837         135 :         for (i=1; i<nb_spine; i++) {
    1838             :                 Fixed len;
    1839             :                 /*also get spine length for txcoord*/
    1840         135 :                 gf_vec_diff(v2, spine[i], spine[i-1]);
    1841         135 :                 len = gf_vec_len(v2);
    1842         135 :                 spine_len += len;
    1843         135 :                 if (check_first_spine_vec && len) {
    1844             :                         check_first_spine_vec = 0;
    1845           9 :                         spine_vec = v2;
    1846             :                 }
    1847             : 
    1848             :                 /*case 1: same point, same SCP*/
    1849         135 :                 if (gf_vec_equal(SCPi[nb_scp-1].pt, spine[i])) {
    1850           0 :                         SCPi[nb_scp-1].max_idx = i;
    1851           0 :                         continue;
    1852             :                 }
    1853             :                 /*last point in spine*/
    1854         135 :                 if (i+1 == nb_spine) {
    1855           9 :                         nb_scp++;
    1856           9 :                         SCPi[nb_scp-1].pt = spine[i];
    1857           9 :                         SCPi[nb_scp-1].max_idx = i;
    1858           9 :                         break;
    1859             :                 }
    1860             : 
    1861         126 :                 gf_vec_diff(v1, spine[i+1], spine[i]);
    1862         126 :                 gf_vec_diff(v2, SCPi[nb_scp-1].pt, spine[i]);
    1863         126 :                 n = gf_vec_cross(v1, v2);
    1864             :                 /*case 2: spine segs are colinear*/
    1865         126 :                 if (!n.x && !n.y && !n.z) {
    1866          63 :                         SCPi[nb_scp-1].max_idx = i;
    1867             :                 }
    1868             :                 /*OK new SCP*/
    1869             :                 else {
    1870          63 :                         nb_scp++;
    1871          63 :                         SCPi[nb_scp-1].pt = spine[i];
    1872          63 :                         SCPi[nb_scp-1].max_idx = i;
    1873             :                 }
    1874             :         }
    1875             : 
    1876             :         /*all colinear!!*/
    1877           9 :         if (nb_scp<=2) {
    1878           8 :                 SCPi[0].xaxis.x = FIX_ONE;
    1879           8 :                 SCPi[0].xaxis.y = 0;
    1880           8 :                 SCPi[0].xaxis.z = 0;
    1881           8 :                 SCPi[0].yaxis.x = 0;
    1882           8 :                 SCPi[0].yaxis.y = FIX_ONE;
    1883           8 :                 SCPi[0].yaxis.z = 0;
    1884           8 :                 SCPi[0].zaxis.x = 0;
    1885           8 :                 SCPi[0].zaxis.y = 0;
    1886           8 :                 SCPi[0].zaxis.z = FIX_ONE;
    1887             :                 /*compute rotation from (0, 1, 0) to spine_vec*/
    1888           8 :                 if (!check_first_spine_vec) {
    1889             :                         Fixed alpha, gamma;
    1890             :                         Fixed cos_a, sin_a, sin_g, cos_g;
    1891             : 
    1892           8 :                         gf_vec_norm(&spine_vec);
    1893           8 :                         if (! NEAR_ZERO(spine_vec.x) ) {
    1894           0 :                                 if (spine_vec.x >= FIX_ONE-FIX_EPSILON) alpha = GF_PI2;
    1895           0 :                                 else if (spine_vec.x <= -FIX_ONE+FIX_EPSILON) alpha = -GF_PI2;
    1896           0 :                                 else alpha = gf_asin(spine_vec.x);
    1897           0 :                                 cos_a = gf_cos(alpha);
    1898           0 :                                 sin_a = spine_vec.x;
    1899             : 
    1900           0 :                                 if (NEAR_ZERO(cos_a)) gamma = 0;
    1901             :                                 else {
    1902             :                                         Fixed __abs;
    1903           0 :                                         gamma = gf_acos(gf_divfix(spine_vec.y, cos_a));
    1904           0 :                                         sin_g = gf_sin(gamma);
    1905           0 :                                         __abs = gf_divfix(spine_vec.z, cos_a) + sin_g;
    1906           0 :                                         if (ABS(__abs) > ABS(sin_g) ) gamma *= -1;
    1907             :                                 }
    1908           0 :                                 cos_g = gf_cos(gamma);
    1909           0 :                                 if (NEAR_ZERO(cos_g)) {
    1910             :                                         cos_g = 0;
    1911             :                                         sin_g = FIX_ONE;
    1912             :                                 } else {
    1913           0 :                                         sin_g = gf_sin(gamma);
    1914             :                                 }
    1915           0 :                                 SCPi[0].yaxis.y = gf_mulfix(cos_a, sin_g);
    1916           0 :                                 SCPi[0].yaxis.z = gf_mulfix(cos_a, cos_g);
    1917           0 :                                 SCPi[0].yaxis.x = sin_a;
    1918           0 :                                 SCPi[0].zaxis.y = -gf_mulfix(sin_a, sin_g);
    1919           0 :                                 SCPi[0].zaxis.z = -gf_mulfix(sin_a, cos_g);
    1920           0 :                                 SCPi[0].zaxis.x = cos_a;
    1921             :                         }
    1922           8 :                         if (! NEAR_ZERO(spine_vec.z) ) {
    1923           0 :                                 if (spine_vec.z >= FIX_ONE-FIX_EPSILON) alpha = GF_PI2;
    1924           0 :                                 else if (spine_vec.z <= -FIX_ONE+FIX_EPSILON) alpha = -GF_PI2;
    1925           0 :                                 else alpha = gf_asin(spine_vec.z);
    1926           0 :                                 cos_a = gf_cos(alpha);
    1927           0 :                                 sin_a = spine_vec.z;
    1928             : 
    1929           0 :                                 if (NEAR_ZERO(cos_a) ) gamma = 0;
    1930             :                                 else {
    1931             :                                         Fixed __abs;
    1932           0 :                                         gamma = gf_acos(gf_divfix(spine_vec.y, cos_a));
    1933           0 :                                         sin_g = gf_sin(gamma);
    1934           0 :                                         __abs = gf_divfix(spine_vec.x, cos_a) + sin_g;
    1935           0 :                                         if (ABS(__abs) > ABS(sin_g) ) gamma *= -1;
    1936             :                                 }
    1937           0 :                                 cos_g = gf_cos(gamma);
    1938           0 :                                 sin_g = gf_sin(gamma);
    1939           0 :                                 SCPi[0].yaxis.y = gf_mulfix(cos_a, sin_g);
    1940           0 :                                 SCPi[0].yaxis.x = gf_mulfix(cos_a, cos_g);
    1941           0 :                                 SCPi[0].yaxis.z = sin_a;
    1942           0 :                                 SCPi[0].zaxis.y = -gf_mulfix(sin_a, sin_g);
    1943           0 :                                 SCPi[0].zaxis.x = -gf_mulfix(sin_a, cos_g);
    1944           0 :                                 SCPi[0].zaxis.z = cos_a;
    1945             :                         }
    1946             :                 }
    1947          79 :                 for (i=0; i<nb_spine; i++) {
    1948          79 :                         SCPs[i].xaxis = SCPi[0].xaxis;
    1949          79 :                         SCPs[i].yaxis = SCPi[0].yaxis;
    1950          79 :                         SCPs[i].zaxis = SCPi[0].zaxis;
    1951             :                 }
    1952             :         }
    1953             :         /*not colinear*/
    1954             :         else {
    1955             :                 assert(nb_scp<=nb_spine);
    1956             : 
    1957             :                 /*now non-cap SCPs axis*/
    1958          64 :                 for (i=1; i<nb_scp-1; i++) {
    1959             :                         /*get Y axis*/
    1960          63 :                         gf_vec_diff(SCPi[i].yaxis, SCPi[i+1].pt, SCPi[i-1].pt);
    1961             :                         /*get Z axis*/
    1962          63 :                         gf_vec_diff(v1, SCPi[i+1].pt, SCPi[i].pt);
    1963          63 :                         gf_vec_diff(v2, SCPi[i-1].pt, SCPi[i].pt);
    1964          63 :                         SCPi[i].zaxis = gf_vec_cross(v1, v2);
    1965             :                 }
    1966             :                 /*compute head and tail*/
    1967           1 :                 if (spine_closed) {
    1968           1 :                         gf_vec_diff(SCPi[0].yaxis, SCPi[1].pt, SCPi[nb_scp-2].pt);
    1969           1 :                         gf_vec_diff(v1, SCPi[1].pt, SCPi[0].pt);
    1970           1 :                         gf_vec_diff(v2, SCPi[nb_scp-2].pt, SCPi[0].pt);
    1971           1 :                         SCPi[0].zaxis = gf_vec_cross(v1, v2);
    1972           1 :                         SCPi[nb_scp-1].yaxis = SCPi[0].yaxis;
    1973           1 :                         SCPi[nb_scp-1].zaxis = SCPi[0].zaxis;
    1974             :                 } else {
    1975           0 :                         gf_vec_diff(SCPi[0].yaxis, SCPi[1].pt, SCPi[0].pt);
    1976           0 :                         SCPi[0].zaxis = SCPi[1].zaxis;
    1977           0 :                         gf_vec_diff(SCPi[nb_scp-1].yaxis, SCPi[nb_scp-1].pt, SCPi[nb_scp-2].pt);
    1978           0 :                         SCPi[nb_scp-1].zaxis = SCPi[nb_scp-2].zaxis;
    1979             :                 }
    1980             :                 /*check orientation*/
    1981          64 :                 for (i=1; i<nb_scp; i++) {
    1982          64 :                         Fixed res = gf_vec_dot(SCPi[i].zaxis, SCPi[i-1].zaxis);
    1983          64 :                         if (res<0) gf_vec_rev(SCPi[i].zaxis);
    1984             :                 }
    1985             :                 /*and assign SCPs*/
    1986             :                 j=0;
    1987          65 :                 for (i=0; i<nb_scp; i++) {
    1988             :                         /*compute X, norm vectors*/
    1989          65 :                         SCPi[i].xaxis = gf_vec_cross(SCPi[i].yaxis, SCPi[i].zaxis);
    1990          65 :                         gf_vec_norm(&SCPi[i].xaxis);
    1991          65 :                         gf_vec_norm(&SCPi[i].yaxis);
    1992          65 :                         gf_vec_norm(&SCPi[i].zaxis);
    1993             :                         /*assign SCPs*/
    1994         195 :                         while (j<=SCPi[i].max_idx) {
    1995          65 :                                 SCPs[j].xaxis = SCPi[i].xaxis;
    1996          65 :                                 SCPs[j].yaxis = SCPi[i].yaxis;
    1997          65 :                                 SCPs[j].zaxis = SCPi[i].zaxis;
    1998          65 :                                 j++;
    1999             :                         }
    2000             :                 }
    2001             :         }
    2002           9 :         gf_free(SCPi);
    2003             : 
    2004             :         r.x = r.q = r.z = 0;
    2005             :         r.y = FIX_ONE;
    2006             :         scale.x = scale.y = FIX_ONE;
    2007             : 
    2008             :         cur_spine = 0;
    2009             :         /*insert all points of the extrusion*/
    2010         162 :         for (i=0; i<nb_spine; i++) {
    2011             :                 u32 cur_face_in_cross;
    2012             :                 SCP *curSCP;
    2013             : 
    2014         144 :                 if (spine_closed && (i+1==nb_spine)) {
    2015             :                         curSCP = &SCPs[0];
    2016             :                         do_close =  1;
    2017             :                 } else {
    2018         143 :                         curSCP = &SCPs[i];
    2019             :                         do_close =  0;
    2020             : 
    2021             :                         /*compute X*/
    2022         143 :                         curSCP->xaxis = gf_vec_cross(curSCP->yaxis, curSCP->zaxis);
    2023         143 :                         gf_vec_norm(&curSCP->xaxis);
    2024         143 :                         gf_vec_norm(&curSCP->yaxis);
    2025         143 :                         gf_vec_norm(&curSCP->zaxis);
    2026             : 
    2027         143 :                         if (spine_ori && (i<spine_ori->count)) r = spine_ori->vals[i];
    2028         143 :                         if (spine_scale && (i<spine_scale->count)) scale = spine_scale->vals[i];
    2029             : 
    2030         143 :                         gf_mx_init(mx);
    2031         143 :                         gf_mx_add_rotation(&mx, r.q, r.x, r.y, r.z);
    2032         143 :                         gf_mx_apply_vec(&mx, &curSCP->xaxis);
    2033         143 :                         gf_mx_apply_vec(&mx, &curSCP->yaxis);
    2034         143 :                         gf_mx_apply_vec(&mx, &curSCP->zaxis);
    2035             :                 }
    2036             : 
    2037         144 :                 vx.texcoords.y = gf_divfix(cur_spine, spine_len);
    2038             : 
    2039             :                 cur_pts_in_cross = 0;
    2040             :                 cur_face_in_cross = 0;
    2041             :                 cur = 0;
    2042         288 :                 for (j=0; j<path->n_contours; j++) {
    2043             :                         Bool subpath_closed;
    2044         144 :                         nb_pts = 1+path->contours[j] - cur;
    2045             :                         cur_cross = 0;
    2046             :                         subpath_closed = 0;
    2047         144 :                         if ((path->points[cur].x==path->points[path->contours[j]].x) && (path->points[cur].y==path->points[path->contours[j]].y))
    2048             :                                 subpath_closed = 1;
    2049             : 
    2050        5928 :                         for (k=0; k<nb_pts; k++) {
    2051        5640 :                                 u32 pidx = k + cur_pts_in_cross + i*pts_per_cross;
    2052        5640 :                                 if (do_close) pidx = k + cur_pts_in_cross;
    2053             : 
    2054        5640 :                                 v1.x = path->points[k+cur].x;
    2055        5640 :                                 v1.z = path->points[k+cur].y;
    2056             : 
    2057        5640 :                                 if (tx_along_spine) {
    2058        5534 :                                         vx.texcoords.x = gf_divfix(cur_cross, cross_len);
    2059             :                                 } else {
    2060         106 :                                         vx.texcoords.x = gf_divfix(v1.x - min_cx, width_cx);
    2061         106 :                                         vx.texcoords.y = gf_divfix(v1.z - min_cy, width_cy);
    2062             :                                 }
    2063             : 
    2064             :                                 /*handle closed cross-section*/
    2065        5640 :                                 if (subpath_closed && (k+1==nb_pts)) {
    2066         144 :                                         pidx = cur_pts_in_cross + i*pts_per_cross;
    2067         144 :                                         if (do_close) pidx = cur_pts_in_cross;
    2068             : 
    2069         144 :                                         v1.x = path->points[cur].x;
    2070         144 :                                         v1.z = path->points[cur].y;
    2071             :                                 }
    2072        5640 :                                 v1.x = gf_mulfix(v1.x, scale.x);
    2073        5640 :                                 v1.z = gf_mulfix(v1.z, scale.y);
    2074             :                                 v1.y = 0;
    2075        5640 :                                 vx.pos.x = gf_mulfix(v1.x, curSCP->xaxis.x) + gf_mulfix(v1.y, curSCP->yaxis.x) + gf_mulfix(v1.z, curSCP->zaxis.x) + spine[i].x;
    2076        5640 :                                 vx.pos.y = gf_mulfix(v1.x, curSCP->xaxis.y) + gf_mulfix(v1.y, curSCP->yaxis.y) + gf_mulfix(v1.z, curSCP->zaxis.y) + spine[i].y;
    2077        5640 :                                 vx.pos.z = gf_mulfix(v1.x, curSCP->xaxis.z) + gf_mulfix(v1.y, curSCP->yaxis.z) + gf_mulfix(v1.z, curSCP->zaxis.z) + spine[i].z;
    2078             : 
    2079             :                                 /*in current spine*/
    2080        5640 :                                 if (i+1<nb_spine) {
    2081             :                                         /*current face*/
    2082        5403 :                                         if (k<nb_pts-1) REGISTER_POINT_FACE(k + cur_face_in_cross + i*faces_per_cross);
    2083             :                                         /*previous face*/
    2084        5403 :                                         if (k) REGISTER_POINT_FACE(k-1 + cur_face_in_cross + i*faces_per_cross);
    2085             :                                 }
    2086             :                                 /*first spine*/
    2087         237 :                                 else if (smooth_normals && do_close) {
    2088          65 :                                         if (k<nb_pts-1) {
    2089          64 :                                                 register_point_in_face(&faces_info[k + cur_face_in_cross], pidx);
    2090          64 :                                                 register_face_in_point(&pts_info[pidx], k + cur_face_in_cross);
    2091             :                                         }
    2092             :                                         /*previous face*/
    2093          65 :                                         if (k) {
    2094          64 :                                                 register_point_in_face(&faces_info[k-1 + cur_face_in_cross], pidx);
    2095          64 :                                                 register_face_in_point(&pts_info[pidx], k-1 + cur_face_in_cross);
    2096             :                                         }
    2097             :                                 }
    2098             :                                 /*in previous spine*/
    2099        5640 :                                 if (i) {
    2100             :                                         /*face "below" face*/
    2101        5403 :                                         if (k<nb_pts-1) REGISTER_POINT_FACE(k + cur_face_in_cross + (i-1)*faces_per_cross);
    2102             :                                         /*previous face "below" face*/
    2103        5403 :                                         if (k) REGISTER_POINT_FACE(k-1 + cur_face_in_cross + (i-1)*faces_per_cross);
    2104             :                                 }
    2105             : 
    2106        5640 :                                 if (k+1<nb_pts) {
    2107             :                                         v1.z = 0;
    2108        5496 :                                         v1.x = path->points[k+1+cur].x - path->points[k+cur].x;
    2109        5496 :                                         v1.y = path->points[k+1+cur].y - path->points[k+cur].y;
    2110        5496 :                                         cur_cross += gf_vec_len(v1);
    2111             :                                 }
    2112             : 
    2113             :                         }
    2114         144 :                         cur_face_in_cross += nb_pts-1;
    2115         144 :                         cur_pts_in_cross += nb_pts;
    2116             :                         cur += nb_pts;
    2117             :                 }
    2118         144 :                 if (i+1<nb_spine) {
    2119         135 :                         gf_vec_diff(v1, spine[i+1], spine[i]);
    2120         135 :                         cur_spine += gf_vec_len(v1);
    2121             :                 }
    2122             :         }
    2123             : 
    2124             :         /*generate triangles & normals*/
    2125        5268 :         for (i=0; i<face_spines; i++) {
    2126        5268 :                 mesh_set_triangle(faces[i], 0, 1, 3);
    2127        5268 :                 mesh_set_triangle(faces[i], 0, 3, 2);
    2128        5268 :                 gf_vec_diff(v1, faces[i]->vertices[1].pos, faces[i]->vertices[0].pos);
    2129        5268 :                 gf_vec_diff(v2, faces[i]->vertices[3].pos, faces[i]->vertices[0].pos);
    2130        5268 :                 n = gf_vec_cross(v1, v2);
    2131        5268 :                 gf_vec_norm(&n);
    2132       26340 :                 for (j=0; j<faces[i]->v_count; j++) {
    2133       21072 :                         MESH_SET_NORMAL(faces[i]->vertices[j], n);
    2134       21072 :                         if (smooth_normals) faces_info[i].nor = n;
    2135             :                 }
    2136             :         }
    2137             : 
    2138             : 
    2139             :         /*generate begin cap*/
    2140           9 :         if (begin_face) {
    2141             :                 scale.x = scale.y = FIX_ONE;
    2142           8 :                 if (spine_scale && spine_scale->count) scale = spine_scale->vals[0];
    2143             : 
    2144             :                 /*get first SCP after rotation*/
    2145           8 :                 SCPbegin = SCPs[0];
    2146             : 
    2147           8 :                 n = SCPbegin.yaxis;
    2148           8 :                 gf_vec_norm(&n);
    2149             : 
    2150           8 :                 convexity = gf_polygone2d_get_convexity(path->points, path->n_points);
    2151           8 :                 switch (convexity) {
    2152             :                 case GF_POLYGON_CONVEX_CCW:
    2153             :                 case GF_POLYGON_COMPLEX_CCW:
    2154             :                         break;
    2155           8 :                 default:
    2156           8 :                         gf_vec_rev(n);
    2157           8 :                         break;
    2158             :                 }
    2159             : 
    2160           8 :                 MESH_SET_NORMAL(vx, n);
    2161             : 
    2162             : 
    2163           8 :                 if (smooth_normals) {
    2164           8 :                         faces_info[begin_face].nor = n;
    2165             :                         assert(gf_vec_len(n));
    2166             :                 }
    2167             :                 cur_pts_in_cross = 0;
    2168             :                 cur = 0;
    2169           8 :                 for (i=0; i<path->n_contours; i++) {
    2170             :                         Bool subpath_closed = 0;
    2171           8 :                         nb_pts = 1 + path->contours[i] - cur;
    2172           8 :                         if ((path->points[cur].x==path->points[path->contours[i]].x) && (path->points[cur].y==path->points[path->contours[i]].y))
    2173             :                                 subpath_closed = 1;
    2174             : 
    2175         180 :                         for (j=0; j<nb_pts; j++) {
    2176         172 :                                 u32 pidx = j + (pts_per_cross-1-cur_pts_in_cross);
    2177         172 :                                 v1.x = path->points[j+cur].x;
    2178         172 :                                 v1.z = path->points[j+cur].y;
    2179         172 :                                 vx.texcoords.x = gf_divfix(v1.x - min_cx, width_cx);
    2180         172 :                                 vx.texcoords.y = gf_divfix(v1.z - min_cy, width_cy);
    2181             :                                 /*handle closed cross-section*/
    2182         172 :                                 if (subpath_closed  && (j+1==nb_pts)) {
    2183           8 :                                         pidx = (pts_per_cross-1-cur_pts_in_cross);
    2184           8 :                                         v1.x = path->points[cur].x;
    2185           8 :                                         v1.z = path->points[cur].y;
    2186             :                                 }
    2187         172 :                                 v1.x = gf_mulfix(v1.x , scale.x);
    2188         172 :                                 v1.z = gf_mulfix(v1.z , scale.y);
    2189             :                                 v1.y = 0;
    2190         172 :                                 vx.pos.x = gf_mulfix(v1.x, SCPbegin.xaxis.x) + gf_mulfix(v1.y, SCPbegin.yaxis.x) + gf_mulfix(v1.z, SCPbegin.zaxis.x) + spine[0].x;
    2191         172 :                                 vx.pos.y = gf_mulfix(v1.x, SCPbegin.xaxis.y) + gf_mulfix(v1.y, SCPbegin.yaxis.y) + gf_mulfix(v1.z, SCPbegin.zaxis.y) + spine[0].y;
    2192         172 :                                 vx.pos.z = gf_mulfix(v1.x, SCPbegin.xaxis.z) + gf_mulfix(v1.y, SCPbegin.yaxis.z) + gf_mulfix(v1.z, SCPbegin.zaxis.z) + spine[0].z;
    2193         172 :                                 REGISTER_POINT_FACE(begin_face);
    2194             :                         }
    2195           8 :                         cur_pts_in_cross += nb_pts;
    2196             :                         cur += nb_pts;
    2197             :                 }
    2198             :         }
    2199             : 
    2200             :         /*generate end cap*/
    2201           9 :         if (end_face) {
    2202             :                 scale.x = scale.y = FIX_ONE;
    2203           0 :                 if (spine_scale && (nb_spine-1<spine_scale->count)) scale = spine_scale->vals[nb_spine-1];
    2204             :                 /*get last SCP after rotation*/
    2205           0 :                 SCPend = SCPs[nb_spine-1];
    2206             : 
    2207           0 :                 n = SCPend.yaxis;
    2208           0 :                 gf_vec_norm(&n);
    2209           0 :                 MESH_SET_NORMAL(vx, n);
    2210           0 :                 convexity = gf_polygone2d_get_convexity(path->points, path->n_points);
    2211           0 :                 switch (convexity) {
    2212           0 :                 case GF_POLYGON_CONVEX_CCW:
    2213             :                 case GF_POLYGON_COMPLEX_CCW:
    2214           0 :                         gf_vec_rev(vx.normal);
    2215           0 :                         gf_vec_rev(n);
    2216           0 :                         break;
    2217             :                 }
    2218             : 
    2219           0 :                 if (smooth_normals) {
    2220           0 :                         faces_info[end_face].nor = n;
    2221             :                         assert(gf_vec_len(n));
    2222             :                 }
    2223             :                 cur_pts_in_cross = 0;
    2224             : 
    2225             :                 cur = 0;
    2226           0 :                 for (i=0; i<path->n_contours; i++) {
    2227             :                         Bool subpath_closed = 0;
    2228           0 :                         nb_pts = 1 + path->contours[i] - cur;
    2229           0 :                         if ((path->points[cur].x==path->points[path->contours[i]].x) && (path->points[cur].y==path->points[path->contours[i]].y))
    2230             :                                 subpath_closed = 1;
    2231             : 
    2232           0 :                         for (j=0; j<nb_pts; j++) {
    2233           0 :                                 u32 pidx = j + cur_pts_in_cross + (nb_spine-1)*pts_per_cross;
    2234           0 :                                 v1.x = path->points[j+cur].x;
    2235           0 :                                 v1.z = path->points[j+cur].y;
    2236           0 :                                 vx.texcoords.x = gf_divfix(v1.x - min_cx, width_cx);
    2237           0 :                                 vx.texcoords.y = gf_divfix(v1.z - min_cy, width_cy);
    2238             :                                 /*handle closed cross-section*/
    2239           0 :                                 if (subpath_closed && (j+1==nb_pts)) {
    2240           0 :                                         pidx = cur_pts_in_cross + (nb_spine-1)*pts_per_cross;
    2241           0 :                                         v1.x = path->points[cur].x;
    2242           0 :                                         v1.z = path->points[cur].y;
    2243             :                                 }
    2244           0 :                                 v1.x = gf_mulfix(v1.x, scale.x);
    2245           0 :                                 v1.z = gf_mulfix(v1.z, scale.y);
    2246             :                                 v1.y = 0;
    2247           0 :                                 vx.pos.x = gf_mulfix(v1.x, SCPend.xaxis.x) + gf_mulfix(v1.y, SCPend.yaxis.x) + gf_mulfix(v1.z, SCPend.zaxis.x) + spine[nb_spine-1].x;
    2248           0 :                                 vx.pos.y = gf_mulfix(v1.x, SCPend.xaxis.y) + gf_mulfix(v1.y, SCPend.yaxis.y) + gf_mulfix(v1.z, SCPend.zaxis.y) + spine[nb_spine-1].y;
    2249           0 :                                 vx.pos.z = gf_mulfix(v1.x, SCPend.xaxis.z) + gf_mulfix(v1.y, SCPend.yaxis.z) + gf_mulfix(v1.z, SCPend.zaxis.z) + spine[nb_spine-1].z;
    2250             : 
    2251           0 :                                 REGISTER_POINT_FACE(end_face);
    2252             :                         }
    2253           0 :                         cur_pts_in_cross += nb_pts;
    2254             :                         cur += nb_pts;
    2255             :                 }
    2256             :         }
    2257             : 
    2258             : 
    2259           9 :         if (smooth_normals) {
    2260             :                 Fixed cosCrease;
    2261             :                 /*we only support 0->PI, whatever exceeds is smoothest*/
    2262           9 :                 if (creaseAngle>GF_PI) cosCrease = -FIX_ONE;
    2263           9 :                 else cosCrease = gf_cos(creaseAngle);
    2264             : 
    2265        5285 :                 for (i=0; i<face_count; i++) {
    2266       21244 :                         for (j=0; j<faces[i]->v_count; j++) {
    2267       21244 :                                 n = smooth_face_normals(pts_info, pt_count, faces_info, face_count, j, i, cosCrease);
    2268       21244 :                                 MESH_SET_NORMAL(faces[i]->vertices[j], n);
    2269             :                         }
    2270             :                 }
    2271             : 
    2272           9 :                 if (faces_info) {
    2273        5276 :                         for (i=0; i<face_count; i++) if (faces_info[i].idx) gf_free(faces_info[i].idx);
    2274           9 :                         gf_free(faces_info);
    2275             :                 }
    2276           9 :                 if (pts_info) {
    2277        5640 :                         for (i=0; i<pt_count; i++) if (pts_info[i].faces) gf_free(pts_info[i].faces);
    2278           9 :                         gf_free(pts_info);
    2279             :                 }
    2280           9 :                 mesh->flags |= MESH_IS_SMOOTHED;
    2281             :         }
    2282             : 
    2283           9 :         mesh->mesh_type = MESH_TRIANGLES;
    2284             : 
    2285        5277 :         for (i=0; i<face_spines; i++) {
    2286        5268 :                 if (faces[i]->v_count) {
    2287             :                         u32 init_idx;
    2288             :                         GF_Mesh *face = faces[i];
    2289        5268 :                         init_idx = mesh->v_count;
    2290             :                         /*quads only*/
    2291        5268 :                         mesh_set_vertex_vx(mesh, &face->vertices[0]);
    2292        5268 :                         mesh_set_vertex_vx(mesh, &face->vertices[1]);
    2293        5268 :                         mesh_set_vertex_vx(mesh, &face->vertices[2]);
    2294        5268 :                         mesh_set_vertex_vx(mesh, &face->vertices[3]);
    2295        5268 :                         mesh_set_triangle(mesh, init_idx + 0, init_idx + 1, init_idx + 3);
    2296        5268 :                         mesh_set_triangle(mesh, init_idx + 0, init_idx + 3, init_idx + 2);
    2297             :                 }
    2298        5268 :                 mesh_free(faces[i]);
    2299             :         }
    2300           9 :         if (begin_face) {
    2301           8 :                 if (path->n_contours>1) {
    2302             : #ifdef GPAC_HAS_GLU
    2303           0 :                         u32 *ptsPerFace = gf_malloc(sizeof(u32)*path->n_contours);
    2304             :                         /*we reversed begin cap!!!*/
    2305             :                         cur = 0;
    2306           0 :                         for (i=0; i<path->n_contours; i++) {
    2307           0 :                                 nb_pts = 1+path->contours[i] - cur;
    2308           0 :                                 cur+=nb_pts;
    2309           0 :                                 ptsPerFace[i] = nb_pts;
    2310             :                         }
    2311           0 :                         TesselateFaceMeshComplex(mesh, faces[begin_face], path->n_contours, ptsPerFace);
    2312           0 :                         gf_free(ptsPerFace);
    2313             : #endif
    2314             :                 } else {
    2315           8 :                         TesselateFaceMesh(mesh, faces[begin_face]);
    2316             :                 }
    2317           8 :                 mesh_free(faces[begin_face]);
    2318             :         }
    2319           9 :         if (end_face) {
    2320           0 :                 if (path->n_contours>1) {
    2321             : #ifdef GPAC_HAS_GLU
    2322           0 :                         u32 *ptsPerFace = gf_malloc(sizeof(u32)*path->n_contours);
    2323             :                         cur = 0;
    2324           0 :                         for (i=0; i<path->n_contours; i++) {
    2325           0 :                                 nb_pts = 1+path->contours[i] - cur;
    2326           0 :                                 cur+=nb_pts;
    2327           0 :                                 ptsPerFace[i] = nb_pts;
    2328             :                         }
    2329           0 :                         TesselateFaceMeshComplex(mesh, faces[end_face], path->n_contours, ptsPerFace);
    2330           0 :                         gf_free(ptsPerFace);
    2331             : #endif
    2332             :                 } else {
    2333           0 :                         TesselateFaceMesh(mesh, faces[end_face]);
    2334             :                 }
    2335           0 :                 mesh_free(faces[end_face]);
    2336             :         }
    2337           9 :         gf_free(faces);
    2338           9 :         gf_free(SCPs);
    2339             : 
    2340             :         /*FIXME: this is correct except we need to handle path cw/ccw - until then no possibility
    2341             :         to get correct lighting*/
    2342             :         /*
    2343             :                 if (path->subpathlen && path->subpath[0]->closed && ((begin_face && end_face) || spine_closed))
    2344             :                         mesh->flags |= MESH_IS_SOLID;
    2345             :                 else
    2346             :                         mesh->flags &= ~MESH_IS_SOLID;
    2347             :         */
    2348             : }
    2349             : 
    2350           2 : void mesh_extrude_path_ext(GF_Mesh *mesh, GF_Path *path, MFVec3f *thespine, Fixed creaseAngle, Fixed min_cx, Fixed min_cy, Fixed width_cx, Fixed width_cy, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool tx_along_spine)
    2351             : {
    2352           2 :         mesh_extrude_path_intern(mesh, path, thespine, creaseAngle, min_cx, min_cy, width_cx, width_cy, begin_cap, end_cap, spine_ori, spine_scale, tx_along_spine);
    2353           2 : }
    2354             : 
    2355           7 : void mesh_extrude_path(GF_Mesh *mesh, GF_Path *path, MFVec3f *thespine, Fixed creaseAngle, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool tx_along_spine)
    2356             : {
    2357             :         GF_Rect rc;
    2358           7 :         gf_path_get_bounds(path, &rc);
    2359           7 :         mesh_extrude_path_intern(mesh, path, thespine, creaseAngle, rc.x, rc.y-rc.height, rc.width, rc.height, begin_cap, end_cap, spine_ori, spine_scale, tx_along_spine);
    2360           7 :         mesh_update_bounds(mesh);
    2361           7 :         gf_mesh_build_aabbtree(mesh);
    2362           7 : }
    2363             : 
    2364           7 : void mesh_new_extrusion(GF_Mesh *mesh, GF_Node *node)
    2365             : {
    2366             :         GF_Path *path;
    2367             :         u32 i;
    2368             :         M_Extrusion *ext = (M_Extrusion *)node;
    2369             : 
    2370           7 :         mesh_reset(mesh);
    2371           7 :         path = gf_path_new();
    2372           7 :         gf_path_add_move_to(path, ext->crossSection.vals[0].x, ext->crossSection.vals[0].y);
    2373         119 :         for (i=1; i<ext->crossSection.count; i++) {
    2374         112 :                 gf_path_add_line_to(path, ext->crossSection.vals[i].x, ext->crossSection.vals[i].y);
    2375             :         }
    2376             : 
    2377           7 :         mesh_extrude_path(mesh, path, &ext->spine, ext->creaseAngle, ext->beginCap, ext->endCap, &ext->orientation, &ext->scale, 1);
    2378           7 :         gf_path_del(path);
    2379             : 
    2380           7 :         mesh_update_bounds(mesh);
    2381           7 :         if (!ext->ccw) mesh->flags |= MESH_IS_CW;
    2382           7 : }
    2383             : 
    2384             : 
    2385             : #endif  /* GPAC_DISABLE_3D*/
    2386             : 
    2387             : #endif /*GPAC_DISABLE_VRML*/

Generated by: LCOV version 1.13