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