FreeWRL/FreeX3D  3.0.0
GenPolyRep.c
1 /*
2 
3 
4 ???
5 
6 */
7 
8 
9 /****************************************************************************
10  This file is part of the FreeWRL/FreeX3D Distribution.
11 
12  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13 
14  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15  it under the terms of the GNU Lesser Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  GNU General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26 ****************************************************************************/
27 
28 
29 
30 #include <config.h>
31 #include <system.h>
32 #include <display.h>
33 #include <internal.h>
34 
35 #include <libFreeWRL.h>
36 
37 #include "../vrml_parser/Structs.h"
38 #include "../vrml_parser/CRoutes.h"
39 #include "../main/headers.h"
40 
41 #include "LinearAlgebra.h"
42 #include "Polyrep.h"
43 #include "Tess.h"
44 #include "Component_Geospatial.h" /* resolving implicit declarations */
45 
46 /*****************************************
47  *
48  * Complex Geometry; ElevationGrid, Extrusion, IndexedFaceSet, Text.
49  *
50  * This code generates a Polyrep structure, that is further
51  * streamlined then streamed to OpenGL.
52  *
53  * Polyreps are streamed in Polyrep.c
54  *
55  *******************************************/
56 
57 extern void Elev_Tri (int vertex_ind,int this_face,int A,int D,int E,int NONORMALS,struct X3D_PolyRep *this_Elev,struct point_XYZ *facenormals,int *pointfaces,int ccw);
58 extern void verify_global_IFS_Coords(int max);
59 extern void Extru_check_normal(struct point_XYZ *facenormals,int this_face,int dire,struct X3D_PolyRep *rep_,int ccw);
60 void register_Polyrep_combiner();
61 /* calculate how many triangles are required for IndexedTriangleFanSet and
62  IndexedTriangleStripSets */
63 static int returnIndexedFanStripIndexSize (struct Multi_Int32 index ) {
64  int IndexSize;
65  int xx, zz;
66  IndexSize = 0;
67  xx = 0;
68  zz = 0;
69 
70  for (xx=0; xx<index.n; xx++) {
71  /* printf ("looking at index %d, is %d of %d\n",xx,index.p[xx],index.n); */
72  if ((index.p[xx] <=-1) || (xx == (index.n-1))) {
73  /* printf ("found an end of run at %d\n",xx); */
74 
75  /* are we on the last index, and it is not a -1? */
76  if ((index.p[xx] > -1) && (xx == (index.n-1))) {
77  zz++; /* include this index */
78  }
79 
80  IndexSize += (zz-2) *4;
81  /* bounds checking... */
82  if (zz < 3) {
83  printf ("IndexedTriangle[Fan|Strip]Set, index %d is less than 3\n",zz);
84  return 0;
85  }
86  zz = 0;
87  } else {
88  zz++;
89  }
90  }
91 
92  /* printf ("ITFS, IndexSize %d\n",IndexSize); */
93  return IndexSize;
94 }
95 
96 /* check validity of fields */
97 int checkX3DIndexedFaceSetFields (struct X3D_IndexedFaceSet *this_) {
98  /* does this have any coordinates? */
99  if (this_->coord == 0) {
100  #ifdef VERBOSE
101  printf ("checkX3DIFS - have an IFS (%d) with no coords...\n",this_);
102  #endif
103  return FALSE;
104  }
105  if (this_->coordIndex.n == 0) {
106  #ifdef VERBOSE
107  printf ("checkX3DIFS - have an IFS (%d) with no coordIndex, pointer is %d offset is %d\n",this_,
108  this_->coordIndex.p,offsetof (struct X3D_IndexedFaceSet, coordIndex));
109  #endif
110  return FALSE;
111  }
112  return TRUE;
113 }
114 
115 /* check validity of ElevationGrid fields */
116 int checkX3DElevationGridFields (struct X3D_ElevationGrid *this_, float **points, int *npoints) {
117  int i,j;
118  int nx = (this_->xDimension);
119  float xSp = (this_->xSpacing);
120  int nz = (this_->zDimension);
121  float zSp = (this_->zSpacing);
122  float *height = ((this_->height).p);
123  int ntri = (nx && nz ? 2 * (nx-1) * (nz-1) : 0);
124  int nh = ((this_->height).n);
125  struct X3D_PolyRep *rep = this_->_intern;
126 
127  float *newpoints;
128  float newPoint[3];
129  int nquads = ntri/2;
130  int *cindexptr;
131 
132  float *tcoord = NULL;
133 
134  /* check validity of input fields */
135  if(nh != nx * nz) {
136  if (nh > nx * nz) {
137  printf ("Elevationgrid: warning: x,y vs. height: %d * %d ne %d:\n", nx,nz,nh);
138  } else {
139  printf ("Elevationgrid: error: x,y vs. height: %d * %d ne %d:\n", nx,nz,nh);
140  return FALSE;
141  }
142  }
143 
144  /* do we have any triangles? */
145  if ((nx < 2) || (nz < 2)) {
146  printf ("ElevationGrid: xDimension and zDimension less than 2 %d %d\n", nx,nz);
147  return FALSE;
148  }
149 
150  /* any texture coordinates passed in? if so, DO NOT generate any texture coords here. */
151  if (!(this_->texCoord)) {
152  /* allocate memory for texture coords */
153  FREE_IF_NZ(rep->GeneratedTexCoords[0]);
154 
155  /* 6 vertices per quad each vertex has a 2-float tex coord mapping */
156  tcoord = rep->GeneratedTexCoords[0] = MALLOC (float *, sizeof (float) * nquads * 12);
157 
158  rep->tcindex=0; /* we will generate our own mapping */
159  } else {
160  ConsoleMessage ("even though we have a texCoord node here, we need to generate");
161  }
162 
163  /* make up points array */
164  /* a point is a vertex and consists of 3 floats (x,y,z) */
165  newpoints = MALLOC (float *, sizeof (float) * nz * nx * 3);
166 
167  FREE_IF_NZ(rep->actualCoord);
168  rep->actualCoord = (float *)newpoints;
169 
170  /* make up coord index */
171  if (this_->_coordIndex.n > 0) {FREE_IF_NZ(this_->_coordIndex.p);}
172  this_->_coordIndex.p = MALLOC (int *, sizeof(int) * nquads * 5);
173  cindexptr = this_->_coordIndex.p;
174 
175  this_->_coordIndex.n = nquads * 5;
176  /* return the newpoints array to the caller */
177  *points = newpoints;
178  *npoints = this_->_coordIndex.n;
179 
180  for (j = 0; j < (nz -1); j++) {
181  for (i=0; i < (nx-1) ; i++) {
182  /*
183  printf ("coord maker, j %d i %d\n",j,i);
184  printf ("coords for this quad: %d %d %d %d %d\n",
185  j*nx+i, j*nx+i+nx, j*nx+i+nx+1, j*nx+i+1, -1);
186  */
187 
188  *cindexptr = j*nx+i; cindexptr++;
189  *cindexptr = j*nx+i+nx; cindexptr++;
190  *cindexptr = j*nx+i+nx+1; cindexptr++;
191  *cindexptr = j*nx+i+1; cindexptr++;
192  *cindexptr = -1; cindexptr++;
193 
194  }
195  }
196 
197  /* tex coords These need to be streamed now; that means for each quad, each vertex needs its tex coords. */
198  /* if the texCoord node exists, let render_TextureCoordinate (or whatever the node is) do our work for us */
199  if (!(this_->texCoord)) {
200  for (j = 0; j < (nz -1); j++) {
201  for (i=0; i < (nx-1) ; i++) {
202  /* first triangle, 3 vertexes */
203  /* first tri */
204  *tcoord = ((float) (i+0)/(nx-1)); tcoord++;
205  *tcoord = ((float)(j+0)/(nz-1)); tcoord ++;
206 
207  *tcoord = ((float) (i+0)/(nx-1)); tcoord++;
208  *tcoord = ((float)(j+1)/(nz-1)); tcoord ++;
209 
210  *tcoord = ((float) (i+1)/(nx-1)); tcoord++;
211  *tcoord = ((float)(j+1)/(nz-1)); tcoord ++;
212 
213  /* second tri */
214  *tcoord = ((float) (i+0)/(nx-1)); tcoord++;
215  *tcoord = ((float)(j+0)/(nz-1)); tcoord ++;
216 
217  *tcoord = ((float) (i+1)/(nx-1)); tcoord++;
218  *tcoord = ((float)(j+1)/(nz-1)); tcoord ++;
219 
220  *tcoord = ((float) (i+1)/(nx-1)); tcoord++;
221  *tcoord = ((float)(j+0)/(nz-1)); tcoord ++;
222  }
223  }
224  }
225 
226  /* Render_Polyrep will use this number of triangles */
227  rep->ntri = ntri;
228 
229  for (j=0; j<nz; j++) {
230  for (i=0; i < nx; i++) {
231 
232  /*
233  printf ("point [%d,%d] is %f %f %f (hei ind %d)\n",
234  i,j,
235  xSp * i,
236  height[i+(j*nx)],
237  zSp * j,
238  i+(j*nx));
239  */
240 
241 
242  newPoint[0] = xSp * i; newPoint[1] = height[i+(j*nx)]; newPoint[2]=zSp*j;
243  memcpy(newpoints,newPoint,sizeof(float)*3);
244  newpoints += 3;
245  }
246  }
247 
248  return TRUE;
249 }
250 
251 
252 static void checkIndexedTriangleStripSetFields (struct X3D_IndexedTriangleStripSet *node) {
253  int IndexSize = 0;
254  int xx,yy,zz; /* temporary variables */
255  int fanVertex;
256  int *newIndex;
257  int windingOrder; /*TriangleStripSet ordering */
258 
259  /* printf ("start of ITSS\n"); */
260  IndexSize = returnIndexedFanStripIndexSize(node->index);
261  if (IndexSize == 0) {
262  /* printf ("IndexSize for ITFS %d\n",IndexSize); */
263  node->index.n = 0;
264  }
265 
266  newIndex = MALLOC (int *, sizeof(int) * IndexSize);
267 
268  /* now calculate the indexes */
269  xx=0;
270  yy=0; zz = 0;
271  while (xx < (node->index.n-1)) {
272  fanVertex = xx;
273  /* scan forward to find end of fan */
274  while ((xx<node->index.n) && (node->index.p[xx] > -1)) xx++;
275  /* printf ("strip runs between %d and %d\n", fanVertex,xx); */
276 
277  /* bounds checking... */
278  if (xx >= IndexSize) {
279  printf ("ITFS - index size error... IndexSize < index value \n");
280  xx = IndexSize;
281  }
282 
283 
284  windingOrder=0;
285  for (zz=fanVertex; zz<(xx-2); zz++) {
286  if (windingOrder==0) {
287  newIndex[yy] = node->index.p[zz]; yy++;
288  newIndex[yy] = node->index.p[zz+1]; yy++;
289  newIndex[yy] = node->index.p[zz+2]; yy++;
290  windingOrder ++;
291  } else {
292  newIndex[yy] = node->index.p[zz]; yy++;
293  newIndex[yy] = node->index.p[zz+2]; yy++;
294  newIndex[yy] = node->index.p[zz+1]; yy++;
295  windingOrder =0;
296  }
297  newIndex[yy] = -1; yy++;
298  }
299 
300  /* is this the end of the fan? */
301  if (xx < (node->index.n-1)) {
302  xx++; /* skip past the -1 */
303  fanVertex = xx;
304  /* printf ("end of fan, but not end of structure - fanVertex %d, xx %d yy %d\n",fanVertex,xx,yy); */
305  }
306  zz += 2;
307  }
308 
309  /* xx=0; while (xx < IndexSize) { printf ("index %d val %d\n",xx,newIndex[xx]); xx++; } */
310 
311  /* now, make the new index active */
312  /* FREE_IF_NZ (node->coordIndex.p); should free if MALLOC'd already */
313  node->_coordIndex.p = newIndex;
314  node->_coordIndex.n = IndexSize;
315 }
316 
317 static void checkIndexedTriangleFanSetFields (struct X3D_IndexedTriangleFanSet *node) {
318  int IndexSize = 0;
319  int xx,yy,zz; /* temporary variables */
320  int fanVertex;
321  int *newIndex;
322 
323  /* printf ("start of ITFS\n"); */
324  IndexSize = returnIndexedFanStripIndexSize(node->index);
325  if (IndexSize == 0) {
326  /* printf ("IndexSize for ITFS %d\n",IndexSize); */
327  node->index.n = 0;
328  }
329 
330  newIndex = MALLOC (int *, sizeof(int) * IndexSize);
331  /* now calculate the indexes */
332 
333  xx=0;
334  yy=0;
335  while (xx < (node->index.n-1)) {
336  fanVertex = xx;
337  /* scan forward to find end of fan */
338  while ((xx<node->index.n) && (node->index.p[xx] > -1)) xx++;
339  /* printf ("fan runs between %d and %d\n", fanVertex,xx); */
340 
341  /* bounds checking... */
342  if (xx >= IndexSize) {
343  printf ("ITFS - index size error... IndexSize < index value \n");
344  xx = IndexSize;
345  }
346 
347  for (zz=fanVertex+1; zz<(xx-1); zz++) {
348  /* printf ("newIndexSize %d, fv %d, zz %d\n",IndexSize, fanVertex, zz); */
349  newIndex[yy] = node->index.p[fanVertex]; yy++;
350  newIndex[yy] = node->index.p[zz]; yy++;
351  newIndex[yy] = node->index.p[zz+1]; yy++;
352  newIndex[yy] = -1; yy++;
353  }
354 
355  /* is this the end of the fan? */
356  if (xx < (node->index.n-1)) {
357  xx++; /* skip past the -1 */
358  fanVertex = xx;
359  /* printf ("end of fan, but not end of structure - fanVertex %d, xx %d yy %d\n",fanVertex,xx,yy); */
360  }
361  }
362 
363  /* xx=0; while (xx < IndexSize) { printf ("index %d val %d\n",xx,newIndex[xx]); xx++; } */
364 
365  /* now, make the new index active */
366  /* FREE_IF_NZ (node->coordIndex.p); should free if MALLOC'd already */
367  node->_coordIndex.p = newIndex;
368  node->_coordIndex.n = IndexSize;
369 }
370 
371 
372 static void checkIndexedTriangleSetFields (struct X3D_IndexedTriangleSet *node) {
373  int IndexSize = 0;
374  int xx,yy,zz; /* temporary variables */
375  int *newIndex;
376 
377  IndexSize = ((node->index.n) * 4) / 3;
378  if (IndexSize <= 0) {
379  /* nothing to do here */
380  node->index.n = 0;
381  }
382 
383  newIndex = MALLOC (int *, sizeof(int) * IndexSize);
384  zz = 0; yy=0;
385  /* printf ("index: "); */
386  for (xx = 0; xx < node->index.n; xx++) {
387  newIndex[zz] = node->index.p[xx];
388  /* printf (" %d ",newIndex[zz]); */
389  zz++;
390  yy++;
391  if (yy == 3) {
392  /* end of one triangle, put a -1 in there */
393  newIndex[zz] = -1;
394  /* printf (" -1 "); */
395  zz++;
396  yy = 0;
397  }
398  /* printf ("\n"); */
399  }
400 
401  /* now, make the new index active */
402  /* FREE_IF_NZ (node->coordIndex.p); should free if MALLOC'd already */
403  node->_coordIndex.p = newIndex;
404  node->_coordIndex.n = IndexSize;
405 }
406 
407 static void checkTriangleFanSetFields (struct X3D_TriangleFanSet *node) {
408  int IndexSize = 0;
409  int xx,yy,zz; /* temporary variables */
410  int fanVertex;
411 
412  /* printf ("TFS, fanCount %d\n",(node->fanCount).n); */
413  if ((node->fanCount).n < 1) {
414  ConsoleMessage("TriangleFanSet, need at least one fanCount element");
415  node->fanCount.n = 0;
416  }
417 
418  /* calculate the size of the Index array */
419  for (xx=0; xx<(node->fanCount).n; xx++) {
420  /* printf ("fanCount %d is %d \n",xx,(node->fanCount).p[xx]); */
421  IndexSize += ((node->fanCount).p[xx]-2) * 4;
422  /* bounds checking... */
423  if ((node->fanCount).p[xx] < 3) {
424  printf ("TriangleFanSet, fanCount index %d is less than 3\n", (node->fanCount).p[xx]);
425  }
426  }
427 
428  /* printf ("IndexSize is %d\n",IndexSize); */
429  node->_coordIndex.p = MALLOC (int *, sizeof(int) * IndexSize);
430  node->_coordIndex.n = IndexSize;
431  IndexSize = 0; /* for assigning the indexes */
432 
433  /* now calculate the indexes */
434  yy=0; zz=0;
435  for (xx=0; xx<(node->fanCount).n; xx++) {
436  /* printf ("fanCount %d is %d \n",xx,(node->fanCount).p[xx]); */
437  fanVertex = zz;
438  zz ++;
439  for (yy=0; yy< ((node->fanCount).p[xx]-2); yy++) {
440  /* printf ("fc %d tris %d %d %d -1\n",
441  xx, fanVertex, zz, zz+1); */
442  node->_coordIndex.p[IndexSize++] = fanVertex;
443  node->_coordIndex.p[IndexSize++] = zz;
444  node->_coordIndex.p[IndexSize++] = zz+1;
445  node->_coordIndex.p[IndexSize++] = -1;
446  zz++;
447  }
448  zz++;
449  }
450 }
451 
452 static void checkIndexedQuadSetFields (struct X3D_IndexedQuadSet *node) {
453  int IndexSize = 0;
454  int xx,yy; /* temporary variables */
455  int *newIndex;
456  int *newIndexPtr;
457 
458  IndexSize = ((node->index.n) /4) * 4;
459  if (IndexSize <= 0) {
460  /* nothing to do here */
461  node->index.n = 0;
462  }
463 
464  //ConsoleMessage ("IndexedQuadCount = IndexSize %d from %d",IndexSize,node->index.n);
465  // do we have not enough indexes to make a quad - ie, any spare indexes?
466  if (IndexSize != node->index.n) ConsoleMessage ("IndexedQuadSet using %d of %d indexes according to spec",IndexSize,node->index.n);
467 
468  // each quad is made of 5 indexes, from 4 - quad 0,1,2,3 makes 0,1,2, 3, -1
469  // as we make this into an IndexedFaceSet, with each Quad being a "face"
470 
471  newIndex = MALLOC (int *, sizeof(int) * IndexSize * 5 / 4);
472  newIndexPtr = newIndex;
473  yy=0;
474  /* printf ("index: "); */
475  for (xx = 0; xx < IndexSize; xx++) {
476  *newIndexPtr = node->index.p[xx];
477 
478 
479  /* printf (" %d ",newIndex[zz]); */
480  newIndexPtr++;
481  yy++;
482  if (yy == 4) {
483  /* end of one triangle, put a -1 in there */
484  *newIndexPtr = -1;
485  /* printf (" -1 "); */
486  newIndexPtr++;
487  yy = 0;
488  }
489  /* printf ("\n"); */
490  }
491 
492  /* now, make the new index active */
493  FREE_IF_NZ (node->index.p); /* should free if MALLOC'd already */
494  node->_coordIndex.p = newIndex;
495  node->_coordIndex.n = IndexSize * 5 / 4;
496 }
497 
498 static void checkQuadSetFields(struct X3D_QuadSet *node) {
499  int npoints = 0;
500  int IndexSize = 0;
501  int xx; /* temporary variables */
502 
503  if(node->coord) {
504  struct Multi_Vec3f *dtmp;
505  dtmp = getCoordinate (node->coord, "QuadSet");
506  npoints = dtmp->n;
507  }
508 
509  /* verify whether we have an incorrect number of coords or not */
510  if (((npoints/4)*4) != npoints) {
511  ConsoleMessage ("Warning, in QuadSet, Coordinates not a multiple of 4\n");
512  npoints = ((npoints/4)*4);
513  }
514 
515  /* printf ("npoints %d\n",npoints); */
516 
517 
518  /* calculate index size; every "face" ends in -1 */
519  IndexSize = (npoints * 8) / 4;
520  //printf ("IndexSize is %d\n",IndexSize);
521  node->_coordIndex.p = MALLOC (int *, sizeof(int) * IndexSize);
522  node->_coordIndex.n = IndexSize;
523 
524  IndexSize = 0; /* for assigning the indexes */
525 
526  /* now calculate the indexes */
527  for (xx=0; xx<npoints; xx+=4) {
528  /* printf ("index %d tris %d %d %d -1\n", xx/3, xx, xx+1, xx+2); */
529  node->_coordIndex.p[IndexSize++] = xx;
530  node->_coordIndex.p[IndexSize++] = xx+1;
531  node->_coordIndex.p[IndexSize++] = xx+2;
532  node->_coordIndex.p[IndexSize++] = -1;
533  node->_coordIndex.p[IndexSize++] = xx+2;
534  node->_coordIndex.p[IndexSize++] = xx+3;
535  node->_coordIndex.p[IndexSize++] = xx;
536  node->_coordIndex.p[IndexSize++] = -1;
537  }
538 /* ConsoleMessage ("end of loop, index size is %d",IndexSize);
539  for (xx=0; xx<IndexSize; xx++) {
540  ConsoleMessage ("... index %d is %d\n",xx,node->_coordIndex.p[xx]);
541  }
542  */
543 }
544 
545 
546 static void checkTriangleStripSetFields (struct X3D_TriangleStripSet *node) {
547  int IndexSize = 0;
548  int xx,yy,zz; /* temporary variables */
549  int windingOrder; /*TriangleStripSet ordering */
550 
551  /* printf ("TSS, stripCount %d\n",(node->stripCount).n); */
552  if ((node->stripCount).n < 1) {
553  ConsoleMessage ("TriangleStripSet, need at least one stripCount element");
554  node->stripCount.n=0;
555  }
556 
557  /* calculate the size of the Index array */
558  for (xx=0; xx<(node->stripCount).n; xx++) {
559  /* printf ("stripCount %d is %d \n",xx,(node->stripCount).p[xx]); */
560  IndexSize += ((node->stripCount).p[xx]-2) * 4;
561  /* bounds checking... */
562  if ((node->stripCount).p[xx] < 3) {
563  printf ("TriangleStripSet, index %d is less than 3\n",
564  (node->stripCount).p[xx]);
565  }
566  }
567 
568  /* printf ("IndexSize is %d\n",IndexSize); */
569  node->_coordIndex.p = MALLOC (int *, sizeof(int) * IndexSize);
570  node->_coordIndex.n = IndexSize;
571  IndexSize = 0; /* for assigning the indexes */
572 
573  /* now calculate the indexes */
574  yy=0; zz=0;
575  for (xx=0; xx<(node->stripCount).n; xx++) {
576  windingOrder=0;
577  /* printf ("stripCount %d is %d \n",xx,(node->stripCount).p[xx]); */
578  for (yy=0; yy< ((node->stripCount).p[xx]-2); yy++) {
579  if (windingOrder==0) {
580  /* printf ("fcwo0 %d tris %d %d %d -1\n", xx, zz, zz+1, zz+2); */
581  node->_coordIndex.p[IndexSize++] = zz;
582  node->_coordIndex.p[IndexSize++] = zz+1;
583  node->_coordIndex.p[IndexSize++] = zz+2;
584  windingOrder++;
585  } else {
586  /* printf ("fcwo1 %d tris %d %d %d -1\n", xx, zz+1, zz, zz+2); */
587  node->_coordIndex.p[IndexSize++] = zz+1;
588  node->_coordIndex.p[IndexSize++] = zz;
589  node->_coordIndex.p[IndexSize++] = zz+2;
590  windingOrder=0;
591  }
592  node->_coordIndex.p[IndexSize++] = -1;
593  zz++;
594  }
595  zz += 2;
596  }
597 }
598 
599 
600 
601 static void checkTriangleSetFields (struct X3D_TriangleSet *node) {
602  int npoints = 0;
603  int IndexSize = 0;
604  int xx; /* temporary variables */
605 
606  if(node->coord) {
607  struct Multi_Vec3f *dtmp;
608  dtmp = getCoordinate (node->coord, "TriangleSet");
609  npoints = dtmp->n;
610  }
611 
612  /* verify whether we have an incorrect number of coords or not */
613  if (((npoints/3)*3) != npoints) {
614  printf ("Warning, in TriangleSet, Coordinates not a multiple of 3\n");
615  npoints = ((npoints/3)*3);
616  }
617 
618  /* printf ("npoints %d\n",npoints); */
619 
620 
621  /* calculate index size; every "face" ends in -1 */
622  IndexSize = (npoints * 4) / 3;
623  /* printf ("IndexSize is %d\n",IndexSize); */
624  node->_coordIndex.p = MALLOC (int *, sizeof(int) * IndexSize);
625  node->_coordIndex.n = IndexSize;
626 
627  IndexSize = 0; /* for assigning the indexes */
628 
629  /* now calculate the indexes */
630  for (xx=0; xx<npoints; xx+=3) {
631  /* printf ("index %d tris %d %d %d -1\n", xx/3, xx, xx+1, xx+2); */
632  node->_coordIndex.p[IndexSize++] = xx;
633  node->_coordIndex.p[IndexSize++] = xx+1;
634  node->_coordIndex.p[IndexSize++] = xx+2;
635  node->_coordIndex.p[IndexSize++] = -1;
636  }
637 }
638 
639 
640 
641 void make_genericfaceset(struct X3D_IndexedFaceSet *node) {
642  int cin;
643  int cpv = TRUE;
644  int npv;
645  int tcin;
646  int colin;
647  int norin;
648  //Aug 11, 2016 there are some complainers on web3d-public -TriangleSet too smoothed
649  // and nodes like TriangleSet don't officially have a creaseangle field like IndexedFaceSet or ElevationGrid
650  // should be if normalPerVertex = TRUE, then smooth, else no smooth and in direction according to ccw
651  // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/rendering.html#TriangleSet
652  // to smooth, we set creaseAngle high -2PI keeps smoothing on- and if we detect normalPerVertex=False we put a PI/4 creaseangle
653  float creaseAngle = (float) PI * 2; // PI*2 == smooth
654  int ccw = TRUE;
655 
656  int ntri = 0;
657  int nvert = 0;
658  int npoints = 0;
659  int nnormals=0;
660  int ncolors=0;
661  int vert_ind = 0;
662  int calc_normind = 0;
663 
664  struct SFVec3f *c1;
665 
666  struct SFVec3f *points = NULL;
667  float *fogdepths = NULL;
668  struct X3D_PolyRep *rep_ = node->_intern;
669 
670  struct Multi_Int32 *orig_coordIndex = NULL;
671  struct Multi_Int32 *orig_texCoordIndex = NULL;
672  struct Multi_Int32 *orig_normalIndex = NULL;
673  struct Multi_Int32 *orig_colorIndex = NULL;
674 
675 
676  GLuint *cindex; /* Coordinate Index */
677  GLuint *colindex; /* Color Index */
678  GLuint *tcindex=0; /* Tex Coord Index */
679  GLuint *norindex; /* Normals Index */
680 
681  int normalArraySize = INT_ID_UNDEFINED; /* bounds checking on normals generated */
682 
683  int faces=0;
684  int convex=TRUE;
685  struct point_XYZ *facenormals; /* normals for each face*/
686  int *faceok = NULL; /* is this face ok? (ie, not degenerate triangles, etc)*/
687  int *pointfaces = NULL;
688 
689  GLDOUBLE tess_v[3]; /*param.to FW_GLU_TESS_VERTEX()*/
690 
691  int *tess_vs = NULL; /* pointer to space needed */
692 
693 
694  int i; /* general purpose counters */
695  int this_face, this_coord;
696 
697  struct X3D_Color *cc = NULL;
698  struct X3D_Normal *nc = NULL;
699  struct X3D_TextureCoordinate *tc = NULL;
700  struct X3D_Coordinate *co = NULL;
701  struct X3D_FogCoordinate *fc = NULL;
702  ttglobal tg = gglobal();
703 
704  if (node->_nodeType == NODE_IndexedFaceSet) {
705  if (!checkX3DIndexedFaceSetFields(node)) {
706  rep_->ntri = 0;
707  return;
708  }
709 
710 
711  } else if (node->_nodeType == NODE_ElevationGrid) {
712  if (!checkX3DElevationGridFields(X3D_ELEVATIONGRID(node),
713  (float **)&points, &npoints)) {
714  rep_->ntri = 0;
715  return;
716  }
717  } else if (node->_nodeType == NODE_GeoElevationGrid) {
718  if (!checkX3DGeoElevationGridFields(X3D_GEOELEVATIONGRID(node),
719  (float **)&points, &npoints)) {
720  rep_->ntri = 0;
721  return;
722  }
723  }
724 
725  switch (node->_nodeType) {
726  case NODE_IndexedFaceSet:
727  convex = node->convex;
728  cpv = node->colorPerVertex;
729  npv = node->normalPerVertex;
730  ccw = node->ccw;
731  orig_texCoordIndex = &node->texCoordIndex;
732  orig_colorIndex = &node->colorIndex;
733  orig_normalIndex = &node->normalIndex;
734  creaseAngle = node->creaseAngle;
735  orig_coordIndex = &node->coordIndex;
736  cc = (struct X3D_Color *) node->color;
737  nc = (struct X3D_Normal *) node->normal;
738  tc = (struct X3D_TextureCoordinate *) node->texCoord;
739  co = (struct X3D_Coordinate *) node->coord;
740  fc = (struct X3D_FogCoordinate *) node->fogCoord;
741  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedFaceSet, attrib));
742  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedFaceSet, color));
743  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedFaceSet, coord));
744  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedFaceSet, fogCoord));
745  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedFaceSet, metadata));
746  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedFaceSet, normal));
747  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedFaceSet, texCoord));
748 
749  break;
750  case NODE_ElevationGrid:
751  orig_coordIndex= &X3D_ELEVATIONGRID(node)->_coordIndex;
752  cpv = X3D_ELEVATIONGRID(node)->colorPerVertex;
753  npv = X3D_ELEVATIONGRID(node)->normalPerVertex;
754  creaseAngle = X3D_ELEVATIONGRID(node)->creaseAngle;
755  cc = (struct X3D_Color *) X3D_ELEVATIONGRID(node)->color;
756  nc = (struct X3D_Normal *) X3D_ELEVATIONGRID(node)->normal;
757  tc = (struct X3D_TextureCoordinate *) X3D_ELEVATIONGRID(node)->texCoord;
758  fc = (struct X3D_FogCoordinate *) X3D_ELEVATIONGRID(node)->fogCoord;
759  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_ElevationGrid, attrib));
760  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_ElevationGrid, color));
761  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_ElevationGrid, fogCoord));
762  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_ElevationGrid, metadata));
763  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_ElevationGrid, normal));
764  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_ElevationGrid, texCoord));
765  break;
766  case NODE_GeoElevationGrid:
767  orig_coordIndex= &X3D_GEOELEVATIONGRID(node)->_coordIndex;
768  cpv = X3D_GEOELEVATIONGRID(node)->colorPerVertex;
769  npv = X3D_GEOELEVATIONGRID(node)->normalPerVertex;
770  creaseAngle = (float) X3D_GEOELEVATIONGRID(node)->creaseAngle;
771  cc = (struct X3D_Color *) X3D_GEOELEVATIONGRID(node)->color;
772  nc = (struct X3D_Normal *) X3D_GEOELEVATIONGRID(node)->normal;
773  tc = (struct X3D_TextureCoordinate *) X3D_GEOELEVATIONGRID(node)->texCoord;
774  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_GeoElevationGrid, color));
775  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_GeoElevationGrid, metadata));
776  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_GeoElevationGrid, normal));
777  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_GeoElevationGrid, texCoord));
778  break;
779  case NODE_IndexedTriangleFanSet:
780  checkIndexedTriangleFanSetFields(X3D_INDEXEDTRIANGLEFANSET(node));
781  orig_coordIndex= &X3D_INDEXEDTRIANGLEFANSET(node)->_coordIndex;
782  cpv = X3D_INDEXEDTRIANGLEFANSET(node)->colorPerVertex;
783  npv = X3D_INDEXEDTRIANGLEFANSET(node)->normalPerVertex;
784  ccw = X3D_INDEXEDTRIANGLEFANSET(node)->ccw;
785  cc = (struct X3D_Color *) X3D_INDEXEDTRIANGLEFANSET(node)->color;
786  nc = (struct X3D_Normal *) X3D_INDEXEDTRIANGLEFANSET(node)->normal;
787  tc = (struct X3D_TextureCoordinate *) X3D_INDEXEDTRIANGLEFANSET(node)->texCoord;
788  co = (struct X3D_Coordinate *) X3D_INDEXEDTRIANGLEFANSET(node)->coord;
789  fc = (struct X3D_FogCoordinate *) X3D_INDEXEDTRIANGLEFANSET(node)->fogCoord;
790  if(!npv) creaseAngle = 0.0; //disable smoothing according to specs "if npv is false, don't smooth
791  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, attrib));
792  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, color));
793  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, coord));
794  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, fogCoord));
795  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, metadata));
796  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, normal));
797  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, texCoord));
798  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, index));
799  break;
800  case NODE_IndexedTriangleSet:
801  checkIndexedTriangleSetFields(X3D_INDEXEDTRIANGLESET(node));
802  orig_coordIndex= &X3D_INDEXEDTRIANGLESET(node)->_coordIndex;
803  cpv = X3D_INDEXEDTRIANGLESET(node)->colorPerVertex;
804  npv = X3D_INDEXEDTRIANGLESET(node)->normalPerVertex;
805  ccw = X3D_INDEXEDTRIANGLESET(node)->ccw;
806  cc = (struct X3D_Color *) X3D_INDEXEDTRIANGLESET(node)->color;
807  nc = (struct X3D_Normal *) X3D_INDEXEDTRIANGLESET(node)->normal;
808  tc = (struct X3D_TextureCoordinate *) X3D_INDEXEDTRIANGLESET(node)->texCoord;
809  co = (struct X3D_Coordinate *) X3D_INDEXEDTRIANGLESET(node)->coord;
810  fc = (struct X3D_FogCoordinate *) X3D_INDEXEDTRIANGLESET(node)->fogCoord;
811  if(!npv) creaseAngle = 0.0; //disable smoothing according to specs "if npv is false, don't smooth
812  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleSet, attrib));
813  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleSet, color));
814  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleSet, coord));
815  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleSet, fogCoord));
816  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleSet, metadata));
817  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleSet, normal));
818  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleSet, texCoord));
819  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleSet, index));
820  break;
821  case NODE_IndexedTriangleStripSet:
822  checkIndexedTriangleStripSetFields(X3D_INDEXEDTRIANGLESTRIPSET(node));
823  orig_coordIndex= &X3D_INDEXEDTRIANGLESTRIPSET(node)->_coordIndex;
824  cpv = X3D_INDEXEDTRIANGLESTRIPSET(node)->colorPerVertex;
825  npv = X3D_INDEXEDTRIANGLESTRIPSET(node)->normalPerVertex;
826  ccw = X3D_INDEXEDTRIANGLESTRIPSET(node)->ccw;
827  cc = (struct X3D_Color *) X3D_INDEXEDTRIANGLESTRIPSET(node)->color;
828  nc = (struct X3D_Normal *) X3D_INDEXEDTRIANGLESTRIPSET(node)->normal;
829  tc = (struct X3D_TextureCoordinate *) X3D_INDEXEDTRIANGLESTRIPSET(node)->texCoord;
830  co = (struct X3D_Coordinate *) X3D_INDEXEDTRIANGLESTRIPSET(node)->coord;
831  fc = (struct X3D_FogCoordinate *) X3D_INDEXEDTRIANGLESTRIPSET(node)->fogCoord;
832  if(!npv) creaseAngle = 0.0; //disable smoothing according to specs "if npv is false, don't smooth
833  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, attrib));
834  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, color));
835  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, coord));
836  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, fogCoord));
837  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, metadata));
838  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, normal));
839  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, texCoord));
840  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedTriangleStripSet, index));
841  break;
842  case NODE_TriangleFanSet:
843  checkTriangleFanSetFields(X3D_TRIANGLEFANSET(node));
844  orig_coordIndex= &X3D_TRIANGLEFANSET(node)->_coordIndex;
845  cpv = X3D_TRIANGLEFANSET(node)->colorPerVertex;
846  npv = X3D_TRIANGLEFANSET(node)->normalPerVertex;
847  ccw = X3D_TRIANGLEFANSET(node)->ccw;
848  cc = (struct X3D_Color *) X3D_TRIANGLEFANSET(node)->color;
849  nc = (struct X3D_Normal *) X3D_TRIANGLEFANSET(node)->normal;
850  tc = (struct X3D_TextureCoordinate *) X3D_TRIANGLEFANSET(node)->texCoord;
851  co = (struct X3D_Coordinate *) X3D_TRIANGLEFANSET(node)->coord;
852  fc = (struct X3D_FogCoordinate *) X3D_TRIANGLEFANSET(node)->fogCoord;
853  if(!nc && !npv) creaseAngle = 0.0; //disable smoothing according to specs "if normals are not provided, and npv is false, don't smooth
854  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleFanSet, attrib));
855  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleFanSet, color));
856  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleFanSet, coord));
857  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleFanSet, fogCoord));
858  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleFanSet, metadata));
859  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleFanSet, normal));
860  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleFanSet, texCoord));
861  break;
862  case NODE_TriangleSet:
863  checkTriangleSetFields(X3D_TRIANGLESET(node));
864  orig_coordIndex= &X3D_TRIANGLESET(node)->_coordIndex;
865  cpv = X3D_TRIANGLESET(node)->colorPerVertex;
866  npv = X3D_TRIANGLESET(node)->normalPerVertex;
867  ccw = X3D_TRIANGLESET(node)->ccw;
868  cc = (struct X3D_Color *) X3D_TRIANGLESET(node)->color;
869  nc = (struct X3D_Normal *) X3D_TRIANGLESET(node)->normal;
870  tc = (struct X3D_TextureCoordinate *) X3D_TRIANGLESET(node)->texCoord;
871  co = (struct X3D_Coordinate *) X3D_TRIANGLESET(node)->coord;
872  fc = (struct X3D_FogCoordinate *) X3D_TRIANGLESET(node)->fogCoord;
873  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleSet, attrib));
874  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleSet, color));
875  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleSet, coord));
876  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleSet, fogCoord));
877  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleSet, metadata));
878  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleSet, normal));
879  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleSet, texCoord));
880  break;
881  case NODE_TriangleStripSet:
882  checkTriangleStripSetFields(X3D_TRIANGLESTRIPSET(node));
883  orig_coordIndex= &X3D_TRIANGLESTRIPSET(node)->_coordIndex;
884  cpv = X3D_TRIANGLESTRIPSET(node)->colorPerVertex;
885  npv = X3D_TRIANGLESTRIPSET(node)->normalPerVertex;
886  ccw = X3D_TRIANGLESTRIPSET(node)->ccw;
887  cc = (struct X3D_Color *) X3D_TRIANGLESTRIPSET(node)->color;
888  nc = (struct X3D_Normal *) X3D_TRIANGLESTRIPSET(node)->normal;
889  tc = (struct X3D_TextureCoordinate *) X3D_TRIANGLESTRIPSET(node)->texCoord;
890  co = (struct X3D_Coordinate *) X3D_TRIANGLESTRIPSET(node)->coord;
891  fc = (struct X3D_FogCoordinate *) X3D_TRIANGLESTRIPSET(node)->fogCoord;
892  if(!nc && !npv) creaseAngle = 0.0; //disable smoothing according to specs "if normals are not provided, and npv is false, don't smooth
893  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleStripSet, attrib));
894  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleStripSet, color));
895  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleStripSet, coord));
896  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleStripSet, fogCoord));
897  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleStripSet, metadata));
898  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleStripSet, normal));
899  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_TriangleStripSet, texCoord));
900  break;
901 
902  case NODE_IndexedQuadSet:
903  checkIndexedQuadSetFields(X3D_INDEXEDQUADSET(node));
904  orig_coordIndex= &X3D_INDEXEDQUADSET(node)->_coordIndex;
905  cpv = X3D_INDEXEDQUADSET(node)->colorPerVertex;
906  npv = X3D_INDEXEDQUADSET(node)->normalPerVertex;
907  ccw = X3D_INDEXEDQUADSET(node)->ccw;
908  cc = (struct X3D_Color *) X3D_INDEXEDQUADSET(node)->color;
909  nc = (struct X3D_Normal *) X3D_INDEXEDQUADSET(node)->normal;
910  tc = (struct X3D_TextureCoordinate *) X3D_INDEXEDQUADSET(node)->texCoord;
911  co = (struct X3D_Coordinate *) X3D_INDEXEDQUADSET(node)->coord;
912  fc = (struct X3D_FogCoordinate *) X3D_INDEXEDQUADSET(node)->fogCoord;
913  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedQuadSet, attrib));
914  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedQuadSet, color));
915  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedQuadSet, coord));
916  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedQuadSet, fogCoord));
917  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedQuadSet, metadata));
918  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedQuadSet, normal));
919  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedQuadSet, texCoord));
920  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_IndexedQuadSet, index));
921  break;
922 
923  case NODE_QuadSet:
924  checkQuadSetFields(X3D_QUADSET(node));
925  orig_coordIndex= &X3D_QUADSET(node)->_coordIndex;
926  cpv = X3D_QUADSET(node)->colorPerVertex;
927  npv = X3D_QUADSET(node)->normalPerVertex;
928  ccw = X3D_QUADSET(node)->ccw;
929  cc = (struct X3D_Color *) X3D_QUADSET(node)->color;
930  nc = (struct X3D_Normal *) X3D_QUADSET(node)->normal;
931  tc = (struct X3D_TextureCoordinate *) X3D_QUADSET(node)->texCoord;
932  co = (struct X3D_Coordinate *) X3D_QUADSET(node)->coord;
933  fc = (struct X3D_FogCoordinate *) X3D_QUADSET(node)->fogCoord;
934  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_QuadSet, attrib));
935  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_QuadSet, color));
936  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_QuadSet, coord));
937  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_QuadSet, fogCoord));
938  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_QuadSet, metadata));
939  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_QuadSet, normal));
940  MARK_EVENT (X3D_NODE(node), offsetof (struct X3D_QuadSet, texCoord));
941  break;
942 
943  default:
944  ConsoleMessage ("unknown type for make_genericfaceset, %d\n",node->_nodeType);
945  rep_->ntri=0;
946  return;
947  }
948 
949  if (orig_coordIndex != NULL) cin= orig_coordIndex->n; else cin = 0;
950  if (orig_texCoordIndex != NULL) tcin= orig_texCoordIndex->n; else tcin = 0;
951  if (orig_colorIndex != NULL) colin= orig_colorIndex->n; else colin = 0;
952  if (orig_normalIndex != NULL) norin= orig_normalIndex->n; else norin = 0;
953 
954  #ifdef VERBOSE
955  printf ("cin %d tcin %d colin %d norin %d\n",cin,tcin,colin,norin);
956  printf ("start of make_indexedfaceset for node %p, cin %d tcin %d colin %d norin %d\n",node, cin, tcin, colin, norin);
957  #endif
958 
959 #undef VERBOSE
960 
961 
962  /* lets get the structure parameters, after munging by checkX3DComposedGeomFields... */
963  #ifdef VERBOSE
964  printf ("NOW, the IFS has a cin of %d ca %f\n",cin,creaseAngle);
965  #endif
966 
967  /* check to see if there are params to make at least one triangle */
968  if (cin<2) {
969  #ifdef VERBOSE
970  printf ("Null IFS found, returing ntri0\n");
971  #endif
972  rep_->ntri = 0;
973  return;
974  }
975 
976  /* record ccw flag */
977  rep_->ccw = ccw;
978 
979  /* if the last coordIndex == -1, ignore it */
980  if((orig_coordIndex->p[cin-1]) == -1) { cin--; }
981 
982 
983  /* texture coords IndexedFaceSet coords colors and normals */
984  if(co != NULL) {
985  struct Multi_Vec3f *dtmp;
986  dtmp = getCoordinate (X3D_NODE(co), "make FacedSet");
987  npoints = dtmp->n;
988  points = dtmp->p;
989  }
990  if(fc != NULL){
991  //http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/enveffects.html#FogCoordinate
992  //we have one fog per co (or if we are short, then duplicate last
993  struct X3D_FogCoordinate *fc2;
994  POSSIBLE_PROTO_EXPANSION (struct X3D_FogCoordinate *,(struct X3D_Node*) fc,fc2)
995  if(fc2){
996  if(fc2->depth.n < npoints){
997  fc2->depth.p = REALLOC(fc2->depth.p, npoints * sizeof(float));
998  for(i=fc2->depth.n; i<npoints; i++){
999  fc2->depth.p[i] = fc2->depth.p[fc->depth.n-1];
1000  }
1001  fc2->depth.n = npoints;
1002  }
1003  fogdepths = fc2->depth.p;
1004  }
1005  }
1006 
1007  /* just check this parameter here for correctness and, whether to generate other nodes. We
1008  will check it better in stream_polyrep. */
1009  if (cc != NULL) {
1010  if ((cc->_nodeType != NODE_Color) && (cc->_nodeType != NODE_ColorRGBA)) {
1011  printf ("make_IFS, expected %d got %d\n", NODE_Color, cc->_nodeType);
1012  } else {
1013  ncolors = cc->color.n;
1014  }
1015  }
1016 
1017  if(nc != NULL) {
1018  if (nc->_nodeType != NODE_Normal) {
1019  printf ("make_IFS, normal expected %d, got %d\n",NODE_Normal, nc->_nodeType);
1020  } else {
1021  nnormals = nc->vector.n;
1022  }
1023  }
1024 
1025 
1026  /* just check this parameter here for correctness and, whether to generate other nodes. We
1027  will check it better in stream_polyrep. */
1028  if (tc != NULL) {
1029  rep_->tcoordtype=tc->_nodeType;
1030  } else {
1031  rep_->tcoordtype=0;
1032  }
1033 
1034  /* count the faces in this polyrep and allocate memory. */
1035  faces = count_IFS_faces (cin,orig_coordIndex);
1036  #ifdef VERBOSE
1037  printf ("faces %d, cin %d npoints %d\n",faces,cin,npoints);
1038  #endif
1039 
1040  if (faces == 0) {
1041  rep_->ntri = 0;
1042  return;
1043  }
1044 
1045  /* are there any coordinates? */
1046  if (npoints <= 0) {
1047  rep_->ntri = 0;
1048  return;
1049  }
1050 
1051  facenormals = MALLOC(struct point_XYZ *, sizeof(struct point_XYZ)*faces); // sizeof(*facenormals)
1052  faceok = MALLOC(int *, sizeof(int)*faces);
1053  pointfaces = MALLOC(int *, sizeof(int)*npoints*POINT_FACES); /* save max x points */ //sizeof(*pointfaces)
1054 
1055  /* generate the face-normals table, so for each face, we know the normal
1056  and for each point, we know the faces that it is in */
1057  if (!IFS_face_normals (facenormals,faceok,pointfaces,faces,npoints,cin,points,orig_coordIndex,ccw)) {
1058  rep_->ntri=0;
1059  FREE_IF_NZ (facenormals);
1060  FREE_IF_NZ (faceok);
1061  FREE_IF_NZ (pointfaces);
1062 
1063  return;
1064  }
1065 
1066  /* wander through to see how much memory needs allocating for triangles */
1067  for(i=0; i<cin; i++) {
1068  if((orig_coordIndex->p[i]) == -1) {
1069  ntri += nvert-2;
1070  nvert = 0;
1071  } else {
1072  nvert ++;
1073  }
1074  }
1075  if(nvert>2) {ntri += nvert-2;}
1076 
1077 
1078  #ifdef VERBOSE
1079  printf ("vert %d ntri %d\n",nvert,ntri);
1080  #endif
1081 
1082  /* Tesselation MAY use more triangles; lets estimate how many more */
1083  if(!convex) { ntri =ntri*2; }
1084 
1085  /* fudge factor - leave space for 1 more triangle just in case we have errors on input */
1086  ntri++;
1087 
1088  FREE_IF_NZ(rep_->cindex);
1089  FREE_IF_NZ(rep_->colindex);
1090  FREE_IF_NZ(rep_->norindex);
1091 
1092  cindex = rep_->cindex = MALLOC(GLuint *, sizeof(*(rep_->cindex))*3*(ntri));
1093  colindex = rep_->colindex = MALLOC(GLuint *, sizeof(*(rep_->colindex))*3*(ntri));
1094  norindex = rep_->norindex = MALLOC(GLuint *,sizeof(*(rep_->norindex))*3*ntri);
1095 
1096  /* zero the indexes */
1097  bzero (colindex,sizeof(*(rep_->colindex))*3*(ntri));
1098  bzero (norindex,sizeof(*(rep_->colindex))*3*(ntri));
1099 
1100  FREE_IF_NZ(rep_->normal);
1101  /* if we calculate normals, we use a normal per point, NOT per triangle */
1102  if (!nnormals) { /* 3 vertexes per triangle, and 3 floats per tri */
1103  normalArraySize = 3*3*ntri;
1104  rep_->normal = MALLOC(float *, sizeof(*(rep_->normal))*normalArraySize * 2 /* JAS */ );
1105  } else { /* dont do much, but get past check below */
1106  rep_->normal = MALLOC(float *, 1);
1107  }
1108 
1109  FREE_IF_NZ(rep_->tcindex);
1110 
1111  tcindex = rep_->tcindex = MALLOC(GLuint*, sizeof(*(rep_->tcindex))*3*(ntri));
1112 
1113  /* Concave faces - use the OpenGL Triangulator to give us the triangles */
1114  tess_vs=MALLOC(int *, sizeof(*(tess_vs))*(ntri)*3);
1115 
1116  this_coord = 0;
1117  i = 0;
1118 
1119  for (this_face=0; this_face<faces; this_face++) {
1120  int relative_coord; /* temp, used if not tesselating */
1121  int tess_contour_start; /* tess, for creating contours, maybe */
1122  int initind = 0;
1123  int lastind = 0; /* coord indexes */
1124 
1125  tg->Tess.global_IFS_Coord_count = 0;
1126  relative_coord = 0;
1127  tess_contour_start = 0;
1128 
1129 
1130  if (!faceok[this_face]) {
1131  #ifdef VERBOSE
1132  printf ("in generate of faces, face %d is invalid, skipping...\n",this_face);
1133  #endif
1134 
1135  /* skip past the seperator, except if we are t the end */
1136 
1137  /* skip to either end or the next -1*/
1138  while ((this_coord < cin) && ((orig_coordIndex->p[this_coord]) != -1)) this_coord++;
1139 
1140  /* skip past the -1*/
1141  if ((this_coord < (cin-1)) && ((orig_coordIndex->p[this_coord]) == -1)) this_coord++;
1142  } else {
1143 
1144  #ifdef VERBOSE
1145  printf ("working on face %d coord %d total coords %d coordIndex %d\n",
1146  this_face,this_coord,cin,(orig_coordIndex->p[ this_coord]));
1147  #endif
1148 
1149  /* create the global_IFS_coords array, at least this time */
1150  /* */
1151  /* What we do is to create a series of triangle vertex */
1152  /* relative to the current coord index, then use that */
1153  /* to generate the actual coords further down. This helps */
1154  /* to map normals, textures, etc when tesselated and the */
1155  /* *perVertex modes are set. */
1156 
1157  /* If we have concave, tesselate! */
1158  // July 2016 dug9 changed Tess.c combiner callback so it works for Text
1159  // but did not fix combiner scenarios here, wich were not working right when face edges intersect (which specs say don't worry about)
1160  if (!convex) {
1161  //register_Polyrep_combiner(); //default, Component_Text resets to this after compiling its text
1162  //FW_GLU_BEGIN_POLYGON(tg->Tess.global_tessobj);
1163  polyrep_combiner_data cbdata;
1164  //not using combinder data right now
1165  gluTessBeginPolygon( tg->Tess.global_tessobj, &cbdata); // //cbdata is for combiner
1166  gluTessBeginContour( tg->Tess.global_tessobj );
1167  } else {
1168  initind = relative_coord++;
1169  lastind = relative_coord++;
1170  }
1171 
1172  i = (orig_coordIndex->p[ relative_coord + this_coord]);
1173 
1174  while (i != -1) {
1175  if (!convex) {
1176  int ind;
1177  int foundContour = FALSE;
1178  /* printf ("\nwhile, i is %d this_coord %d rel coord %d\n",i,this_coord,relative_coord); */
1179 
1180  /* is this a duplicate? if so, start a new contour */
1181  for (ind=tess_contour_start; ind<relative_coord; ind++) {
1182 /*
1183  printf ("contour checking, comparing %d and %d, ind %d\n",
1184  orig_coordIndex->p[relative_coord + this_coord],
1185  orig_coordIndex->p[ind + this_coord],
1186  ind);
1187 */
1188  if ( orig_coordIndex->p[relative_coord + this_coord] ==
1189  orig_coordIndex->p[ind + this_coord]) {
1190  /* printf ("FOUND CONTOUR\n"); */
1191  tess_contour_start = relative_coord+1;
1192  FW_GLU_NEXT_CONTOUR(tg->Tess.global_tessobj,GLU_UNKNOWN);
1193  foundContour = TRUE;
1194  break;
1195  }
1196 
1197  }
1198  if (!foundContour) {
1199  c1 = &(points[i]);
1200  tess_v[0] = c1->c[0];
1201  tess_v[1] = c1->c[1];
1202  tess_v[2] = c1->c[2];
1203  tess_vs[relative_coord] = relative_coord;
1204  /* printf ("vertex %f %f %f, index %d\n",tess_v[0], tess_v[1], tess_v[2], tess_vs[relative_coord]); */
1205  //&p->FW_RIA[p->FW_RIA_indx]
1206  //&tess_vs[relative_coord]
1207  FW_GLU_TESS_VERTEX(tg->Tess.global_tessobj,tess_v,&tess_vs[relative_coord]);
1208  }
1209 
1210  relative_coord++;
1211  } else {
1212  /* take coordinates and make triangles out of them */
1213  tg->Tess.global_IFS_Coords[tg->Tess.global_IFS_Coord_count++] = initind;
1214  tg->Tess.global_IFS_Coords[tg->Tess.global_IFS_Coord_count++] = lastind;
1215  tg->Tess.global_IFS_Coords[tg->Tess.global_IFS_Coord_count++] = relative_coord;
1216  /* printf ("triangle %d %d %d\n",initind,lastind,relative_coord);*/
1217  lastind = relative_coord++;
1218  }
1219 
1220  if (relative_coord + this_coord == cin) {
1221  i = -1;
1222  } else {
1223  i = (orig_coordIndex->p[ relative_coord + this_coord]);
1224  }
1225  }
1226 
1227  if (!convex) {
1228  //FW_GLU_END_POLYGON(tg->Tess.global_tessobj);
1229  gluTessEndContour( tg->Tess.global_tessobj );
1230  gluTessEndPolygon( tg->Tess.global_tessobj );
1231 
1232  /* Tesselated faces may have a different normal than calculated previously */
1233  /* bounds check, once again */
1234 
1235  verify_global_IFS_Coords(cin);
1236 
1237  IFS_check_normal (facenormals,this_face,points, this_coord, orig_coordIndex, ccw);
1238  }
1239 
1240 
1241  /* now store this information for the whole of the polyrep */
1242  for (i=0; i<tg->Tess.global_IFS_Coord_count; i++) {
1243  /* Triangle Coordinate */
1244  cindex [vert_ind] = (orig_coordIndex->p[this_coord+tg->Tess.global_IFS_Coords[i]]);
1245 
1246  /* printf ("vertex %d gic %d cindex %d\n",vert_ind,global_IFS_Coords[i],cindex[vert_ind]); */
1247 
1248  /* Vertex Normal */
1249  if(nnormals) {
1250  if (norin) {
1251  /* we have a NormalIndex */
1252  if (npv) {
1253  norindex[vert_ind] = orig_normalIndex->p[this_coord+tg->Tess.global_IFS_Coords[i]];
1254  /* printf ("norm1, index %d\n",norindex[vert_ind]);*/
1255  } else {
1256  norindex[vert_ind] = orig_normalIndex->p[this_face];
1257  /* printf ("norm2, index %d\n",norindex[vert_ind]);*/
1258  }
1259  } else {
1260  /* no normalIndex - use the coordIndex */
1261  if (npv) {
1262  norindex[vert_ind] = (orig_coordIndex->p[this_coord+tg->Tess.global_IFS_Coords[i]]);
1263  /* printf ("norm3, index %d\n",norindex[vert_ind]); */
1264  } else {
1265  norindex[vert_ind] = this_face;
1266  /* printf ("norm4, index %d\n",norindex[vert_ind]);*/
1267  }
1268  }
1269 
1270  } else {
1271  if (fabs(creaseAngle) > 0.00001) {
1272  /* normalize each vertex */
1273  if (normalArraySize != INT_ID_UNDEFINED) {
1274  if (calc_normind*3 > normalArraySize) {
1275  printf ("HMMM _ NORMAL OVERFLOW\n");
1276  }
1277  }
1278 
1279  normalize_ifs_face (&rep_->normal[calc_normind*3],
1280  facenormals, pointfaces, cindex[vert_ind],
1281  this_face, creaseAngle);
1282  rep_->norindex[vert_ind] = calc_normind++;
1283  } else {
1284  /* use the calculated normals */
1285  rep_->normal[vert_ind*3+0]=(float) facenormals[this_face].x;
1286  rep_->normal[vert_ind*3+1]=(float) facenormals[this_face].y;
1287  rep_->normal[vert_ind*3+2]=(float) facenormals[this_face].z;
1288  rep_->norindex[vert_ind] = vert_ind;
1289  /* printf ("using calculated normals %f %f %f for face %d, vert_ind %d\n",
1290  rep_->normal[vert_ind*3+0],rep_->normal[vert_ind*3+1],
1291  rep_->normal[vert_ind*3+2],this_face,rep_->norindex[vert_ind]);
1292  */
1293  }
1294  }
1295 
1296  /* Vertex Colours */
1297  if(ncolors) {
1298  if (colin) {
1299  int tmpI;
1300  /* we have a colorIndex */
1301  if (cpv) tmpI = this_coord+tg->Tess.global_IFS_Coords[i];
1302  else tmpI = this_face;
1303 
1304  if (tmpI >= orig_colorIndex->n) {
1305  printf ("faceSet, colorIndex problem, %d >= %d\n", tmpI,orig_colorIndex->n);
1306  colindex[vert_ind] = 0;
1307  } else {
1308  colindex[vert_ind] = orig_colorIndex->p[tmpI];
1309  }
1310  /* printf ("col2, index %d\n",colindex[vert_ind]); */
1311 
1312  } else {
1313  /* no colorIndex - use the coordIndex */
1314  if (cpv) {
1315  colindex[vert_ind] = (orig_coordIndex->p[this_coord+tg->Tess.global_IFS_Coords[i]]);
1316  /* printf ("col3, index %d\n",colindex[vert_ind]); */
1317  } else {
1318  colindex[vert_ind] = this_face;
1319  /* printf ("col4, index %d\n",colindex[vert_ind]); */
1320  }
1321  //ConsoleMessage ("color index is %d",colindex[vert_ind]);
1322  }
1323  }
1324 
1325 
1326  /* Texture Coordinates */
1327  if (tcin) {
1328  /* bounds checking if we run out of texCoords, just fill in with 0 */
1329  if ((this_coord+tg->Tess.global_IFS_Coords[i]) < tcin) {
1330  tcindex[vert_ind] = orig_texCoordIndex->p[this_coord+tg->Tess.global_IFS_Coords[i]];
1331  } else {
1332  tcindex[vert_ind] = 0;
1333  }
1334  /* printf ("ntexCoords,tcin, index %d\n",tcindex[vert_ind]); */
1335  } else {
1336  /* no texCoordIndex, use the Coord Index */
1337  tcindex[vert_ind] = (orig_coordIndex->p[this_coord+tg->Tess.global_IFS_Coords[i]]);
1338  /* printf ("ntexcoords, notcin, vertex %d point %d\n",vert_ind,tcindex[vert_ind]); */
1339  }
1340  // just use cindex: fogindex[vert_ind] = (orig_coordIndex->p[this_coord+tg->Tess.global_IFS_Coords[i]]);
1341 
1342  /* increment index, but check for baaad errors. */
1343  if (vert_ind < (ntri*3-1)) vert_ind++;
1344  }
1345 
1346  /* for the next face, we work from a new base */
1347  this_coord += relative_coord;
1348 
1349  /* skip past the seperator, except if we are t the end */
1350  if (this_coord < cin)
1351  if ((orig_coordIndex->p[this_coord]) == -1) {this_coord++;}
1352  }
1353  }
1354 
1355  /* we have an accurate triangle count now... */
1356  rep_->ntri = vert_ind/3;
1357  #ifdef VERBOSE
1358  printf ("make_indededfaceset, end, ntri %d\n",rep_->ntri);
1359  #endif
1360 
1361  FREE_IF_NZ (tess_vs);
1362  FREE_IF_NZ (facenormals);
1363  FREE_IF_NZ (faceok);
1364  FREE_IF_NZ (pointfaces);
1365 }
1366 
1367 #undef VERBOSE
1368 
1369 /********************************************************************************************/
1370 /* get a valid alpha angle from that that is passed in */
1371 /* asin of 1.0000 seems to fail sometimes, so */
1372 double getAlpha(float ang) {
1373  if (ang >= 0.99999) return asin(0.9999);
1374  else if (ang <= -0.99999) return asin(-0.9999);
1375  return asin((double)ang);
1376 }
1377 
1378 
1379 double getGamma(double alpha, double minor) {
1380  double gamma;
1381 
1382  if(APPROX(cos(alpha),0))
1383  return (double) 0;
1384  else {
1385  gamma=acos(minor / cos(alpha));
1386  if(fabs(sin(gamma)-(-minor/cos(alpha)))>fabs(sin(gamma))) gamma=-gamma;
1387  }
1388  return gamma;
1389 }
1390 
1391 void compute_spy_spz(struct point_XYZ *spy, struct point_XYZ *spz, struct SFVec3f *spine, int nspi) {
1392  int majorX = FALSE;
1393  int majorZ = FALSE;
1394  int minorY = FALSE;
1395  int minorX = FALSE;
1396  #ifdef VERBOSE
1397  int majorY = FALSE;
1398  int minorZ = FALSE;
1399  #endif
1400  double alpha,gamma; /* angles for the rotation */
1401  int spi;
1402  float spylen;
1403  struct point_XYZ spp1 = {0.0, 0.0, 0.0};
1404 
1405 
1406  /* need to find the rotation from SCP[spi].y to (0 1 0)*/
1407  /* and rotate (0 0 1) and (0 1 0) to be the new y and z */
1408  /* values for all SCPs */
1409  /* I will choose rotation about the x and z axis */
1410 
1411  /* search a non trivial vector along the spine */
1412  for(spi=1;spi<nspi;spi++) {
1413  VEC_FROM_CDIFF(spine[spi],spine[0],spp1);
1414  if(!APPROX(VECSQ(spp1),0))
1415  break;
1416  }
1417 
1418  /* normalize the non trivial vector */
1419  spylen=1/(float) sqrt(VECSQ(spp1)); VECSCALE(spp1,spylen);
1420  #ifdef VERBOSE
1421  printf("Reference vector along spine=[%f,%f,%f]\n", spp1.x,spp1.y,spp1.z);
1422  #endif
1423 
1424 
1425  /* find the major and minor axes */
1426  if ((fabs(spp1.x) >= fabs(spp1.y)) && (fabs(spp1.x) >= fabs(spp1.z))) {majorX = TRUE;}
1427  else if ((fabs(spp1.y) >= fabs(spp1.x)) && (fabs(spp1.y) >= fabs(spp1.z))) {/* majorY = TRUE;*/ }
1428  else majorZ = TRUE;
1429  if ((fabs(spp1.x) <= fabs(spp1.y)) && (fabs(spp1.x) <= fabs(spp1.z))) {minorX = TRUE;}
1430  else if ((fabs(spp1.y) <= fabs(spp1.x)) && (fabs(spp1.y) <= fabs(spp1.z))) minorY = TRUE;
1431  else { /*minorZ = TRUE; */}
1432 
1433  #ifdef VERBOSE
1434  printf ("major axis %d %d %d\n",majorX, majorY, majorZ);
1435  printf ("minor axis %d %d %d\n",minorX, minorY, minorZ);
1436  #endif
1437 
1438  if(majorX) {
1439  /* get the angle for the x axis rotation */
1440  /* asin of 1.0000 seems to fail sometimes, so */
1441 
1442  alpha = getAlpha((float)spp1.x);
1443  gamma = getGamma(alpha,minorY?spp1.y:spp1.z);
1444 
1445  #ifdef VERBOSE
1446  printf("majorX: alpha=%f gamma=%f\n",alpha,gamma);
1447  #endif
1448 
1449 
1450  /* XXX: should we use the minor axis to determine the order of minor calculations???? */
1451  spy->y=-(cos(alpha)*(-sin(gamma)));
1452  spy->z=cos(alpha)*cos(gamma);
1453  spy->x=sin(alpha);
1454  spz->y=-(sin(alpha)*sin(gamma));
1455  spz->z=(-sin(alpha))*cos(gamma);
1456  spz->x=cos(alpha);
1457  } else if(majorZ) {
1458  /* get the angle for the z axis rotation */
1459 
1460  alpha = getAlpha((float)spp1.z);
1461  gamma = getGamma(alpha,minorX?spp1.x:spp1.y);
1462 
1463  #ifdef VERBOSE
1464  printf("majorZ: alpha=%f gamma=%f\n",alpha,gamma);
1465  #endif
1466  /* XXX: should we use the minor axis to determine the order of minor calculations???? */
1467  spy->y=-(cos(alpha)*(-sin(gamma)));
1468  spy->x=cos(alpha)*cos(gamma);
1469  spy->z=sin(alpha);
1470  spz->y=-(sin(alpha)*sin(gamma));
1471  spz->x=(-sin(alpha))*cos(gamma);
1472  spz->z=cos(alpha);
1473  } else {
1474  /* get the angle for the y axis rotation */
1475  if(1){
1476  /* dug9: Mar7,2013 special case: if spine is (all collinear +) parallel to
1477  local Y axis, just return and use defaults which are set up correctly */
1478  struct point_XYZ crossp;
1479  VECCP(*spy,spp1,crossp);
1480  if( veclengthd((double*)&crossp) < .001 ) return;
1481  }
1482  alpha = getAlpha((float)spp1.y);
1483  gamma = getGamma(alpha,minorX?spp1.x:spp1.z);
1484 
1485  #ifdef VERBOSE
1486  printf("majorY: lpha=%f gamma=%f\n",alpha,gamma);
1487  #endif
1488  /* XXX: should we use the minor axis to determine the order of minor calculations???? */
1489  spy->x=-(cos(alpha)*(-sin(gamma)));
1490  spy->z=cos(alpha)*cos(gamma);
1491  spy->y=sin(alpha);
1492  spz->x=-(sin(alpha)*sin(gamma));
1493  spz->z=(-sin(alpha))*cos(gamma);
1494  spz->y=cos(alpha);
1495  }
1496 }
1497 
1498 
1499 
1500 
1501 
1502 /***************************************************************
1503  stream the extrusion texture coords. We do this now because
1504  stream_polyrep does not go through the tcindexes - the old
1505  "render every triangle" method did. So, we gain in rendering
1506  speed for a little bit of post-processing here.
1507  ***************************************************************/
1508 void stream_extrusion_texture_coords (struct X3D_PolyRep *rep_,
1509  float *tcoord,
1510  GLuint *tcindex) {
1511 
1512  int count;
1513  int ind;
1514  float* nc;
1515 
1516  /* printf ("stream_extrusion_texture_coords, have %d triangles \n",rep_->ntri); */
1517 
1518  /* 2 floats per vertex, each triangle has 3 vertexes... */
1519  rep_->GeneratedTexCoords[0] = MALLOC (float *, sizeof(float) * 2 * 3 * rep_->ntri);
1520 
1521  nc = rep_->GeneratedTexCoords[0];
1522 
1523  /* go through - note now that the "span" is 2 floats per vertex, while the old
1524  method (used when the extrusion code was written) was to use 3 floats, but
1525  ignoring one of them. Thus the "ind*3" stuff below. Yes, we could go through
1526  and re-write the generator, but, who cares - the tcoord param is freed after
1527  the return of this, so the "waste" is only temporary.
1528  */
1529  for (count = 0; count < rep_->ntri*3; count++) {
1530  ind = tcindex[count];
1531  /* printf ("working through vertex %d - tcindex %d vertex %f %f \n",count,ind,
1532  tcoord[ind*3], tcoord[ind*3+2]); */
1533  *nc = tcoord[ind*3]; nc++; *nc = tcoord[ind*3+2]; nc++;
1534  }
1535 }
1536 
1537 
1538 void make_Extrusion(struct X3D_Extrusion *node) {
1539 
1540  /*****begin of Member Extrusion */
1541  /* This code originates from the file VRMLExtrusion.pm */
1542 
1543  int tcoordsize;
1544  int tcindexsize;
1545 
1546  int beginCap = node->beginCap; /* beginCap flag */
1547  int endCap = node->endCap; /* endCap flag */
1548 
1549  int nspi = node->spine.n; /* number of spine points */
1550  int nsec = node->crossSection.n; /* no. of points in the 2D curve
1551  but note that this is verified
1552  and coincident points thrown out */
1553 
1554  int nori = node->orientation.n; /* no. of given orientators
1555  which rotate the calculated SCPs =
1556  spine-aligned cross-section planes*/
1557  int nsca = node->scale.n; /* no. of scale parameters */
1558 
1559  struct SFVec3f *spine =node->spine.p; /* vector of spine vertices */
1560  struct SFVec2f *curve =node->crossSection.p; /* vector of 2D curve points */
1561  struct SFRotation *orientation=node->orientation.p;/*vector of SCP rotations*/
1562 
1563  struct X3D_PolyRep *rep_=node->_intern;/*internal rep, we want to fill*/
1564 
1565  /* the next variables will point at members of *rep */
1566  GLuint *cindex; /* field containing indices into
1567  the coord vector. Three together
1568  indicate which points form a
1569  triangle */
1570  float *coord; /* contains vertices building the
1571  triangles as x y z values */
1572 
1573  float *tcoord; /* contains vertices building the
1574  textures as x y z values */
1575 
1576  GLuint *tcindex; /* field containing texture indices
1577  for the vertex. */
1578 
1579  int ntri = 0; /* no. of triangles to be used
1580  to represent all, but the caps */
1581  int nctri=0; /* no. of triangles for both caps*/
1582  int max_ncoord_add=0; /* max no. of add coords */
1583  int ncoord_add=0; /* no. off added coords */
1584  int ncoord=0; /* no. of used coords */
1585 
1586  int ncolinear_at_begin=0; /* no. of triangles which need
1587  to be skipped, because curve-points
1588  are in one line at start of curve*/
1589  int ncolinear_at_end=0; /* no. of triangles which need
1590  to be skipped, because curve-points
1591  are in one line at end of curve*/
1592 
1593  int spi,sec,triind,pos_of_last_zvalue; /* help variables */
1594  int next_spi, prev_spi;
1595  int t; /* another loop var */
1596 
1597 
1598  int circular = FALSE; /* is spine closed? */
1599  int tubular=FALSE; /* is the 2D curve closed? */
1600  int spine_is_one_vertex; /* only one real spine vertix */
1601 
1602  float spxlen,spylen,spzlen; /* help vars for scaling */
1603 
1604  /* def:struct representing SCPs */
1605  struct SCP { /* spine-aligned cross-section plane*/
1606  struct point_XYZ y; /* y axis of SCP */
1607  struct point_XYZ z; /* z axis of SCP */
1608  int prev,next; /* index in SCP[]
1609  prev/next different vertix for
1610  calculation of this SCP */
1611  };
1612 
1613  struct SCP *SCP; /* dyn. vector rep. the SCPs */
1614 
1615  struct point_XYZ spm1,spp1,spy,spz,spx; /* help vertix vars */
1616 
1617  int tci_ct; /* Tex Gen index counter */
1618 
1619  /* variables for calculating smooth normals */
1620  int HAVETOSMOOTH;
1621  struct point_XYZ *facenormals = 0;
1622  int *pointfaces = 0;
1623  int *defaultface = 0;
1624  int this_face = 0; /* always counts up */
1625  int tmp;
1626  float creaseAngle = node->creaseAngle;
1627  int ccw = node->ccw;
1628  int end_of_sides; /* for triangle normal generation,
1629  keep track of where the sides end
1630  and caps begin */
1631 
1632  /* variables for begin/endcap S,T mapping for textures */
1633  float *beginVals;
1634  float *endVals;
1635  struct SFVec2f *crossSection;
1636 
1637  #ifdef VERBOSE
1638  printf ("VRMLExtrusion.pm start\n");
1639  #endif
1640 
1641  /***********************************************************************
1642  *
1643  * Copy and verify cross section - remove coincident points (yes, virginia,
1644  * one of the NIST tests has this - the pie-shaped convex one
1645  *
1646  ************************************************************************/
1647 /*FIXME:
1648  to prevent a crash with script generated data
1649 */
1650 
1651  if (nspi < 1) return;
1652 
1653  /* is there anything to this Extrusion??? */
1654  if (nsec < 1) {
1655  rep_->ntri=0;
1656  return;
1657  } else {
1658  int tmp1, temp_indx;
1659  int increment, currentlocn;
1660 
1661  crossSection = MALLOC(struct SFVec2f *, sizeof(crossSection)*nsec*2);
1662 
1663 
1664  currentlocn = 0;
1665  for (tmp1=0; tmp1<nsec; tmp1++) {
1666  /* save this crossSection */
1667  crossSection[currentlocn].c[0] = curve[tmp1].c[0];
1668  crossSection[currentlocn].c[1] = curve[tmp1].c[1];
1669 
1670  /* assume that it is not duplicated */
1671  increment = 1;
1672 
1673  for (temp_indx=0; temp_indx<currentlocn; temp_indx++) {
1674  if ((APPROX(crossSection[currentlocn].c[0],crossSection[temp_indx].c[0])) &&
1675  (APPROX(crossSection[currentlocn].c[1],crossSection[temp_indx].c[1]))) {
1676  /* maybe we have a closed curve, so points SHOULD be the same */
1677  if ((temp_indx != 0) && (tmp1 != (nsec-1))) {
1678  /* printf ("... breaking; increment = 0\n");*/
1679  increment = 0;
1680  break;
1681  } else {
1682  /* printf ("... we are tubular\n");*/
1683  tubular = TRUE;
1684  }
1685  }
1686  }
1687  /* increment the crossSection index, unless it was duplicated */
1688  currentlocn += increment;
1689  }
1690 
1691  #ifdef VERBOSE
1692  printf ("we had nsec %d coords, but now we have %d\n",nsec,currentlocn);
1693  #endif
1694 
1695  nsec = currentlocn;
1696  }
1697 
1698 
1699  /* now that we have removed possible coincident vertices, we can calc ntris */
1700  ntri = 2 * (nspi-1) * (nsec-1);
1701 
1702  #ifdef VERBOSE
1703  printf ("so, we have ntri %d nspi %d nsec %d\n",ntri,nspi,nsec);
1704  #endif
1705 
1706  /* check if the spline is closed */
1707 
1708  circular = APPROX(spine[0].c[0], spine[nspi-1].c[0]) &&
1709  APPROX(spine[0].c[1], spine[nspi-1].c[1]) &&
1710  APPROX(spine[0].c[2], spine[nspi-1].c[2]);
1711 
1712  #ifdef VERBOSE
1713  printf ("tubular %d circular %d\n",tubular, circular);
1714  #endif
1715 
1716 
1717  /************************************************************************
1718  * calc number of triangles per cap, if caps are enabled and possible
1719  */
1720 
1721  /* if we are both circular and tubular, we ignore any caps */
1722  if (circular && tubular) {
1723  beginCap = FALSE;
1724  endCap = FALSE;
1725  #ifdef VERBOSE
1726  printf ("Extrusion, turning off caps \n");
1727  #endif
1728  }
1729 
1730  if(beginCap||endCap) {
1731  if(tubular?nsec<4:nsec<3) {
1732  freewrlDie("Only two real vertices in crossSection. Caps not possible!");
1733  }
1734 
1735  if(tubular) nctri=nsec-2;
1736  else nctri=nsec-1;
1737 
1738  #ifdef VERBOSE
1739  printf ("nsec = %d, ntri = %d nctri = %d\n",nsec, ntri,nctri);
1740  #endif
1741 
1742 
1743  /* check if there are colinear points at the beginning of the curve*/
1744  sec=0;
1745  while(sec+2<=nsec-1 &&
1746  /* to find out if two vectors a and b are colinear,
1747  try a.x*b.y=a.y*b.x */
1748 
1749  APPROX(0, (crossSection[sec+1].c[0]-crossSection[0].c[0])
1750  *(crossSection[sec+2].c[1]-crossSection[0].c[1])
1751  - (crossSection[sec+1].c[1]-crossSection[0].c[1])
1752  *(crossSection[sec+2].c[0]-crossSection[0].c[0]))
1753  ) ncolinear_at_begin++, sec++;
1754 
1755  /* check if there are colinear points at the end of the curve
1756  in line with the very first point, because we want to
1757  draw the triangle to there. */
1758  sec=tubular?(nsec-2):(nsec-1);
1759  while(sec-2>=0 &&
1760  APPROX(0, (crossSection[sec ].c[0]-crossSection[0].c[0])
1761  *(crossSection[sec-1].c[1]-crossSection[0].c[1])
1762  - (crossSection[sec ].c[1]-crossSection[0].c[1])
1763  *(crossSection[sec-1].c[0]-crossSection[0].c[0]))
1764  ) ncolinear_at_end++,sec--;
1765 
1766  nctri-= ncolinear_at_begin+ncolinear_at_end;
1767 
1768  if(nctri<1) {
1769  /* no triangle left :( */
1770  freewrlDie("All in crossSection points colinear. Caps not possible!");
1771  }
1772 
1773  /* so we have calculated nctri for one cap, but we might have two*/
1774  nctri= ((beginCap)?nctri:0) + ((endCap)?nctri:0) ;
1775  }
1776 
1777  /* if we have non-convex polygons, we might need a few triangles more */
1778  /* The unused memory will be freed with realloc later */
1779  if(!node->convex) {
1780 
1781  max_ncoord_add=(nspi-1)*(nsec-1) /* because of intersections */
1782  +nctri; /* because of cap tesselation */
1783  nctri*=2; /* we might need more trigs for the caps */
1784  }
1785 
1786  /************************************************************************
1787  * prepare for filling *rep
1788  */
1789 
1790  rep_->ccw = 1;
1791 
1792  rep_->ntri = ntri + nctri; /* Thats the no. of triangles representing
1793  the whole Extrusion Shape. */
1794 
1795  /* get some memory */
1796  cindex = rep_->cindex = MALLOC(GLuint *, sizeof(*(rep_->cindex))*3*(rep_->ntri));
1797  coord = rep_->actualCoord = MALLOC(float *, sizeof(*(rep_->actualCoord))*(nspi*nsec+max_ncoord_add)*3);
1798  rep_->normal = MALLOC(float *, sizeof(*(rep_->normal))*3*(rep_->ntri)*3);
1799  rep_->norindex = MALLOC(GLuint *, sizeof(*(rep_->norindex))*3*(rep_->ntri));
1800 
1801  /* face normals - one face per quad (ie, 2 triangles) */
1802  /* have to make sure that if nctri is odd, that we increment by one */
1803 
1804 
1805  facenormals = MALLOC(struct point_XYZ *, sizeof(*facenormals)*(rep_->ntri+1)/2);
1806 
1807  /* for each triangle vertex, tell me which face(s) it is in */
1808  pointfaces = MALLOC(int *, sizeof(*pointfaces)*POINT_FACES*3*rep_->ntri);
1809 
1810  /* for each triangle, it has a defaultface... */
1811  defaultface = MALLOC(int *, sizeof(*defaultface)*rep_->ntri);
1812 
1813 
1814  /*memory for the SCPs. Only needed in this function. Freed later */
1815  SCP = MALLOC(struct SCP *, sizeof(struct SCP)*nspi);
1816 
1817  /* so, we now have to worry about textures. */
1818  /* XXX note - this over-estimates; realloc to be exact */
1819 
1820  tcoordsize = (nctri + (ntri*2))*3;
1821 
1822  #ifdef VERBOSE
1823  printf ("tcoordsize is %d\n",tcoordsize);
1824  # endif
1825 
1826  FREE_IF_NZ (rep_->GeneratedTexCoords[0]);
1827  FREE_IF_NZ (rep_->tcindex);
1828 
1829  tcoord = MALLOC(float *, sizeof(*(rep_->GeneratedTexCoords[0]))*tcoordsize);
1830 
1831  tcindexsize = rep_->ntri*3;
1832  #ifdef VERBOSE
1833  printf ("tcindexsize %d\n",tcindexsize);
1834  #endif
1835 
1836  tcindex = MALLOC(GLuint *, sizeof(*(rep_->tcindex))*tcindexsize);
1837 
1838  /* keep around cross section info for tex coord mapping */
1839  beginVals = MALLOC(float *, sizeof(float) * 2 * (nsec+1)*100);
1840  endVals = MALLOC(float *, sizeof(float) * 2 * (nsec+1)*100);
1841 
1842  memset((void *)tcindex,0,tcindexsize*sizeof(*(rep_->tcindex)));
1843  /* printf ("zeroing tcindex\n");*/
1844  /* { int i; for (i=0; i<tcindexsize; i++) { tcindex[i]=0; } }*/
1845 
1846  /* Normal Generation Code */
1847  HAVETOSMOOTH = (fabs(creaseAngle)>0.0001);
1848  for (tmp = 0; tmp < 3*rep_->ntri; tmp++) {
1849  pointfaces[tmp*POINT_FACES]=0;
1850  }
1851 
1852 
1853  /************************************************************************
1854  * calculate all SCPs
1855  */
1856 
1857  spine_is_one_vertex=0;
1858 
1859  /* fill the prev and next values in the SCP structs first
1860  *
1861  * this is so complicated, because spine vertices can be the same
1862  * They should have exactly the same SCP, therefore only one of
1863  * an group of sucessive equal spine vertices (now called SESVs)
1864  * must be used for calculation.
1865  * For calculation the previous and next different spine vertex
1866  * must be known. We save that info in the prev and next fields of
1867  * the SCP struct.
1868  * Note: We have start and end SESVs which will be treated differently
1869  * depending on whether the spine is closed or not
1870  *
1871  */
1872 
1873  for(spi=0; spi<nspi;spi++){
1874  for(next_spi=spi+1;next_spi<nspi;next_spi++) {
1875  VEC_FROM_CDIFF(spine[spi],spine[next_spi],spp1);
1876  if(!APPROX(VECSQ(spp1),0))
1877  break;
1878  }
1879  if(next_spi<nspi) SCP[next_spi].prev=next_spi-1;
1880 
1881  #ifdef VERBOSE
1882  printf("spi=%d next_spi=%d\n",spi,next_spi);
1883  #endif
1884 
1885  prev_spi=spi-1;
1886  SCP[spi].next=next_spi;
1887  SCP[spi].prev=prev_spi;
1888 
1889  while(next_spi>spi+1) { /* fill gaps */
1890  spi++;
1891  SCP[spi].next=next_spi;
1892  SCP[spi].prev=prev_spi;
1893  }
1894  }
1895  /* now: start-SEVS .prev fields contain -1 */
1896  /* and end-SEVS .next fields contain nspi */
1897 
1898 
1899  /* calculate the SCPs now... */
1900 
1901  #ifdef VERBOSE
1902  printf (" SCP[0].next = %d, nspi = %d\n",SCP[0].next,nspi);
1903  #endif
1904 
1905 
1906 
1907  if(SCP[0].next==nspi) {
1908  spine_is_one_vertex=1;
1909  #ifdef VERBOSE
1910  printf("All spine vertices are the same!\n");
1911  #endif
1912 
1913  /* initialize all y and z values with zero, they will */
1914  /* be treated as colinear case later then */
1915  SCP[0].z.x=0; SCP[0].z.y=0; SCP[0].z.z=0;
1916  SCP[0].y=SCP[0].z;
1917  for(spi=1;spi<nspi;spi++) {
1918  SCP[spi].y=SCP[0].y;
1919  SCP[spi].z=SCP[0].z;
1920  }
1921  }else{
1922  #ifdef VERBOSE
1923  for(spi=0;spi<nspi;spi++) {
1924  printf("SCP[%d].next=%d, SCP[%d].prev=%d\n",
1925  spi,SCP[spi].next,spi,SCP[spi].prev);
1926  }
1927  #endif
1928 
1929  /* find spine vertix different to the first spine vertix */
1930  spi=0;
1931  while(SCP[spi].prev==-1) spi++;
1932 
1933  /* find last spine vertix different to the last */
1934  t=nspi-1;
1935  while(SCP[t].next==nspi) t--;
1936 
1937  #ifdef VERBOSE
1938  printf ("now, spi = %d, t = %d\n",spi,t);
1939  #endif
1940 
1941  /* for all but the first + last really different spine vertix */
1942  /* add case for then there are only 2 spines, and spi is already */
1943  /* spi is already greater than t... JAS */
1944 
1945  if (spi > t) {
1946  /* calc y */
1947  VEC_FROM_CDIFF(spine[1],spine[0],SCP[0].y);
1948  /* calc z */
1949  VEC_FROM_CDIFF(spine[1],spine[0],spp1);
1950  if(0){
1951  VEC_FROM_CDIFF(spine[1],spine[0],spm1);
1952  VECCP(spp1,spm1,SCP[1].z);
1953  }
1954  if(1){
1955  //dug9 Mar7,2013 from specs
1956  // http://www.web3d.org/files/specifications/19775-1/V3.2/Part01/components/geometry3D.html#Extrusion
1957  //in 13.3.5.4 Special Cases "
1958  //If the entire spine is collinear, the SCP is computed by finding
1959  //the rotation of a vector along the positive Y-axis (v1) to the vector
1960  //formed by the spine points (v2). The Y=0 plane is then rotated by this value.
1961  struct point_XYZ Yaxis; //scene local Y axis (up)
1962  double dlen_cp;
1963  Yaxis.x = 0.0;
1964  Yaxis.y = 1.0;
1965  Yaxis.z = 0.0;
1966  VECCP(spp1,Yaxis,SCP[1].z);
1967  //but what if the Yaxis is aligned pretty much to the spine axis?
1968  //then the cross product will be zero. We want a unit vector. So use Zaxis.
1969  dlen_cp = veclengthd((double*)&(SCP[1].z));
1970  if( dlen_cp < .001 )
1971  {
1972  SCP[1].z.x = 0.0;
1973  SCP[1].z.y = 0.0;
1974  SCP[1].z.z = 1.0; //align z to local scene Z axis, like flux, cortona, white_dune, blaxxun, cosmo
1975  }
1976  }
1977  #ifdef VERBOSE
1978  printf ("just calculated z for spi 0\n");
1979  printf("SCP[0].y=[%f,%f,%f], SCP[1].z=[%f,%f,%f]\n",
1980  SCP[0].y.x,SCP[0].y.y,SCP[0].y.z,
1981  SCP[1].z.x,SCP[1].z.y,SCP[1].z.z);
1982  #endif
1983  }
1984 
1985  else {
1986  for(; spi<=t; spi++) {
1987  /* calc y */
1988  VEC_FROM_CDIFF(spine[SCP[spi].next],spine[SCP[spi].prev],SCP[spi].y);
1989  /* calc z */
1990  VEC_FROM_CDIFF(spine[SCP[spi].next],spine[spi],spp1);
1991  VEC_FROM_CDIFF(spine[SCP[spi].prev],spine[spi],spm1);
1992  VECCP(spp1,spm1,SCP[spi].z);
1993  #ifdef VERBOSE
1994  printf ("just calculated z for spi %d\n",spi);
1995  #endif
1996  }
1997  }
1998 
1999  if(circular) {
2000  #ifdef VERBOSE
2001  printf ("we are circular\n");
2002  #endif
2003  /* calc y for first SCP */
2004  VEC_FROM_CDIFF(spine[SCP[0].next],spine[SCP[nspi-1].prev],SCP[0].y);
2005  /* the last is the same as the first */
2006  SCP[nspi-1].y=SCP[0].y;
2007 
2008  /* calc z */
2009  VEC_FROM_CDIFF(spine[SCP[0].next],spine[0],spp1);
2010  VEC_FROM_CDIFF(spine[SCP[nspi-1].prev],spine[0],spm1);
2011  VECCP(spp1,spm1,SCP[0].z);
2012  /* the last is the same as the first */
2013  SCP[nspi-1].z=SCP[0].z;
2014 
2015  } else {
2016  #ifdef VERBOSE
2017  printf ("we are not circular\n");
2018  #endif
2019 
2020  /* calc y for first SCP */
2021  VEC_FROM_CDIFF(spine[SCP[0].next],spine[0],SCP[0].y);
2022 
2023  /* calc y for the last SCP */
2024  /* in the case of 2, nspi-1 = 1, ...prev = 0 */
2025  VEC_FROM_CDIFF(spine[nspi-1],spine[SCP[nspi-1].prev],SCP[nspi-1].y);
2026 
2027  /* z for the start SESVs is the same as for the next SCP */
2028  SCP[0].z=SCP[SCP[0].next].z;
2029  /* z for the last SCP is the same as for the one before the last*/
2030  SCP[nspi-1].z=SCP[SCP[nspi-1].prev].z;
2031 
2032  #ifdef VERBOSE
2033  printf("SCP[0].y=[%f,%f,%f], SCP[0].z=[%f,%f,%f]\n",
2034  SCP[0].y.x,SCP[0].y.y,SCP[0].y.z,
2035  SCP[0].z.x,SCP[0].z.y,SCP[0].z.z);
2036  printf("SCP[1].y=[%f,%f,%f], SCP[1].z=[%f,%f,%f]\n",
2037  SCP[1].y.x,SCP[1].y.y,SCP[1].y.z,
2038  SCP[1].z.x,SCP[1].z.y,SCP[1].z.z);
2039  #endif
2040  } /* else */
2041 
2042  /* fill the other start SESVs SCPs*/
2043  spi=1;
2044  while(SCP[spi].prev==-1) {
2045  SCP[spi].y=SCP[0].y;
2046  SCP[spi].z=SCP[0].z;
2047  spi++;
2048  }
2049  /* fill the other end SESVs SCPs*/
2050  t=nspi-2;
2051  while(SCP[t].next==nspi) {
2052  SCP[t].y=SCP[nspi-1].y;
2053  SCP[t].z=SCP[nspi-1].z;
2054  t--;
2055  }
2056 
2057  } /* else */
2058 
2059 
2060  /* We have to deal with colinear cases, what means z=0 */
2061  pos_of_last_zvalue=-1; /* where a zvalue is found */
2062  for(spi=0;spi<nspi;spi++) {
2063  if(pos_of_last_zvalue>=0) { /* already found one? */
2064  if(APPROX(VECSQ(SCP[spi].z),0))
2065  SCP[spi].z= SCP[pos_of_last_zvalue].z;
2066 
2067  pos_of_last_zvalue=spi;
2068  } else
2069  if(!APPROX(VECSQ(SCP[spi].z),0)) {
2070  /* we got the first, fill the previous */
2071  #ifdef VERBOSE
2072  printf("Found z-Value!\n");
2073  #endif
2074 
2075  for(t=spi-1; t>-1; t--)
2076  SCP[t].z=SCP[spi].z;
2077  pos_of_last_zvalue=spi;
2078  }
2079  }
2080 
2081  #ifdef VERBOSE
2082  printf("pos_of_last_zvalue=%d\n",pos_of_last_zvalue);
2083  #endif
2084 
2085 
2086  /* z axis flipping, if VECPT(SCP[i].z,SCP[i-1].z)<0 */
2087  /* we can do it here, because it is not needed in the all-colinear case */
2088  for(spi=(circular?2:1);spi<nspi;spi++) {
2089  if(VECPT(SCP[spi].z,SCP[spi-1].z)<0) {
2090  VECSCALE(SCP[spi].z,-1);
2091  #ifdef VERBOSE
2092  printf("Extrusion.GenPloyRep: Flipped axis spi=%d\n",spi);
2093  #endif
2094  }
2095  } /* for */
2096 
2097  /* One case is missing: whole spine is colinear */
2098  if(pos_of_last_zvalue==-1) {
2099 
2100  #ifdef VERBOSE
2101  printf("Extrusion.GenPloyRep:Whole spine is colinear!\n");
2102  #endif
2103 
2104  /* this is the default, if we don`t need to rotate */
2105  spy.x=0; spy.y=1; spy.z=0;
2106  spz.x=0; spz.y=0; spz.z=1;
2107 
2108  if(!spine_is_one_vertex) {
2109  compute_spy_spz(&spy,&spz,spine,nspi);
2110  }
2111 
2112  #ifdef VERBOSE
2113  printf ("so, spy [%f %f %f], spz [%f %f %f]\n", spy.x, spy.y,spy.z, spz.x, spz.y, spz.z);
2114  #endif
2115 
2116  /* apply new y and z values to all SCPs */
2117  for(spi=0;spi<nspi;spi++) {
2118  SCP[spi].y=spy;
2119  SCP[spi].z=spz;
2120  }
2121 
2122  } /* if all colinear */
2123 
2124  #ifdef VERBOSE
2125  for(spi=0;spi<nspi;spi++) {
2126  printf("SCP[%d].y=[%f,%f,%f], SCP[%d].z=[%f,%f,%f]\n",
2127  spi,SCP[spi].y.x,SCP[spi].y.y,SCP[spi].y.z,
2128  spi,SCP[spi].z.x,SCP[spi].z.y,SCP[spi].z.z);
2129  }
2130  #endif
2131 
2132 
2133  /************************************************************************
2134  * calculate the coords
2135  */
2136 
2137  /* test for number of scale and orientation parameters */
2138  if(nsca>1 && nsca <nspi)
2139  printf("Extrusion.GenPolyRep: Warning!\n"
2140  "\tNumber of scaling parameters do not match the number of spines!\n"
2141  "\tWill revert to using only the first scale value.\n");
2142 
2143  if(nori>1 && nori <nspi)
2144  printf("Extrusion.GenPolyRep: Warning!\n"
2145  "\tNumber of orientation parameters "
2146  "do not match the number of spines!\n"
2147  "\tWill revert to using only the first orientation value.\n");
2148 
2149 
2150  for(spi = 0; spi<nspi; spi++) {
2151  double m[3][3]; /* space for the rotation matrix */
2152  spy=SCP[spi].y;
2153  spz=SCP[spi].z;
2154  VECCP(spy,spz,spx);
2155  spylen = 1/(float)sqrt(VECSQ(spy)); VECSCALE(spy, spylen);
2156  spzlen = 1/(float)sqrt(VECSQ(spz)); VECSCALE(spz, spzlen);
2157  spxlen = 1/(float)sqrt(VECSQ(spx)); VECSCALE(spx, spxlen);
2158 
2159  /* rotate spx spy and spz */
2160  if(nori) {
2161  int ori = (nori==nspi ? spi : 0);
2162 
2163  if(IS_ROTATION_VEC_NOT_NORMAL(orientation[ori]))
2164  printf("Extrusion.GenPolyRep: Warning!\n"
2165  "\tRotationvector #%d not normal!\n"
2166  "\tWon`t correct it, because it is bad VRML`97.\n",
2167  ori+1);
2168 
2169  MATRIX_FROM_ROTATION(orientation[ori],m);
2170  VECMM(m,spx);
2171  VECMM(m,spy);
2172  VECMM(m,spz);
2173  }
2174 
2175  for(sec = 0; sec<nsec; sec++) {
2176  struct point_XYZ point;
2177  float ptx = crossSection[sec].c[0];
2178  float ptz = crossSection[sec].c[1];
2179  if(nsca) {
2180  int sca = (nsca==nspi ? spi : 0);
2181  ptx *= node->scale.p[sca].c[0];
2182  ptz *= node->scale.p[sca].c[1];
2183  }
2184  point.x = ptx;
2185  point.y = 0;
2186  point.z = ptz;
2187 
2188  /* printf ("working on sec %d of %d, spine %d of %d\n", sec, nsec, spi, nspi);*/
2189 
2190 
2191  /* texture mapping for caps - keep vals around */
2192  if (spi == 0) { /* begin cap vertices */
2193  /* printf ("begin cap vertecies index %d %d \n", sec*2+0, sec*2+1); */
2194 
2195  beginVals[sec*2+0] = ptx;
2196  beginVals[sec*2+1] = ptz;
2197  } else if (spi == (nspi-1)) { /* end cap vertices */
2198  /* printf ("end cap vertecies index %d %d size %d\n", sec*2+0, sec*2+1, 2 * (nsec+1));*/
2199  endVals[(sec*2)+0]=ptx;
2200  endVals[(sec*2)+1]=ptz;
2201  }
2202 
2203  /* printf ("coord index %x sec %d spi %d nsec %d\n",*/
2204  /* &coord[(sec+spi*nsec)*3+0], sec, spi,nsec);*/
2205 
2206  coord[(sec+spi*nsec)*3+0] =
2207  (float)(spx.x * point.x + spy.x * point.y + spz.x * point.z)
2208  + node->spine.p[spi].c[0];
2209  coord[(sec+spi*nsec)*3+1] =
2210  (float)(spx.y * point.x + spy.y * point.y + spz.y * point.z)
2211  + node->spine.p[spi].c[1];
2212  coord[(sec+spi*nsec)*3+2] =
2213  (float)(spx.z * point.x + spy.z * point.y + spz.z * point.z)
2214  + node->spine.p[spi].c[2];
2215 
2216  } /* for(sec */
2217  } /* for(spi */
2218  ncoord=nsec*nspi;
2219 
2220 
2221  /* freeing SCP coordinates. not needed anymore. */
2222  FREE_IF_NZ (SCP);
2223 
2224  /************************************************************************
2225  * setting the values of *cindex to the right coords
2226  */
2227 
2228  triind = 0;
2229  {
2230  int x,z;
2231  int A,B,C,D; /* should referr to the four vertices of the polygon
2232  (hopefully) counted counter-clockwise, like
2233 
2234  D----C
2235  | |
2236  | |
2237  | |
2238  A----B
2239 
2240  */
2241  int Atex, Btex, Ctex, Dtex, Etex, Ftex; /* Tex Coord points */
2242 
2243  struct point_XYZ ac,bd, /* help vectors */
2244  ab,cd; /* help vectors for testing intersection */
2245  int E,F; /* third point to be used for the triangles*/
2246  double u,r, /* help variables for testing intersection */
2247  denominator, /* ... */
2248  numerator; /* ... */
2249 
2250  #ifdef VERBOSE
2251  printf("Coords: \n");
2252 
2253  for(x=0; x<nsec; x++) {
2254  for(z=0; z<nspi; z++) {
2255  int xxx = 3*(x+z*nsec);
2256  printf("coord: %d [%f %f %f] ",(x+z*nsec),
2257  coord[xxx], coord[xxx+1], coord[xxx+2]);
2258 
2259  }
2260  printf("\n");
2261  }
2262  printf("\n");
2263  #endif
2264 
2265 
2266  /* Now, lay out the spines/sections, and generate triangles */
2267  //register_Polyrep_combiner(); //default, component_text resets to this after compiling its text
2268  for(x=0; x<nsec-1; x++) {
2269  for(z=0; z<nspi-1; z++) {
2270  A=x+z*nsec;
2271  B=(x+1)+z*nsec;
2272  C=(x+1)+(z+1)*nsec;
2273  D= x+(z+1)*nsec;
2274 
2275  /* texture mapping coords */
2276  Atex = A; Btex = B; Ctex = C; Dtex = D;
2277 
2278  /* if we are circular, check to see if this is the first tri, or the last */
2279  /* the vertexes are identical, but for smooth normal calcs, make the */
2280  /* indexes the same, too */
2281  /* note, we dont touch tex coords here. */
2282  /* printf ("x %d z %d nsec %d nspi %d\n",x,z,nsec,nspi);*/
2283 
2284  if (tubular) {
2285  /* printf ("tubular, x %d nsec %d this_face %d\n",x,nsec,this_face);*/
2286  if (x==(nsec-2)) {
2287  B -=(x+1);
2288  C -=(x+1);
2289  }
2290  }
2291 
2292  if (circular) {
2293  if (z==(nspi-2)) {
2294  /* last row in column, assume z=nspi-2, subtract this off */
2295  C -= (z+1)*nsec;
2296  D -= (z+1)*nsec;
2297  }
2298  }
2299 
2300  /* calculate the distance A-C and see, if it is smaller as B-D */
2301  VEC_FROM_COORDDIFF(coord,C,coord,A,ac);
2302  VEC_FROM_COORDDIFF(coord,D,coord,B,bd);
2303 
2304  if(sqrt(VECSQ(ac))>sqrt(VECSQ(bd))) {
2305  E=B; F=D; Etex=Btex; Ftex=Dtex;
2306  } else {
2307  E=C; F=A; Etex=Ctex; Ftex=Atex;
2308  }
2309 
2310  /* if concave polygons are expected, we also expect intersecting ones
2311  so we are testing, whether A-B and D-C intersect */
2312  if(!node->convex) {
2313  VEC_FROM_COORDDIFF(coord,B,coord,A,ab);
2314  VEC_FROM_COORDDIFF(coord,D,coord,C,cd);
2315  /* ca=-ac */
2316  #ifdef VERBOSE
2317  printf("ab=[%f,%f,%f],cd=[%f,%f,%f]\n",
2318  ab.x,ab.y,ab.z,cd.x,cd.y,cd.z);
2319  printf("Orig: %d %d [%f %f %f] [%f %f %f] (%d, %d, %d) \n",
2320  D, C,
2321  coord[D*3], coord[D*3+1], coord[D*3+2],
2322  coord[C*3], coord[C*3+1], coord[C*3+2],
2323  ncoord, nsec, nspi
2324  );
2325  #endif
2326 
2327  denominator= ab.y*cd.x-ab.x*cd.y;
2328  numerator = (-ac.x)*cd.y-(-ac.y)*cd.x;
2329 
2330  r=u=-1;
2331  if(!APPROX(denominator,0)) {
2332  u=numerator/denominator;
2333  r=((-ac.x)*ab.y-(-ac.y)*ab.x)/denominator;
2334  } else {
2335  /* lines still may be coincident*/
2336  if(APPROX(numerator,0)) {
2337  /* we have to calculate u and r using the z coord*/
2338  denominator=ab.z*cd.x-ab.x*cd.z;
2339  numerator = (-ac.x)*cd.z-(-ac.z)*cd.x;
2340  if(!APPROX(denominator,0)) {
2341  u=numerator/denominator;
2342  r=((-ac.x)*ab.y-(-ac.y)*ab.x)/denominator;
2343  }
2344  }
2345  } /* else */
2346  #ifdef VERBOSE
2347  printf("u=%f, r=%f\n",u,r);
2348  #endif
2349 
2350  if(u>=0 && u<=1 && r>=0 && r<=1
2351  && APPROX((-ac.x)+u*ab.x,r*cd.x)
2352  && APPROX((-ac.y)+u*ab.y,r*cd.y)
2353  && APPROX((-ac.z)+u*ab.z,r*cd.z)) {
2354 
2355  #ifdef VERBOSE
2356  printf("Intersection found at P=[%f,%f,%f]!\n",
2357  coord[A*3]+u*ab.x,
2358  coord[A*3+1]+u*ab.y,
2359  coord[A*3+2]+u*ab.y
2360  );
2361  #endif
2362 
2363  coord[(ncoord)*3 ]=coord[A*3 ]+(float)(u*ab.x);
2364  coord[(ncoord)*3+1]=coord[A*3+1]+(float)(u*ab.y);
2365  coord[(ncoord)*3+2]=coord[A*3+2]+(float)(u*ab.z);
2366  E=ncoord;
2367  F=ncoord;
2368  ncoord_add++;
2369  ncoord++;
2370  }
2371 
2372  }
2373 
2374  /* printf ("tcindex %d\n",tcindex);*/
2375  /* printf ("Triangle1 %d %d %d\n",D,A,E);*/
2376  /* first triangle calculate pointfaces, etc, for this face */
2377  Elev_Tri(triind*3, this_face, D,A,E, TRUE , rep_, facenormals, pointfaces,ccw);
2378 
2379  tcindex[triind*3] = (GLuint)Dtex;
2380  tcindex[triind*3+2] = (GLuint)Etex;
2381  tcindex[triind*3+1] = (GLuint)Atex;
2382 
2383  defaultface[triind] = this_face;
2384  triind++;
2385 
2386  /* printf ("Triangle2 %d %d %d\n",B,C,F);*/
2387  /* second triangle - pointfaces, etc,for this face */
2388  Elev_Tri(triind*3, this_face, B, C, F, TRUE, rep_, facenormals, pointfaces,ccw);
2389 
2390  tcindex[triind*3] = (GLuint)Btex;
2391  tcindex[triind*3+1] = (GLuint)Ctex;
2392  tcindex[triind*3+2] = (GLuint)Ftex;
2393 
2394  if ((triind*3+2) >= tcindexsize)
2395  printf ("INTERNAL ERROR: Extrusion - tcindex size too small!\n");
2396  defaultface[triind] = this_face;
2397  triind ++;
2398  this_face ++;
2399 
2400  }
2401  }
2402 
2403  /* do normal calculations for the sides, here */
2404  for (tmp=0; tmp<(triind*3); tmp++) {
2405  if (HAVETOSMOOTH) {
2406  normalize_ifs_face (&rep_->normal[tmp*3],
2407  facenormals, pointfaces, cindex[tmp],
2408  defaultface[tmp/3], creaseAngle);
2409  } else {
2410  rep_->normal[tmp*3+0] = (float) facenormals[defaultface[tmp/3]].x;
2411  rep_->normal[tmp*3+1] = (float) facenormals[defaultface[tmp/3]].y;
2412  rep_->normal[tmp*3+2] = (float) facenormals[defaultface[tmp/3]].z;
2413  }
2414  rep_->norindex[tmp] = (GLuint)tmp;
2415  }
2416  /* keep track of where the sides end, triangle count-wise, for Normal mapping */
2417  end_of_sides = triind*3;
2418 
2419  /* tcindexes are TOTALLY different from sides - set this in case we are
2420  doing textures in the end caps */
2421  tci_ct = nspi*nsec;
2422 
2423  if(node->convex) {
2424  int endpoint;
2425 
2426  int triind_start; /* textures need 2 passes */
2427 
2428  /* if not tubular, we need one more triangle */
2429  if (tubular) endpoint = nsec-3-ncolinear_at_end;
2430  else endpoint = nsec-2-ncolinear_at_end;
2431 
2432 
2433  /* printf ("beginCap, starting at triind %d\n",triind);*/
2434 
2435  /* this is the simple case with convex polygons */
2436  if(beginCap) {
2437  triind_start = triind;
2438 
2439  for(x=0+ncolinear_at_begin; x<endpoint; x++) {
2440  Elev_Tri(triind*3, this_face, 0, x+2, x+1, TRUE , rep_, facenormals, pointfaces,ccw);
2441  defaultface[triind] = this_face;
2442  Extru_tex(triind*3, tci_ct, 0 , +x+2, x+1, tcindex ,ccw,tcindexsize);
2443  triind ++;
2444  }
2445 
2446  Extru_ST_map(triind_start,0+ncolinear_at_begin,endpoint,
2447  beginVals,nsec,tcindex, cindex, tcoord, tcoordsize);
2448  tci_ct+=endpoint-(0+ncolinear_at_begin);
2449  triind_start+=endpoint-(0+ncolinear_at_begin);
2450  this_face++;
2451  } /* if beginCap */
2452 
2453  if(endCap) {
2454  triind_start = triind;
2455 
2456  for(x=0+ncolinear_at_begin; x<endpoint; x++) {
2457  Elev_Tri(triind*3, this_face, 0 +(nspi-1)*nsec,
2458  x+1+(nspi-1)*nsec,x+2+(nspi-1)*nsec,
2459  TRUE , rep_, facenormals, pointfaces,ccw);
2460  defaultface[triind] = this_face;
2461  Extru_tex(triind*3, tci_ct, 0+(nspi-1)*nsec,
2462  x+1+(nspi-1)*nsec,
2463  x+2+(nspi-1)*nsec,
2464  tcindex,ccw,tcindexsize);
2465  triind ++;
2466  }
2467  this_face++;
2468  Extru_ST_map(triind_start,0+ncolinear_at_begin,endpoint,
2469  endVals, nsec, tcindex, cindex, tcoord, tcoordsize);
2470  } /* if endCap */
2471  /* for (tmp=0;tmp<tcindexsize; tmp++) printf ("index1D %d tcindex %d\n",tmp,tcindex[tmp]);*/
2472 
2473  } else
2474  if(beginCap || endCap) {
2475  /* polygons might be concave-> do tessellation */
2476  /* XXX - no textures yet - Linux Tesselators give me enough headaches;
2477  lets wait until they are all ok before trying texture mapping */
2478 
2479  /* give us some memory - this array will contain tessd triangle counts */
2480  int *tess_vs;
2481  struct SFVec3f *c1;
2482  GLDOUBLE tess_v[3];
2483  int endpoint;
2484  ttglobal tg = gglobal();
2485 
2486  tess_vs=MALLOC(int *, sizeof(*(tess_vs)) * (nsec - 3 - ncolinear_at_end) * 3);
2487 
2488  /* if not tubular, we need one more triangle */
2489  if (tubular) endpoint = nsec-1-ncolinear_at_end;
2490  else endpoint = nsec-ncolinear_at_end;
2491 
2492 
2493  if (beginCap) {
2494  tg->Tess.global_IFS_Coord_count = 0;
2495  //FW_GLU_BEGIN_POLYGON(tg->Tess.global_tessobj);
2496  gluTessBeginPolygon( tg->Tess.global_tessobj, NULL); //&cbdata );
2497  gluTessBeginContour( tg->Tess.global_tessobj );
2498 
2499  for(x=0+ncolinear_at_begin; x<endpoint; x++) {
2500  /* printf ("starting tv for x %d of %d\n",x,endpoint);*/
2501  c1 = (struct SFVec3f *) &rep_->actualCoord[3*x];
2502  /* printf ("and, coords for this one are: %f %f %f\n",*/
2503  /* c1->c[0], c1->c[1],c1->c[2]);*/
2504 
2505  tess_v[0] = c1->c[0]; tess_v[1] = c1->c[1]; tess_v[2] = c1->c[2];
2506  tess_vs[x] = x;
2507  FW_GLU_TESS_VERTEX(tg->Tess.global_tessobj,tess_v,&tess_vs[x]);
2508  }
2509  //FW_GLU_END_POLYGON(tg->Tess.global_tessobj);
2510  gluTessEndContour( tg->Tess.global_tessobj );
2511  gluTessEndPolygon( tg->Tess.global_tessobj );
2512 
2513  verify_global_IFS_Coords(ntri*3);
2514 
2515  for (x=0; x<tg->Tess.global_IFS_Coord_count; x+=3) {
2516  /* printf ("now, in 2nd for loop, x %d glob %d\n",x,*/
2517  /* global_IFS_Coord_count);*/
2518  Elev_Tri(triind*3, this_face, tg->Tess.global_IFS_Coords[x],
2519  tg->Tess.global_IFS_Coords[x+2], tg->Tess.global_IFS_Coords[x+1],
2520  TRUE , rep_, facenormals, pointfaces,ccw);
2521  defaultface[triind] = this_face;
2522  triind ++;
2523  }
2524  /* Tesselated faces may have a different normal than calculated previously */
2525  Extru_check_normal (facenormals,this_face,-1,rep_,ccw);
2526 
2527  this_face++;
2528  }
2529 
2530  if (endCap) {
2531  tg->Tess.global_IFS_Coord_count = 0;
2532  //FW_GLU_BEGIN_POLYGON(tg->Tess.global_tessobj);
2533  gluTessBeginPolygon( tg->Tess.global_tessobj, NULL); //&cbdata ); //cbdata is for combiner
2534  gluTessBeginContour( tg->Tess.global_tessobj );
2535 
2536  for(x=0+ncolinear_at_begin; x<endpoint; x++) {
2537  c1 = (struct SFVec3f *) &rep_->actualCoord[3*(x+(nspi-1)*nsec)];
2538  tess_v[0] = c1->c[0]; tess_v[1] = c1->c[1]; tess_v[2] = c1->c[2];
2539  tess_vs[x] = x+(nspi-1)*nsec;
2540  FW_GLU_TESS_VERTEX(tg->Tess.global_tessobj,tess_v,&tess_vs[x]);
2541  }
2542  //FW_GLU_END_POLYGON(tg->Tess.global_tessobj);
2543  gluTessEndContour( tg->Tess.global_tessobj );
2544  gluTessEndPolygon( tg->Tess.global_tessobj );
2545 
2546  verify_global_IFS_Coords(ntri*3);
2547 
2548  for (x=0; x<tg->Tess.global_IFS_Coord_count; x+=3) {
2549  Elev_Tri(triind*3, this_face, tg->Tess.global_IFS_Coords[x],
2550  tg->Tess.global_IFS_Coords[x+1], tg->Tess.global_IFS_Coords[x+2],
2551  TRUE , rep_, facenormals, pointfaces,ccw);
2552  defaultface[triind] = this_face;
2553  triind ++;
2554  }
2555  /* Tesselated faces may have a different normal than calculated previously */
2556  Extru_check_normal (facenormals,this_face,1,rep_,ccw);
2557 
2558  this_face++;
2559  }
2560 
2561  /* get rid of MALLOCd memory for tess */
2562  FREE_IF_NZ (tess_vs);
2563  } /* elseif */
2564 
2565  } /* end of block */
2566 
2567  /* if we have tesselated, we MAY have fewer triangles than estimated, so... */
2568  rep_->ntri=triind;
2569 
2570  /* for (tmp=0;tmp<tcindexsize; tmp++) printf ("index2 %d tcindex %d\n",tmp,tcindex[tmp]);*/
2571  /* do normal calculations for the caps here note - no smoothing */
2572  for (tmp=end_of_sides; tmp<(triind*3); tmp++) {
2573  rep_->normal[tmp*3+0] = (float) facenormals[defaultface[tmp/3]].x;
2574  rep_->normal[tmp*3+1] = (float) facenormals[defaultface[tmp/3]].y;
2575  rep_->normal[tmp*3+2] = (float) facenormals[defaultface[tmp/3]].z;
2576  rep_->norindex[tmp] = (GLuint)tmp;
2577  }
2578 
2579  /* do texture mapping calculations for sides */
2580  /* range check - this should NEVER happen... */
2581  if (tcoordsize <= ((nsec-1)+(nspi-1)*(nsec-1)*3+2)) {
2582  printf ("INTERNAL ERROR: Extrusion side tcoord calcs nspi %d nsec %d tcoordsize %d\n",
2583  nspi,nsec,tcoordsize);
2584  }
2585  for(sec=0; sec<nsec; sec++) {
2586  for(spi=0; spi<nspi; spi++) {
2587  /* printf ("tcoord idx %d %d %d tcoordsize %d ",*/
2588  /* (sec+spi*nsec)*3,(sec+spi*nsec)*3+1,(sec+spi*nsec)*3+2,tcoordsize);*/
2589  /* printf ("side texts sec %d spi %d\n",sec,spi);*/
2590  tcoord[(sec+spi*nsec)*3+0] = (float) sec/(nsec-1);
2591  tcoord[(sec+spi*nsec)*3+1] = 0;
2592  tcoord[(sec+spi*nsec)*3+2] = (float) spi/(nspi-1);
2593  /* printf (" %f %f\n",tcoord[(sec+spi*nsec)*3+0],tcoord[(sec+spi*nsec)*3+2]);*/
2594  }
2595  }
2596 
2597  #ifdef VERBOSE
2598  printf ("done, lets free\n");
2599  #endif
2600 
2601  /* we no longer need to keep normal-generating memory around */
2602  FREE_IF_NZ (defaultface);
2603  FREE_IF_NZ (pointfaces);
2604  FREE_IF_NZ (facenormals);
2605  FREE_IF_NZ (crossSection);
2606 
2607  FREE_IF_NZ (beginVals);
2608  FREE_IF_NZ (endVals);
2609 
2610 
2611  /* stream the texture coords so that they are linear as tcindex is not used in stream_polyrep */
2612  stream_extrusion_texture_coords (rep_, tcoord, tcindex);
2613 
2614  /* now that the tex coords are streamed, remove the temoporary arrays */
2615  FREE_IF_NZ (tcoord);
2616  FREE_IF_NZ (tcindex);
2617 
2618 
2619  #ifdef VERBOSE
2620  printf("Extrusion.GenPloyRep: triind=%d ntri=%d nctri=%d "
2621  "ncolinear_at_begin=%d ncolinear_at_end=%d\n",
2622  triind,ntri,nctri,ncolinear_at_begin,ncolinear_at_end);
2623 
2624  printf ("end VRMLExtrusion.pm\n");
2625  #endif
2626 
2627  /*****end of Member Extrusion */
2628 }