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*/
|