FreeWRL/FreeX3D  3.0.0
Polyrep.c
1 /*
2 
3 
4 ???
5 
6 */
7 
8 /****************************************************************************
9  This file is part of the FreeWRL/FreeX3D Distribution.
10 
11  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
12 
13  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
14  it under the terms of the GNU Lesser Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
19  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  GNU General Public License for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
25 ****************************************************************************/
26 
27 
28 
29 #include <config.h>
30 #include <system.h>
31 #include <display.h>
32 #include <internal.h>
33 
34 #include <libFreeWRL.h>
35 
36 #include "../vrml_parser/Structs.h"
37 #include "../main/headers.h"
38 #include "../opengl/Frustum.h"
39 #include "../opengl/Material.h"
40 #include "../opengl/OpenGL_Utils.h"
41 #include "../opengl/Textures.h"
42 #include "../scenegraph/Component_Shape.h"
43 #include "../scenegraph/RenderFuncs.h"
44 
45 #include "Polyrep.h"
46 #include "LinearAlgebra.h"
47 #include "Tess.h"
48 
49 
50 /* Polyrep rendering, node has a color field, which is an RGB field (not RGBA) and transparency is changing */
51 static void recalculateColorField(struct X3D_PolyRep *r) {
52  int n;
53  struct SFColorRGBA *newcolors;
54  float *op, *np;
55 
56  /* first, make sure we do not do this over and over... */
57  r->transparency = getAppearanceProperties()->transparency;
58 
59  newcolors = MALLOC (struct SFColorRGBA *, sizeof (struct SFColorRGBA)*r->ntri*3);
60  op = r->color;
61  np = (float *)newcolors;
62 
63  for (n=0; n<r->ntri*3; n++) {
64  *np = *op; np++; op++; /* R */
65  *np = *op; np++; op++; /* G */
66  *np = *op; np++; op++; /* B */
67  *np = getAppearanceProperties()->transparency; np++; op++; /* A */
68  }
69  FREE_IF_NZ(r->color);
70  r->color = (float *)newcolors;
71 
72  /* VBOs need this re-bound */
73 
74  if (r->VBO_buffers[COLOR_VBO] == 0) glGenBuffers(1,&r->VBO_buffers[COLOR_VBO]);
75  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,r->VBO_buffers[COLOR_VBO]);
76  glBufferData(GL_ARRAY_BUFFER,r->ntri*sizeof(struct SFColorRGBA)*3,r->color, GL_STATIC_DRAW);
77  FREE_IF_NZ(r->color);
78 }
79 
80 /* How many faces are in this IndexedFaceSet? */
81 
82 int count_IFS_faces(int cin, struct Multi_Int32 *coordIndex) {
83  /* lets see how many faces we have */
84  int pointctr=0;
85  int max_points_per_face = 0;
86  int min_points_per_face = 99999;
87  int i;
88  int faces = 0;
89 
90  if (coordIndex == NULL) return 0;
91  if (coordIndex->n == 0) return 0;
92 
93  for(i=0; i<cin; i++) {
94 
95  if((coordIndex->p[i] == -1) || (i==cin-1)) {
96  if(coordIndex->p[i] != -1) {
97  pointctr++;
98  }
99 
100  faces++;
101  if (pointctr > max_points_per_face)
102  max_points_per_face = pointctr;
103  if (pointctr < min_points_per_face)
104  min_points_per_face = pointctr;
105  pointctr = 0;
106  } else pointctr++;
107  }
108 
109 
110  /*
111  printf ("this structure has %d faces\n",faces);
112  printf (" max points per face %d\n",max_points_per_face);
113  printf (" min points per face %d\n\n",min_points_per_face);
114  */
115 
116  if (faces < 1) {
117  /* printf("an IndexedFaceSet with no faces found\n"); */
118  return (0);
119  }
120  return faces;
121 }
122 
123 
124 /* Generate the normals for each face of an IndexedFaceSet */
125 /* create two datastructures: */
126 /* - face normals; given a face, tell me the normal */
127 /* - point-face; for each point, tell me the face(s) */
128 
129 int IFS_face_normals (
130  struct point_XYZ *facenormals,
131  int *faceok,
132  int *pointfaces,
133  int faces,
134  int npoints,
135  int cin,
136  struct SFVec3f *points,
137  struct Multi_Int32 *coordIndex,
138  int ccw) {
139 
140  int tmp_a = 0, this_face_finished;
141  int i,checkpoint;
142  int facectr;
143  int pt_1, pt_2, pt_3;
144  float AC, BC;
145  struct SFVec3f *c1,*c2,*c3;
146  float a[3]; float b[3];
147 
148  int retval = FALSE;
149 
150  float this_vl;
151  struct point_XYZ thisfaceNorms;
152 
153  /* printf ("IFS_face_normals, faces %d\n",faces); */
154 
155  /* Assume each face is ok for now*/
156  for(i=0; i<faces; i++) {
157  faceok[i] = TRUE;
158  }
159 
160  /* calculate normals for each face*/
161  for(i=0; i<faces; i++) {
162  /* lets decide which normal to choose here, in case of more than 1 triangle.
163  we choose the triangle with the greatest vector length hoping that it is
164  the least "degenerate" of them all */
165  this_vl = 0.0f;
166  facenormals[i].x = 0.0;
167  facenormals[i].y = 0.0;
168  facenormals[i].z = 1.0;
169 
170 
171  if (tmp_a >= cin-2) {
172  printf ("last face in Indexed Geometry has not enough vertexes\n");
173  faceok[i] = FALSE;
174  } else {
175  /* does this face have at least 3 vertexes? */
176  if ((coordIndex->p[tmp_a] == -1) ||
177  (coordIndex->p[tmp_a+1] == -1) ||
178  (coordIndex->p[tmp_a+2] == -1)) {
179  printf ("IndexedFaceNormals: have a face with two or less vertexes\n");
180  faceok[i] = FALSE;
181 
182  if (coordIndex->p[tmp_a] != -1) tmp_a++;
183  } else {
184  /* check to see that the coordIndex does not point to a
185  point that is outside the range of our point array */
186  checkpoint = tmp_a;
187  while (checkpoint < cin) {
188  if (coordIndex->p[checkpoint] == -1) {
189  checkpoint = cin; /* stop the scan*/
190  } else {
191  /* printf ("verifying %d for face %d\n",coordIndex->p[checkpoint],i); */
192  if ((coordIndex->p[checkpoint] < 0) ||
193  (coordIndex->p[checkpoint] >= npoints)) {
194  printf ("Indexed Geometry face %d has a point out of range,",i);
195  printf (" point is %d, should be between 0 and %d\n",
196  coordIndex->p[checkpoint],npoints-1);
197  faceok[i] = FALSE;
198  }
199  checkpoint++;
200  }
201  }
202  }
203  }
204 
205  /* face has passed checks so far... */
206  if (faceok[i]) {
207  /* printf ("face %d ok\n",i); */
208  /* check for degenerate triangles -- we go through all triangles in a face to see which
209  triangle has the largest vector length */
210 
211  this_face_finished = FALSE;
212  pt_1 = tmp_a;
213  if (ccw) {
214  /* printf ("IFS face normals CCW\n"); */
215  pt_2 = tmp_a+1; pt_3 = tmp_a+2;
216  } else {
217  /* printf ("IFS face normals *NOT* CCW\n"); */
218  pt_3 = tmp_a+1; pt_2 = tmp_a+2;
219  }
220 
221  do {
222  /* first three coords give us the normal */
223  c1 = &(points[coordIndex->p[pt_1]]);
224  c2 = &(points[coordIndex->p[pt_2]]);
225  c3 = &(points[coordIndex->p[pt_3]]);
226 
227  a[0] = c2->c[0] - c1->c[0];
228  a[1] = c2->c[1] - c1->c[1];
229  a[2] = c2->c[2] - c1->c[2];
230  b[0] = c3->c[0] - c1->c[0];
231  b[1] = c3->c[1] - c1->c[1];
232  b[2] = c3->c[2] - c1->c[2];
233 
234  /* printf ("a0 %f a1 %f a2 %f b0 %f b1 %f b2 %f\n", a[0],a[1],a[2],b[0],b[1],b[2]); */
235 
236  thisfaceNorms.x = a[1]*b[2] - b[1]*a[2];
237  thisfaceNorms.y = -(a[0]*b[2] - b[0]*a[2]);
238  thisfaceNorms.z = a[0]*b[1] - b[0]*a[1];
239 
240  /* printf ("vector length is %f\n",calc_vector_length (thisfaceNorms)); */
241 
242  /* is this vector length greater than a previous one? */
243  if (calc_vector_length(thisfaceNorms) > this_vl) {
244  /* printf ("for face, using points %d %d %d\n",pt_1, pt_2, pt_3); */
245  this_vl = calc_vector_length(thisfaceNorms);
246  facenormals[i].x = thisfaceNorms.x;
247  facenormals[i].y = thisfaceNorms.y;
248  facenormals[i].z = thisfaceNorms.z;
249  }
250 
251  /* lets skip along to next triangle in this face */
252 
253  AC=(c1->c[0]-c3->c[0])*(c1->c[1]-c3->c[1])*(c1->c[2]-c3->c[2]);
254  BC=(c2->c[0]-c3->c[0])*(c2->c[1]-c3->c[1])*(c2->c[2]-c3->c[2]);
255  /* printf ("AC %f ",AC); printf ("BC %f \n",BC); */
256 
257  /* we have 3 points, a, b, c */
258  /* we also have 3 vectors, AB, AC, BC */
259  /* find out which one looks the closest one to skip out */
260  /* either we move both 2nd and 3rd points, or just the 3rd */
261 
262  if (ccw) {
263  /* printf ("moving along IFS face normals CCW\n"); */
264  if (fabs(AC) < fabs(BC)) { pt_2++; }
265  pt_3++;
266  } else {
267  /* printf ("moving along IFS face normals *NOT* CCW\n"); */
268  /* if (fabs(AC) < fabs(BC)) { pt_3++; } */
269  pt_2++;
270  }
271 
272  /* skip forward to the next couple of points - if possible */
273  /* printf ("looking at %d, cin is %d\n",tmp_a, cin); */
274  tmp_a ++;
275  if ((tmp_a >= cin-2) || (coordIndex->p[tmp_a+2] == -1)) {
276  this_face_finished = TRUE; tmp_a +=2;
277  }
278  } while (!this_face_finished);
279 
280  if (APPROX(this_vl,0.0)) {
281  /* printf ("face %d is degenerate\n",i); */
282  faceok[i] = 0;
283  } else {
284  /* printf ("face %d is ok\n",i); */
285  normalize_vector(&facenormals[i]);
286 
287  /*
288  printf ("vertices \t%f %f %f\n\t\t%f %f %f\n\t\t%f %f %f\n",
289  c1->c[0],c1->c[1],c1->c[2],
290  c2->c[0],c2->c[1],c2->c[2],
291  c3->c[0],c3->c[1],c3->c[2]);
292  printf ("normal %f %f %f\n\n",facenormals[i].x,
293  facenormals[i].y,facenormals[i].z);
294 
295  */
296  }
297 
298 
299  }
300 
301  /* skip forward to next ifs - we have the normal - but check for bad Points!*/
302  if (i<faces-1) {
303  if (tmp_a <= 0) {
304  /* this is an error in the input file; lets try and continue */
305  tmp_a = 1;
306  }
307 
308  if (tmp_a > 0) {
309  while (((coordIndex->p[tmp_a-1]) != -1) && (tmp_a < cin-2)) {
310  /* printf ("skipping past %d for face %d\n",coordIndex->p[tmp_a-1],i);*/
311  tmp_a++;
312  }
313  }
314  }
315  /* printf ("for face %d, vec len is %f\n",i,this_vl); */
316  }
317 
318 
319  /* do we have any valid faces??? */
320  for(i=0; i<faces; i++) {
321  if (faceok[i] == TRUE) {
322  retval = TRUE;
323  }
324  }
325  if (!retval) return retval; /* nope, lets just drop out of here */
326 
327 
328  /* now, go through each face, and make a point-face list
329  so that I can give it a point later, and I will know which face(s)
330  it belong to that point */
331  /* printf ("\nnow generating point-face list\n"); */
332  for (i=0; i<npoints; i++) { pointfaces[i*POINT_FACES]=0; }
333  facectr=0;
334  for(i=0; i<cin; i++) {
335  tmp_a=coordIndex->p[i];
336  /* printf ("pointfaces, coord %d coordIndex %d face %d\n",i,tmp_a,facectr); */
337  if (tmp_a == -1) {
338  facectr++;
339  } else {
340  if (faceok[facectr]) {
341  tmp_a*=POINT_FACES;
342  add_to_face (tmp_a,facectr,pointfaces);
343  } else {
344  /* printf ("skipping add_to_face for invalid face %d\n",facectr);*/
345  }
346  }
347  }
348 
349  /*
350  printf ("\ncheck \n");
351  for (i=0; i<npoints; i++) {
352  int tmp_b;
353 
354  tmp_a = i*POINT_FACES;
355  printf ("point %d is in %d faces, these are:\n ", i, pointfaces[tmp_a]);
356  for (tmp_b=0; tmp_b<pointfaces[tmp_a]; tmp_b++) {
357  printf ("%d ",pointfaces[tmp_a+tmp_b+1]);
358  }
359  printf ("\n");
360  }
361  */
362 
363  return retval;
364 }
365 
366 
367 
368 /* Tesselated faces MAY have the wrong normal calculated. re-calculate after tesselation */
369 
370 void Extru_check_normal (
371  struct point_XYZ *facenormals,
372  int this_face,
373  int direction,
374  struct X3D_PolyRep *rep_,
375  int ccw) {
376 
377  /* only use this after tesselator as we get coord indexes from global var */
378  struct SFVec3f *c1,*c2,*c3;
379  float a[3]; float b[3];
380  int zz1, zz2;
381  ttglobal tg = gglobal();
382 
383  if (ccw) {
384  zz1 = 1;
385  zz2 = 2;
386  } else {
387  zz1 = 2;
388  zz2 = 1;
389  }
390 
391  /* first three coords give us the normal */
392  c1 = (struct SFVec3f *) &rep_->actualCoord[3*tg->Tess.global_IFS_Coords[0]];
393  c2 = (struct SFVec3f *) &rep_->actualCoord[3*tg->Tess.global_IFS_Coords[zz1]];
394  c3 = (struct SFVec3f *) &rep_->actualCoord[3*tg->Tess.global_IFS_Coords[zz2]];
395 
396  /*printf ("Extru_check_normal, coords %d %d %d\n",global_IFS_Coords[0],
397  global_IFS_Coords[1],global_IFS_Coords[2]);
398  printf ("Extru_check_normal vertices \t%f %f %f\n\t\t%f %f %f\n\t\t%f %f %f\n",
399  c1->c[0],c1->c[1],c1->c[2],
400  c2->c[0],c2->c[1],c2->c[2],
401  c3->c[0],c3->c[1],c3->c[2]);
402  */
403 
404  a[0] = c2->c[0] - c1->c[0];
405  a[1] = c2->c[1] - c1->c[1];
406  a[2] = c2->c[2] - c1->c[2];
407  b[0] = c3->c[0] - c1->c[0];
408  b[1] = c3->c[1] - c1->c[1];
409  b[2] = c3->c[2] - c1->c[2];
410 
411  facenormals[this_face].x = a[1]*b[2] - b[1]*a[2] * direction;
412  facenormals[this_face].y = -(a[0]*b[2] - b[0]*a[2]) * direction;
413  facenormals[this_face].z = a[0]*b[1] - b[0]*a[1] * direction;
414 
415  if (APPROX(calc_vector_length (facenormals[this_face]),0.0)) {
416  ConsoleMessage ("WARNING: FreeWRL got degenerate triangle; OpenGL tesselator should not give degenerate triangles back %f\n",
417  fabs(calc_vector_length (facenormals[this_face])));
418  }
419 
420  normalize_vector(&facenormals[this_face]);
421  /* printf ("facenormal for %d is %f %f %f\n",this_face, facenormals[this_face].x,
422  facenormals[this_face].y, facenormals[this_face].z); */
423 }
424 
425 /* Tesselated faces MAY have the wrong normal calculated. re-calculate after tesselation */
426 
427 
428 void IFS_check_normal (
429  struct point_XYZ *facenormals,
430  int this_face,
431  struct SFVec3f *points, int base,
432  struct Multi_Int32 *coordIndex, int ccw) {
433 
434  struct SFVec3f *c1,*c2,*c3;
435  float a[3]; float b[3];
436  ttglobal tg = gglobal();
437 
438  /* printf ("IFS_check_normal, base %d points %d %d %d\n",base,*/
439  /* global_IFS_Coords[0],global_IFS_Coords[1],global_IFS_Coords[2]);*/
440  /* printf ("normal was %f %f %f\n\n",facenormals[this_face].x,*/
441  /* facenormals[this_face].y,facenormals[this_face].z);*/
442 
443 
444  /* first three coords give us the normal */
445  c1 = &(points[coordIndex->p[base+tg->Tess.global_IFS_Coords[0]]]);
446  if (ccw) {
447  c2 = &(points[coordIndex->p[base+tg->Tess.global_IFS_Coords[1]]]);
448  c3 = &(points[coordIndex->p[base+tg->Tess.global_IFS_Coords[2]]]);
449  } else {
450  c3 = &(points[coordIndex->p[base+tg->Tess.global_IFS_Coords[1]]]);
451  c2 = &(points[coordIndex->p[base+tg->Tess.global_IFS_Coords[2]]]);
452  }
453 
454  a[0] = c2->c[0] - c1->c[0];
455  a[1] = c2->c[1] - c1->c[1];
456  a[2] = c2->c[2] - c1->c[2];
457  b[0] = c3->c[0] - c1->c[0];
458  b[1] = c3->c[1] - c1->c[1];
459  b[2] = c3->c[2] - c1->c[2];
460 
461  facenormals[this_face].x = a[1]*b[2] - b[1]*a[2];
462  facenormals[this_face].y = -(a[0]*b[2] - b[0]*a[2]);
463  facenormals[this_face].z = a[0]*b[1] - b[0]*a[1];
464 
465  /* printf ("vector length is %f\n",calc_vector_length (facenormals[this_face])); */
466 
467  if (APPROX(calc_vector_length (facenormals[this_face]),0.0)) {
468  /* printf ("warning: Tesselated surface has invalid normal - if this is an IndexedFaceSet, check coordinates of ALL faces\n");*/
469  } else {
470 
471  normalize_vector(&facenormals[this_face]);
472 
473 
474  /* printf ("vertices \t%f %f %f\n\t\t%f %f %f\n\t\t%f %f %f\n",*/
475  /* c1->c[0],c1->c[1],c1->c[2],*/
476  /* c2->c[0],c2->c[1],c2->c[2],*/
477  /* c3->c[0],c3->c[1],c3->c[2]);*/
478  /* printf ("normal %f %f %f\n\n",facenormals[this_face].x,*/
479  /* facenormals[this_face].y,facenormals[this_face].z);*/
480  }
481 
482 }
483 
484 
485 void add_to_face (
486  int point,
487  int face,
488  int *pointfaces) {
489 
490  int count;
491  if (pointfaces[point] < (POINT_FACES-1)) {
492  /* room to add, but is it already there? */
493  for (count = 1; count <= pointfaces[point]; count++) {
494  if (pointfaces[point+count] == face) return;
495  }
496  /* ok, we have an empty slot, and face not already added */
497  pointfaces[point]++;
498  pointfaces[point+ pointfaces[point]] = face;
499  }
500 }
501 
502 /********************************************************************
503  *
504  * ElevationGrid Triangle
505  *
506  */
507 void Elev_Tri (
508  int vertex_ind,
509  int this_face,
510  int A,
511  int D,
512  int E,
513  int NONORMALS,
514  struct X3D_PolyRep *this_Elev,
515  struct point_XYZ *facenormals,
516  int *pointfaces,
517  int ccw) {
518 
519  struct SFVec3f *c1,*c2,*c3;
520  float a[3]; float b[3];
521  int tmp;
522 
523  /* printf ("Elev_Tri Triangle %d %d %d\n",A,D,E); */
524 
525  /* generate normals in a clockwise manner, reverse the triangle */
526  if (!(ccw)) {
527  tmp = D;
528  D = E;
529  E = tmp;
530  }
531 
532 
533  this_Elev->cindex[vertex_ind] = (GLuint)A;
534  this_Elev->cindex[vertex_ind+1] = (GLuint)D;
535  this_Elev->cindex[vertex_ind+2] = (GLuint)E;
536 
537  /*
538  printf ("Elev_Tri, vertices for vertex_ind %d are:",vertex_ind);
539  c1 = (struct SFVec3f *) &this_Elev->actualCoord[3*A];
540  c2 = (struct SFVec3f *) &this_Elev->actualCoord[3*D];
541  c3 = (struct SFVec3f *) &this_Elev->actualCoord[3*E];
542 
543  printf ("\n%f %f %f\n%f %f %f\n%f %f %f\n\n",
544  c1->c[0], c1->c[1],c1->c[2],c2->c[0],c2->c[1],c2->c[2],
545  c3->c[0],c3->c[1],c3->c[2]);
546  */
547 
548 
549  if (NONORMALS) {
550  /* calculate normal for this triangle */
551  c1 = (struct SFVec3f *) &this_Elev->actualCoord[3*A];
552  c2 = (struct SFVec3f *) &this_Elev->actualCoord[3*D];
553  c3 = (struct SFVec3f *) &this_Elev->actualCoord[3*E];
554 
555  /*
556  printf ("calc norms \n%f %f %f\n%f %f %f\n%f %f %f\n",
557  c1->c[0], c1->c[1],c1->c[2],c2->c[0],c2->c[1],c2->c[2],
558  c3->c[0],c3->c[1],c3->c[2]);
559  */
560 
561  a[0] = c2->c[0] - c1->c[0];
562  a[1] = c2->c[1] - c1->c[1];
563  a[2] = c2->c[2] - c1->c[2];
564  b[0] = c3->c[0] - c1->c[0];
565  b[1] = c3->c[1] - c1->c[1];
566  b[2] = c3->c[2] - c1->c[2];
567 
568  facenormals[this_face].x = a[1]*b[2] - b[1]*a[2];
569  facenormals[this_face].y = -(a[0]*b[2] - b[0]*a[2]);
570  facenormals[this_face].z = a[0]*b[1] - b[0]*a[1];
571 
572  /*
573  printf ("facenormals index %d is %f %f %f\n",this_face, facenormals[this_face].x,
574  facenormals[this_face].y, facenormals[this_face].z);
575  */
576 
577  /* add this face to the faces for this point */
578  add_to_face (A*POINT_FACES,this_face,pointfaces);
579  add_to_face (D*POINT_FACES,this_face,pointfaces);
580  add_to_face (E*POINT_FACES,this_face,pointfaces);
581  }
582 }
583 
584 
585 
586 /***********************************************************************8
587  *
588  * Extrusion Texture Mapping
589  *
590  ***********************************************************************/
591 
592 void Extru_tex(
593  int vertex_ind,
594  int tci_ct,
595  int A,
596  int B,
597  int C,
598  GLuint *tcindex,
599  int ccw,
600  int tcindexsize) {
601 
602  int j;
603 
604  /* bounds check */
605  /* printf ("Extru_tex, tcindexsize %d, vertex_ind %d\n",tcindexsize, vertex_ind); */
606  if (vertex_ind+2 >= tcindexsize) {
607  printf ("INTERNAL ERROR: Extru_tex, bounds check %d >= %d\n",vertex_ind+2,tcindexsize);
608  }
609 
610  /* generate textures in a clockwise manner, reverse the triangle */
611  if (!(ccw)) { j = B; B = C; C = j; }
612 
613  /* ok, we have to do textures; lets do the tcindexes and record min/max */
614  tcindex[vertex_ind] = (GLuint)(tci_ct+A);
615  tcindex[vertex_ind+1] =(GLuint)(tci_ct+B);
616  tcindex[vertex_ind+2] =(GLuint)(tci_ct+C);
617 }
618 
619 
620 /*********************************************************************
621  *
622  * S,T mappings for Extrusions on begin and end caps.
623  *
624  **********************************************************************/
625 
626 
627 void Extru_ST_map(
628  int triind_start,
629  int start,
630  int end,
631  float *Vals,
632  int nsec,
633  GLuint *tcindex,
634  GLuint *cindex,
635  float *GeneratedTexCoords,
636  int tcoordsize) {
637 
638  int x;
639  GLfloat minS = 9999.9f;
640  GLfloat maxS = -9999.9f;
641  GLfloat minT = 9999.9f;
642  GLfloat maxT = -9999.9f;
643 
644  GLfloat Srange = 0.0f;
645  GLfloat Trange = 0.0f;
646 
647  int Point_Zero; /* the point that all cap tris start at. see comment below */
648 
649  /* printf ("Extru_ST, nsec %d\n",nsec); */
650 
651  /* find the base and range of S, T */
652  for (x=0; x<nsec; x++) {
653  /* printf ("for textures, coord vals %f %f for sec %d\n", Vals[x*2+0], Vals[x*2+1],x); */
654  if (Vals[x*2+0] < minS) minS = Vals[x*2+0];
655  if (Vals[x*2+0] > maxS) maxS = Vals[x*2+0];
656  if (Vals[x*2+1] < minT) minT = Vals[x*2+1];
657  if (Vals[x*2+1] > maxT) maxT = Vals[x*2+1];
658  }
659  Srange = maxS -minS;
660  Trange = maxT - minT;
661 
662  /* I hate divide by zeroes. :-) */
663  if (APPROX(Srange, 0.0)) Srange = 0.001f;
664  if (APPROX(Trange, 0.0)) Trange = 0.001f;
665 
666  /* printf ("minS %f Srange %f minT %f Trange %f\n",minS,Srange,minT,Trange); */
667 
668  /* Ok, we know the min vals of S and T; and the ranges. The way that end cap
669  * triangles are drawn is that we have one common point, the first point in
670  * each triangle. Use this as a base into the Vals index, to generate a S,T
671  * tex coord mapping for the [0,1] range
672  */
673 
674  for(x=start; x<end; x++) {
675  int tci;
676  // int ci;
677 
678  /*
679  printf ("Extru_ST_Map: triangle has tex vertices:%d %d %d ",
680  tcindex[triind_start*3],
681  tcindex[triind_start*3+1] ,
682  tcindex[triind_start*3+2]);
683  printf ("Extru_ST_Map: coord vertices:%d %d %d\n",
684  cindex[triind_start*3],
685  cindex[triind_start*3+1] ,
686  cindex[triind_start*3+2]);
687  */
688 
689  /* for first vertex */
690  tci = tcindex[triind_start*3];
691  //ci = cindex[triind_start*3];
692  Point_Zero = tci;
693 
694  if ((tci*3+2) >= tcoordsize) {
695  printf ("INTERNAL ERROR: Extru_ST_map(1), index %d greater than %d \n",(tci*3+2),tcoordsize);
696  return;
697  }
698 
699  /* S value */
700  GeneratedTexCoords[tci*3+0] = (Vals[(tci-Point_Zero)*2+0] - minS) / Srange ;
701 
702  /* not used by render_polyrep */
703  GeneratedTexCoords[tci*3+1] = 0;
704 
705  /* T value */
706  GeneratedTexCoords[tci*3+2] = (Vals[(tci-Point_Zero)*2+1] - minT) / Trange;
707 
708 
709  /* for second vertex */
710  tci = tcindex[triind_start*3+1];
711  //ci = cindex[triind_start*3+1];
712 
713  if ((tci*3+2) >= tcoordsize) {
714  printf ("INTERNAL ERROR: Extru_ST_map(2), index %d greater than %d \n",(tci*3+2),tcoordsize);
715  return;
716  }
717 
718  /* S value */
719  GeneratedTexCoords[tci*3+0] = (Vals[(tci-Point_Zero)*2+0] - minS) / Srange ;
720 
721  /* not used by render_polyrep */
722  GeneratedTexCoords[tci*3+1] = 0;
723 
724  /* T value */
725  GeneratedTexCoords[tci*3+2] = (Vals[(tci-Point_Zero)*2+1] - minT) / Trange;
726 
727 
728  /* for third vertex */
729  tci = tcindex[triind_start*3+2];
730 
731  if ((tci*3+2) >= tcoordsize) {
732  printf ("INTERNAL ERROR: Extru_ST_map(3), index %d greater than %d \n",(tci*3+2),tcoordsize);
733  return;
734  }
735 
736  /* S value */
737  GeneratedTexCoords[tci*3+0] = (Vals[(tci-Point_Zero)*2+0] - minS) / Srange ;
738 
739  /* not used by render_polyrep */
740  GeneratedTexCoords[tci*3+1] = 0;
741 
742  /* T value */
743  GeneratedTexCoords[tci*3+2] = (Vals[(tci-Point_Zero)*2+1] - minT) / Trange;
744 
745  triind_start++;
746  }
747 }
748 
749 
750 void do_glNormal3fv(struct SFVec3f *dest, GLfloat *param) {
751  struct point_XYZ myp;
752 
753  /* normalize all vectors; even if they are coded into a VRML file */
754 
755  myp.x = param[0]; myp.y = param[1]; myp.z = param[2];
756 
757  normalize_vector (&myp);
758 
759  dest->c[0] = (float) myp.x; dest->c[1] = (float) myp.y; dest->c[2] = (float) myp.z;
760 }
761 
762 
763 
764 
765 
766 /*********************************************************************
767  *
768  * render_polyrep : render one of the internal polygonal representations
769  * for some nodes
770  *
771  ********************************************************************/
772 #define DESIRE(whichOne,zzz) ((whichOne & zzz)==zzz)
773 
774 void render_polyrep(void *node) {
775  //struct X3D_Virt *virt;
776  struct X3D_Node *renderedNodePtr;
777  struct X3D_PolyRep *pr;
778  int hasc;
779 
780 
781  ttglobal tg = gglobal();
782 
783  renderedNodePtr = X3D_NODE(node);
784  //virt = virtTable[renderedNodePtr->_nodeType];
785  pr = renderedNodePtr->_intern;
786 
787  #ifdef TEXVERBOSE
788  printf ("\nrender_polyrep, _nodeType %s\n",stringNodeType(renderedNodePtr->_nodeType));
789  printf ("ntri %d\n",pr->ntri);
790  #endif
791 
792  if (pr->ntri==0) {
793  /* no triangles */
794  return;
795  }
796 
797  // do we have VBOs here? were they removed??
798  if ((pr->VBO_buffers[VERTEX_VBO]) == 0) return;
799 
800  if (!pr->streamed) {
801  printf ("render_polyrep, not streamed, returning\n");
802  return;
803  }
804 
805  /* save these values for streaming the texture coordinates later */
806  tg->Textures.global_tcin = pr->tcindex;
807  tg->Textures.global_tcin_count = pr->ntri*3;
808  tg->Textures.global_tcin_lastParent = node;
809 
810  /* we take the geometry here, and push it up the stream. */
811  setExtent( renderedNodePtr->EXTENT_MAX_X, renderedNodePtr->EXTENT_MIN_X, renderedNodePtr->EXTENT_MAX_Y,
812  renderedNodePtr->EXTENT_MIN_Y, renderedNodePtr->EXTENT_MAX_Z, renderedNodePtr->EXTENT_MIN_Z,
813  renderedNodePtr);
814 
815  /* clockwise or not?*/
816  if (!pr->ccw) { FW_GL_FRONTFACE(GL_CW); }
817  //http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/lighting.html#t-Litcolourandalpha
818  //if lit, use colors if colornode and (intensity or no texture)
819  hasc = ((pr->VBO_buffers[COLOR_VBO]!=0) || pr->color) && (tg->RenderFuncs.last_texture_type!=TEXTURE_NO_ALPHA);
820 
821  /* Do we have any colours? Are textures, if present, not RGB? */
822  if(hasc){
823  if (!pr->isRGBAcolorNode)
824  if (!APPROX(pr->transparency,getAppearanceProperties()->transparency)) {
825  recalculateColorField(pr);
826  }
827 
828  LIGHTING_ON
829  }
830 
831  /* status bar, text do not have normals*/
832  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,0);
833  if (pr->VBO_buffers[NORMAL_VBO]!=0 ) {
834  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, pr->VBO_buffers[NORMAL_VBO]);
835  FW_GL_NORMAL_POINTER(GL_FLOAT,0,0);
836  if(DESIRE(getShaderFlags().base,SHADINGSTYLE_FLAT) ) {
837  if(pr->last_normal_type != 1)
838  glBufferData(GL_ARRAY_BUFFER,sizeof (GLfloat)*3*pr->ntri*3,pr->flat_normal,GL_STATIC_DRAW); /* OpenGL-ES */
839  pr->last_normal_type = 1;
840  }else {
841  if(pr->last_normal_type != 0)
842  glBufferData(GL_ARRAY_BUFFER,sizeof (GLfloat)*3*pr->ntri*3,pr->normal,GL_STATIC_DRAW); /* OpenGL-ES */
843  pr->last_normal_type = 0;
844  }
845  }
846 
847  if (pr->VBO_buffers[FOG_VBO]!=0) {
848  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, pr->VBO_buffers[FOG_VBO]);
849  FW_GL_FOG_POINTER(GL_FLOAT,0,0);
850  }
851 
852  /* colours? */
853  if (hasc) {
854 
855  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,pr->VBO_buffers[COLOR_VBO]);
856  FW_GL_COLOR_POINTER(4,GL_FLOAT,0,0);
857  }
858 
859 
860  /* textures?*/
861  if (pr->VBO_buffers[TEXTURE_VBO0] != 0) {
862  int k;
863  struct textureVertexInfo mtf[4] = {{NULL,2,GL_FLOAT,0, NULL,NULL},
864  {NULL,2,GL_FLOAT,0, NULL,NULL},{NULL,2,GL_FLOAT,0, NULL,NULL},{NULL,2,GL_FLOAT,0, NULL,NULL}};
865  for(k=0;k<max(1,pr->ntcoord);k++){
866  //FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,pr->VBO_buffers[TEXTURE_VBO0+k]);
867  mtf[k].VBO = pr->VBO_buffers[TEXTURE_VBO0+k];
868  mtf[k].TC_size = pr->ntexdim[k];
869  if(k > 0) mtf[k-1].next = &mtf[k];
870  }
871  textureCoord_send(mtf);
872  } else {
873  ConsoleMessage("skipping tds of textures");
874  }
875 
876  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, pr->VBO_buffers[VERTEX_VBO]);
877  FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER,pr->VBO_buffers[INDEX_VBO]);
878  FW_GL_VERTEX_POINTER(3,GL_FLOAT,0,0);
879 
880  if(DESIRE(getShaderFlags().base,SHADINGSTYLE_WIRE)){
881  //wireframe triangles
882  if(pr->last_index_type != 1)
883  glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof (GLushort)*pr->ntri*3*2,pr->wire_indices,GL_STATIC_DRAW); /* OpenGL-ES */
884  pr->last_index_type = 1;
885  //if (setupShader())
886  // glDrawElements(GL_LINES, pr->ntri*3*2, GL_UNSIGNED_SHORT, NULL);
887  sendElementsToGPU(GL_LINES,pr->ntri*3*2,NULL);
888  }else{
889  //surface triangles
890  //glDrawArrays(GL_TRIANGLES,,,) doesn't use indices - its glDrawElements that does
891  //if(pr->last_index_type != 0)
892  // glBufferData(GL_ELEMENT_ARRAY_BUFFER,sizeof (GLushort)*pr->ntri*3,pr->tri_indices,GL_STATIC_DRAW); /* OpenGL-ES */
893  pr->last_index_type = 0;
894  sendArraysToGPU(GL_TRIANGLES,0,pr->ntri*3);
895  }
896 
897  /* turn VBOs off for now */
898  //FW_GL_BINDBUFFER(GL_ARRAY_BUFFER, 0);
899  //FW_GL_BINDBUFFER(GL_ELEMENT_ARRAY_BUFFER, 0);
900 
901  tg->Mainloop.trisThisLoop += pr->ntri;
902 
903 
904 
905 PRINT_GL_ERROR_IF_ANY("");
906 
907  if (!pr->ccw) FW_GL_FRONTFACE(GL_CCW);
908 
909  #ifdef TEXVERBOSE
910  {
911  int i;
912  int *cin;
913  float *cod;
914  float *tcod;
915  tcod = pr->GeneratedTexCoords;
916  cod = pr->actualCoord;
917  cin = pr->cindex;
918  printf ("\n\nrender_polyrep:\n");
919  for (i=0; i<pr->ntri*3; i++) {
920  printf ("i %d cindex %d vertex %f %f %f",i,cin[i],
921  cod[cin[i]*3+0],
922  cod[cin[i]*3+1],
923  cod[cin[i]*3+2]);
924 
925  if (tcod != 0) {
926  printf (" tex %f %f",
927  tcod[cin[i]*2+0],
928  tcod[cin[i]*2+1]);
929  }
930  printf ("\n");
931  }
932  }
933  #endif
934 
935 PRINT_GL_ERROR_IF_ANY("");
936 
937 
938 }
939 
940 
941 /*********************************************************************
942  *
943  * render_ray_polyrep : get intersections of a ray with one of the
944  * polygonal representations
945  *
946  * currently handled:
947  * rendray_Text
948  * rendray_ElevationGrid
949  * rendray_Extrusion
950  * rendray_IndexedFaceSet
951  * rendray_ElevationGrid
952  * rendray_IndexedTriangleSet
953  * rendray_IndexedTriangleFanSet
954  * rendray_IndexedTriangleStripSet
955  * rendray_TriangleSet
956  * rendray_TriangleFanSet
957  * rendray_TriangleStripSet
958  * rendray_GeoElevationGrid
959  */
960 
961 
962 void render_ray_polyrep(void *node) {
963  //struct X3D_Virt *virt;
964  struct X3D_Node *genericNodePtr;
965  struct X3D_PolyRep *polyRep;
966  int i;
967  int pt;
968  float *point[3];
969  struct point_XYZ v1, v2, v3;
970  //struct point_XYZ ray;
971  float pt1, pt2, pt3;
972  struct point_XYZ hitpoint;
973  float tmp1,tmp2;
974  float v1len, v2len, v3len;
975  float v12pt;
976  struct point_XYZ t_r1,t_r2;
977  //ttglobal tg;
978 
979  /* is this structure still loading? */
980  if (!node) return;
981  //tg = gglobal();
982  //VECCOPY(t_r1,tg->RenderFuncs.t_r1);
983  //VECCOPY(t_r2,tg->RenderFuncs.t_r2);
984  get_current_ray(&t_r1, &t_r2);
985  //VECCOPY(t_r3,tg->RenderFuncs.t_r3);
986 
987  //ray.x = t_r2.x - t_r1.x;
988  //ray.y = t_r2.y - t_r1.y;
989  //ray.z = t_r2.z - t_r1.z;
990 
991  genericNodePtr = X3D_NODE(node);
992  //virt = virtTable[genericNodePtr->_nodeType];
993 
994  /* is this structure still loading? */
995  if (!(genericNodePtr->_intern)) {
996  /* printf ("render_ray_polyrep - no internal structure, returning\n"); */
997  return;
998  }
999 
1000  polyRep = genericNodePtr->_intern;
1001 
1002  /*
1003  printf("render_ray_polyrep %d '%s' (%d %d): %d\n",node,stringNodeType(genericNodePtr->_nodeType),
1004  genericNodePtr->_change, polyRep->_change, polyRep->ntri);
1005  */
1006 
1007 
1008 
1009  for(i=0; i<polyRep->ntri; i++) {
1010  for(pt = 0; pt<3; pt++) {
1011  int ind = polyRep->cindex[i*3+pt];
1012  point[pt] = (polyRep->actualCoord+3*ind);
1013  }
1014 
1015  /*
1016  printf ("have points (%f %f %f) (%f %f %f) (%f %f %f)\n",
1017  point[0][0],point[0][1],point[0][2],
1018  point[1][0],point[1][1],point[1][2],
1019  point[2][0],point[2][1],point[2][2]);
1020  */
1021 
1022  /* First we need to project our point to the surface */
1023  /* Poss. 1: */
1024  /* Solve s1xs2 dot ((1-r)r1 + r r2 - pt0) == 0 */
1025  /* I.e. calculate s1xs2 and ... */
1026  v1.x = point[1][0] - point[0][0];
1027  v1.y = point[1][1] - point[0][1];
1028  v1.z = point[1][2] - point[0][2];
1029  v2.x = point[2][0] - point[0][0];
1030  v2.y = point[2][1] - point[0][1];
1031  v2.z = point[2][2] - point[0][2];
1032  v1len = (float) sqrt(VECSQ(v1)); VECSCALE(v1, 1/v1len);
1033  v2len = (float) sqrt(VECSQ(v2)); VECSCALE(v2, 1/v2len);
1034  v12pt = (float) VECPT(v1,v2);
1035 
1036  /* this will get around a divide by zero further on JAS */
1037  if (fabs(v12pt-1.0) < 0.00001) continue;
1038 
1039  /* if we have a degenerate triangle, we can't compute a normal, so skip */
1040 
1041  if ((fabs(v1len) > 0.00001) && (fabs(v2len) > 0.00001)) {
1042 
1043  /* v3 is our normal to the surface */
1044  VECCP(v1,v2,v3);
1045  v3len = (float) sqrt(VECSQ(v3)); VECSCALE(v3, 1/v3len);
1046 
1047  pt1 = (float) VECPT(t_r1,v3);
1048  pt2 = (float) VECPT(t_r2,v3);
1049  pt3 = (float) (v3.x * point[0][0] + v3.y * point[0][1] + v3.z * point[0][2]);
1050  /* Now we have (1-r)pt1 + r pt2 - pt3 = 0
1051  * r * (pt1 - pt2) = pt1 - pt3
1052  */
1053  tmp1 = pt1-pt2;
1054  if(!APPROX(tmp1,0)) {
1055  float ra, rb;
1056  float k,l;
1057  struct point_XYZ p0h;
1058 
1059  tmp2 = (float) ((pt1-pt3) / (pt1-pt2));
1060  hitpoint.x = MRATX(tmp2);
1061  hitpoint.y = MRATY(tmp2);
1062  hitpoint.z = MRATZ(tmp2);
1063  /* Now we want to see if we are in the triangle */
1064  /* Projections to the two triangle sides */
1065  p0h.x = hitpoint.x - point[0][0];
1066  p0h.y = hitpoint.y - point[0][1];
1067  p0h.z = hitpoint.z - point[0][2];
1068  ra = (float) VECPT(v1, p0h);
1069  if(ra < 0.0f) {continue;}
1070  rb = (float) VECPT(v2, p0h);
1071  if(rb < 0.0f) {continue;}
1072  /* Now, the condition for the point to
1073  * be inside
1074  * (ka + lb = p)
1075  * (k + l b.a = p.a)
1076  * (k b.a + l = p.b)
1077  * (k - (b.a)**2 k = p.a - (b.a)*p.b)
1078  * k = (p.a - (b.a)*(p.b)) / (1-(b.a)**2)
1079  */
1080  k = (ra - v12pt * rb) / (1-v12pt*v12pt);
1081  l = (rb - v12pt * ra) / (1-v12pt*v12pt);
1082  k /= v1len; l /= v2len;
1083  if(k+l > 1 || k < 0 || l < 0) {
1084  continue;
1085  }
1086  rayhit(((float)(tmp2)),
1087  ((float)(hitpoint.x)),
1088  ((float)(hitpoint.y)),
1089  ((float)(hitpoint.z)),
1090  ((float)(v3.x)),
1091  ((float)(v3.y)),
1092  ((float)(v3.z)),
1093  ((float)-1),((float)-1), "polyrep");
1094  }
1095  /*
1096  } else {
1097  printf ("render_ray_polyrep, skipping degenerate triangle\n");
1098  */
1099  }
1100  }
1101 }
1102 
1103 // https://en.wikipedia.org/wiki/Möller–Trumbore_intersection_algorithm
1104 #define EPSILON 0.000001
1105 int triangle_intersection( float * V1, // Triangle vertices
1106  float * V2,
1107  float * V3,
1108  float * O, //Ray origin
1109  float * D, //Ray direction
1110  float* out ) // scale of ray direction from origin to intersection
1111 {
1112  float e1[3], e2[3]; //Edge1, Edge2
1113  float P[3], Q[3], T[3];
1114  float det, inv_det, u, v;
1115  float t;
1116 
1117  //Find vectors for two edges sharing V1
1118  vecdif3f(e1, V2, V1);
1119  vecdif3f(e2, V3, V1);
1120  //Begin calculating determinant - also used to calculate u parameter
1121  veccross3f(P, D, e2);
1122  //if determinant is near zero, ray lies in plane of triangle or ray is parallel to plane of triangle
1123  det = vecdot3f(e1, P);
1124  //NOT CULLING
1125  if(det > -EPSILON && det < EPSILON) return 0;
1126  inv_det = 1.f / det;
1127 
1128  //calculate distance from V1 to ray origin
1129  vecdif3f(T, O, V1);
1130 
1131  //Calculate u parameter and test bound
1132  u = vecdot3f(T, P) * inv_det;
1133  //The intersection lies outside of the triangle
1134  if(u < 0.f || u > 1.f) return 0;
1135 
1136  //Prepare to test v parameter
1137  veccross3f(Q, T, e1);
1138 
1139  //Calculate V parameter and test bound
1140  v = vecdot3f(D, Q) * inv_det;
1141  //The intersection lies outside of the triangle
1142  if(v < 0.f || u + v > 1.f) return 0;
1143 
1144  t = vecdot3f(e2, Q) * inv_det;
1145 
1146  if(t > EPSILON) { //ray intersection
1147  *out = t;
1148  return 1;
1149  }
1150 
1151  // No hit, no win
1152  return 0;
1153 }
1154 
1155 enum {
1156  RAYTRIALGO_DEFAULT = 1,
1157  RAYTRIALGO_MULLER = 2,
1158  //Not implemented: watertight http://jcgt.org/published/0002/01/05/paper.pdf
1159 };
1160 static int raytrialgo = RAYTRIALGO_MULLER;
1161 int intersect_polyrep(struct X3D_Node *node, float *p1, float *p2, float *nearest, float *normal){
1162  //need a utility function like part of guts of render_ray_polyrep
1163  //everything in same coordinate system, no matrix multiplication in here
1164  //p1, p2 - 2 points forming ray, in direciton from p1 toward p2, of length p2-p1
1165  //return value:
1166  // count of intersections - can be used for inside test (odd - inside, even - outside)
1167  // nearest[3] - the intersection nearest p1
1168  // normal[3] - normal at nearest intersection
1169 
1170  //struct X3D_Virt *virt;
1171  struct X3D_Node *genericNodePtr;
1172  struct X3D_PolyRep *polyRep;
1173  int i, nintersections, ihavehit;
1174  int pt;
1175  float nearestdist, delta[3];
1176  float *point[3];
1177  struct point_XYZ v1, v2, v3;
1178  //struct point_XYZ ray;
1179  float pt1, pt2, pt3;
1180  struct point_XYZ hitpoint;
1181  float tmp1,tmp2;
1182  float v1len, v2len, v3len;
1183  float v12pt;
1184  struct point_XYZ t_r1,t_r2;
1185  //ttglobal tg;
1186 
1187  ihavehit = -1;
1188 
1189  /* is this structure still loading? */
1190  if (!node) return 0;
1191  //tg = gglobal();
1192  //VECCOPY(t_r1,tg->RenderFuncs.t_r1);
1193  //VECCOPY(t_r2,tg->RenderFuncs.t_r2);
1194 // get_current_ray(&t_r1, &t_r2);
1195  vecdif3f(delta,p2,p1);
1196  nearestdist = veclength3f(delta) + .000001f;
1197  nintersections = 0;
1198  t_r1.x = p1[0];
1199  t_r1.y = p1[1];
1200  t_r1.z = p1[2];
1201  t_r2.x = p2[0];
1202  t_r2.y = p2[1];
1203  t_r2.z = p2[2];
1204  //VECCOPY(t_r3,tg->RenderFuncs.t_r3);
1205 
1206  //ray.x = t_r2.x - t_r1.x;
1207  //ray.y = t_r2.y - t_r1.y;
1208  //ray.z = t_r2.z - t_r1.z;
1209 
1210  genericNodePtr = X3D_NODE(node);
1211  //virt = virtTable[genericNodePtr->_nodeType];
1212 
1213  /* is this structure still loading? */
1214  if (!(genericNodePtr->_intern)) {
1215  /* printf ("render_ray_polyrep - no internal structure, returning\n"); */
1216  return 0;
1217  }
1218 
1219  polyRep = genericNodePtr->_intern;
1220 
1221  /*
1222  printf("render_ray_polyrep %d '%s' (%d %d): %d\n",node,stringNodeType(genericNodePtr->_nodeType),
1223  genericNodePtr->_change, polyRep->_change, polyRep->ntri);
1224  */
1225 
1226 
1227 
1228  for(i=0; i<polyRep->ntri; i++) {
1229  for(pt = 0; pt<3; pt++) {
1230  int ind = polyRep->cindex[i*3+pt];
1231  point[pt] = (polyRep->actualCoord+3*ind);
1232  }
1233  if(raytrialgo == RAYTRIALGO_MULLER){
1234  //works for particlephysics > bounded physics
1235  float tscale, d2[3],delta[3];
1236  vecdif3f(delta,p2,p1);
1237  vecnormalize3f(d2,delta); //muller takes a D normalized direction vector
1238  if(triangle_intersection(point[0],point[1],point[2],p1,d2,&tscale)){
1239  //printf("muller-trumbore intersection tascale %f nearestdist %f\n",tscale,nearestdist);
1240  nintersections++;
1241  if(tscale > 0.0f && tscale < nearestdist){
1242  //closest so far
1243  float e1[3],e2[3],nn[3],pd[3];
1244  vecscale3f(pd,d2,tscale);
1245  vecadd3f(nearest,p1,pd);
1246  //compute normal to triangle
1247  vecdif3f(e1,point[1],point[0]);
1248  vecdif3f(e2,point[2],point[0]);
1249  veccross3f(nn,e1,e2); //e2,e1 points inside, e1,e2 points outside
1250  vecnormalize3f(normal,nn);
1251  nearestdist = tscale;
1252  ihavehit = 1;
1253  }
1254  }
1255  }else if(raytrialgo == RAYTRIALGO_DEFAULT){
1256  //doesn't work right for particle physics > bounded physics
1257  //x leaks on right side of IFS box, occassionally leaky left side
1258  /*
1259  printf ("have points (%f %f %f) (%f %f %f) (%f %f %f)\n",
1260  point[0][0],point[0][1],point[0][2],
1261  point[1][0],point[1][1],point[1][2],
1262  point[2][0],point[2][1],point[2][2]);
1263  */
1264 
1265  /* First we need to project our point to the surface */
1266  /* Poss. 1: */
1267  /* Solve s1xs2 dot ((1-r)r1 + r r2 - pt0) == 0 */
1268  /* I.e. calculate s1xs2 and ... */
1269  v1.x = point[1][0] - point[0][0];
1270  v1.y = point[1][1] - point[0][1];
1271  v1.z = point[1][2] - point[0][2];
1272  v2.x = point[2][0] - point[0][0];
1273  v2.y = point[2][1] - point[0][1];
1274  v2.z = point[2][2] - point[0][2];
1275  v1len = (float) sqrt(VECSQ(v1)); VECSCALE(v1, 1/v1len);
1276  v2len = (float) sqrt(VECSQ(v2)); VECSCALE(v2, 1/v2len);
1277  v12pt = (float) VECPT(v1,v2);
1278 
1279  /* this will get around a divide by zero further on JAS */
1280  if (fabs(v12pt-1.0) < 0.00001)
1281  continue;
1282 
1283  /* if we have a degenerate triangle, we can't compute a normal, so skip */
1284 
1285  if ((fabs(v1len) > 0.00001) && (fabs(v2len) > 0.00001)) {
1286 
1287  /* v3 is our normal to the surface */
1288  VECCP(v1,v2,v3);
1289  v3len = (float) sqrt(VECSQ(v3)); VECSCALE(v3, 1/v3len);
1290 
1291  pt1 = (float) VECPT(t_r1,v3);
1292  pt2 = (float) VECPT(t_r2,v3);
1293  pt3 = (float) (v3.x * point[0][0] + v3.y * point[0][1] + v3.z * point[0][2]);
1294  /* Now we have (1-r)pt1 + r pt2 - pt3 = 0
1295  * r * (pt1 - pt2) = pt1 - pt3
1296  */
1297  tmp1 = pt1-pt2;
1298  if(!APPROX(tmp1,0)) {
1299  float ra, rb;
1300  float k,l;
1301  struct point_XYZ p0h;
1302 
1303  tmp2 = (float) ((pt1-pt3) / (pt1-pt2));
1304  hitpoint.x = MRATX(tmp2);
1305  hitpoint.y = MRATY(tmp2);
1306  hitpoint.z = MRATZ(tmp2);
1307  /* Now we want to see if we are in the triangle */
1308  /* Projections to the two triangle sides */
1309  p0h.x = hitpoint.x - point[0][0];
1310  p0h.y = hitpoint.y - point[0][1];
1311  p0h.z = hitpoint.z - point[0][2];
1312  ra = (float) VECPT(v1, p0h);
1313  if(ra < 0.0f) {
1314  continue;
1315  }
1316  rb = (float) VECPT(v2, p0h);
1317  if(rb < 0.0f) {
1318  continue;
1319  }
1320  /* Now, the condition for the point to
1321  * be inside
1322  * (ka + lb = p)
1323  * (k + l b.a = p.a)
1324  * (k b.a + l = p.b)
1325  * (k - (b.a)**2 k = p.a - (b.a)*p.b)
1326  * k = (p.a - (b.a)*(p.b)) / (1-(b.a)**2)
1327  */
1328  k = (ra - v12pt * rb) / (1-v12pt*v12pt);
1329  l = (rb - v12pt * ra) / (1-v12pt*v12pt);
1330  k /= v1len; l /= v2len;
1331  if(k+l > 1 || k < 0 || l < 0) {
1332  continue;
1333  }
1334  //we have a hit
1335  nintersections ++;
1336  if(tmp2 >= 0.0 && tmp2 < nearestdist){
1337  ihavehit = 1;
1338  nearest[0] = (float)hitpoint.x;
1339  nearest[1] = (float)hitpoint.y;
1340  nearest[2] = (float)hitpoint.z;
1341  normal[0] = (float)v3.x;
1342  normal[1] = (float)v3.y;
1343  normal[2] = (float)v3.z;
1344  nearestdist = tmp2;
1345  }
1346  //rayhit(((float)(tmp2)),
1347  //((float)(hitpoint.x)),
1348  //((float)(hitpoint.y)),
1349  //((float)(hitpoint.z)),
1350  // ((float)(v3.x)),
1351  //((float)(v3.y)),
1352  //((float)(v3.z)),
1353  //((float)-1),((float)-1), "polyrep");
1354  }
1355  } // if degenerate
1356  } // if raytrialgo
1357  } //for triangle
1358 
1359  return nintersections*ihavehit; //-ve if no hit but intersections of infinite ray for p1,
1360  // +ve if hit and intersections, 0 -nothing
1361 }
1362 int intersect_polyrep2(struct X3D_Node *node, float *p1, float *p2, Stack *intersection_stack){
1363  //this one returns a vector of points
1364  //please allocate intersection_stack before calling ie instersection_stack = newStack(struct intersection_info);
1365  //p1 - p2 is your plumbline or line, see also particalsystems for use
1366  //need a utility function like part of guts of render_ray_polyrep
1367  //everything in same coordinate system, no matrix multiplication in here
1368  //p1, p2 - 2 points forming ray, in direciton from p1 toward p2, of length p2-p1
1369  //return value:
1370  // count of intersections - can be used for inside test (odd - inside, even - outside)
1371  // nearest[3] - the intersection nearest p1
1372  // normal[3] - normal at nearest intersection
1373 
1374  //struct X3D_Virt *virt;
1375  struct X3D_Node *genericNodePtr;
1376  struct X3D_PolyRep *polyRep;
1377  int i, nintersections, ihavehit;
1378  int pt;
1379  float nearestdist, delta[3];
1380  float *point[3];
1381  struct point_XYZ v1, v2, v3;
1382  //struct point_XYZ ray;
1383  float pt1, pt2, pt3;
1384  struct point_XYZ hitpoint;
1385  float tmp1,tmp2;
1386  float v1len, v2len, v3len;
1387  float v12pt;
1388  struct point_XYZ t_r1,t_r2;
1389  //ttglobal tg;
1390 
1391  ihavehit = -1;
1392 
1393  /* is this structure still loading? */
1394  if (!node) return 0;
1395  //tg = gglobal();
1396  //VECCOPY(t_r1,tg->RenderFuncs.t_r1);
1397  //VECCOPY(t_r2,tg->RenderFuncs.t_r2);
1398 // get_current_ray(&t_r1, &t_r2);
1399  vecdif3f(delta,p2,p1);
1400  nearestdist = veclength3f(delta) + .000001f;
1401  nintersections = 0;
1402  t_r1.x = p1[0];
1403  t_r1.y = p1[1];
1404  t_r1.z = p1[2];
1405  t_r2.x = p2[0];
1406  t_r2.y = p2[1];
1407  t_r2.z = p2[2];
1408  //VECCOPY(t_r3,tg->RenderFuncs.t_r3);
1409 
1410  //ray.x = t_r2.x - t_r1.x;
1411  //ray.y = t_r2.y - t_r1.y;
1412  //ray.z = t_r2.z - t_r1.z;
1413 
1414  genericNodePtr = X3D_NODE(node);
1415  //virt = virtTable[genericNodePtr->_nodeType];
1416 
1417  /* is this structure still loading? */
1418  if (!(genericNodePtr->_intern)) {
1419  /* printf ("render_ray_polyrep - no internal structure, returning\n"); */
1420  return 0;
1421  }
1422 
1423  polyRep = genericNodePtr->_intern;
1424 
1425  /*
1426  printf("render_ray_polyrep %d '%s' (%d %d): %d\n",node,stringNodeType(genericNodePtr->_nodeType),
1427  genericNodePtr->_change, polyRep->_change, polyRep->ntri);
1428  */
1429 
1430 
1431 
1432  for(i=0; i<polyRep->ntri; i++) {
1433  for(pt = 0; pt<3; pt++) {
1434  int ind = polyRep->cindex[i*3+pt];
1435  point[pt] = (polyRep->actualCoord+3*ind);
1436  }
1437  if(raytrialgo == RAYTRIALGO_MULLER){
1438  //works for particlephysics > bounded physics
1439  float tscale, d2[3],delta[3];
1440  vecdif3f(delta,p2,p1);
1441  vecnormalize3f(d2,delta); //muller takes a D normalized direction vector
1442  if(triangle_intersection(point[0],point[1],point[2],p1,d2,&tscale)){
1443  //printf("muller-trumbore intersection tascale %f nearestdist %f\n",tscale,nearestdist);
1444  nintersections++;
1445 
1446  if(tscale > 0.0f && tscale < veclength3f(delta)){ //nearestdist){
1447  //closest so far
1448  float e1[3],e2[3],nn[3],pd[3],pi[3],normi[3];
1449  struct intersection_info iinfo;
1450  vecscale3f(pd,d2,tscale);
1451  vecadd3f(pi,p1,pd);
1452  //compute normal to triangle
1453  vecdif3f(e1,point[1],point[0]);
1454  vecdif3f(e2,point[2],point[0]);
1455  veccross3f(nn,e1,e2); //e2,e1 points inside, e1,e2 points outside
1456  vecnormalize3f(normi,nn);
1457  veccopy3f(iinfo.p,pi);
1458  veccopy3f(iinfo.normal,normi);
1459  stack_push(struct intersection_info,intersection_stack,iinfo);
1460  if(tscale < nearestdist) {
1461  //veccopy3f(nearest,pi);
1462  //veccopy3f(normal,normi);
1463  nearestdist = tscale;
1464  ihavehit = 1;
1465  }
1466  }
1467  }
1468  }else if(raytrialgo == RAYTRIALGO_DEFAULT){
1469  //doesn't work right for particle physics > bounded physics
1470  //x leaks on right side of IFS box, occassionally leaky left side
1471  /*
1472  printf ("have points (%f %f %f) (%f %f %f) (%f %f %f)\n",
1473  point[0][0],point[0][1],point[0][2],
1474  point[1][0],point[1][1],point[1][2],
1475  point[2][0],point[2][1],point[2][2]);
1476  */
1477 
1478  /* First we need to project our point to the surface */
1479  /* Poss. 1: */
1480  /* Solve s1xs2 dot ((1-r)r1 + r r2 - pt0) == 0 */
1481  /* I.e. calculate s1xs2 and ... */
1482  v1.x = point[1][0] - point[0][0];
1483  v1.y = point[1][1] - point[0][1];
1484  v1.z = point[1][2] - point[0][2];
1485  v2.x = point[2][0] - point[0][0];
1486  v2.y = point[2][1] - point[0][1];
1487  v2.z = point[2][2] - point[0][2];
1488  v1len = (float) sqrt(VECSQ(v1)); VECSCALE(v1, 1/v1len);
1489  v2len = (float) sqrt(VECSQ(v2)); VECSCALE(v2, 1/v2len);
1490  v12pt = (float) VECPT(v1,v2);
1491 
1492  /* this will get around a divide by zero further on JAS */
1493  if (fabs(v12pt-1.0) < 0.00001)
1494  continue;
1495 
1496  /* if we have a degenerate triangle, we can't compute a normal, so skip */
1497 
1498  if ((fabs(v1len) > 0.00001) && (fabs(v2len) > 0.00001)) {
1499 
1500  /* v3 is our normal to the surface */
1501  VECCP(v1,v2,v3);
1502  v3len = (float) sqrt(VECSQ(v3)); VECSCALE(v3, 1/v3len);
1503 
1504  pt1 = (float) VECPT(t_r1,v3);
1505  pt2 = (float) VECPT(t_r2,v3);
1506  pt3 = (float) (v3.x * point[0][0] + v3.y * point[0][1] + v3.z * point[0][2]);
1507  /* Now we have (1-r)pt1 + r pt2 - pt3 = 0
1508  * r * (pt1 - pt2) = pt1 - pt3
1509  */
1510  tmp1 = pt1-pt2;
1511  if(!APPROX(tmp1,0)) {
1512  float ra, rb;
1513  float k,l;
1514  struct point_XYZ p0h;
1515 
1516  tmp2 = (float) ((pt1-pt3) / (pt1-pt2));
1517  hitpoint.x = MRATX(tmp2);
1518  hitpoint.y = MRATY(tmp2);
1519  hitpoint.z = MRATZ(tmp2);
1520  /* Now we want to see if we are in the triangle */
1521  /* Projections to the two triangle sides */
1522  p0h.x = hitpoint.x - point[0][0];
1523  p0h.y = hitpoint.y - point[0][1];
1524  p0h.z = hitpoint.z - point[0][2];
1525  ra = (float) VECPT(v1, p0h);
1526  if(ra < 0.0f) {
1527  continue;
1528  }
1529  rb = (float) VECPT(v2, p0h);
1530  if(rb < 0.0f) {
1531  continue;
1532  }
1533  /* Now, the condition for the point to
1534  * be inside
1535  * (ka + lb = p)
1536  * (k + l b.a = p.a)
1537  * (k b.a + l = p.b)
1538  * (k - (b.a)**2 k = p.a - (b.a)*p.b)
1539  * k = (p.a - (b.a)*(p.b)) / (1-(b.a)**2)
1540  */
1541  k = (ra - v12pt * rb) / (1-v12pt*v12pt);
1542  l = (rb - v12pt * ra) / (1-v12pt*v12pt);
1543  k /= v1len; l /= v2len;
1544  if(k+l > 1 || k < 0 || l < 0) {
1545  continue;
1546  }
1547  //we have a hit
1548  nintersections ++;
1549  if(tmp2 >= 0.0 && tmp2 < nearestdist){
1550  ihavehit = 1;
1551  //nearest[0] = (float)hitpoint.x;
1552  //nearest[1] = (float)hitpoint.y;
1553  //nearest[2] = (float)hitpoint.z;
1554  //normal[0] = (float)v3.x;
1555  //normal[1] = (float)v3.y;
1556  //normal[2] = (float)v3.z;
1557  nearestdist = tmp2;
1558  }
1559  //rayhit(((float)(tmp2)),
1560  //((float)(hitpoint.x)),
1561  //((float)(hitpoint.y)),
1562  //((float)(hitpoint.z)),
1563  // ((float)(v3.x)),
1564  //((float)(v3.y)),
1565  //((float)(v3.z)),
1566  //((float)-1),((float)-1), "polyrep");
1567  }
1568  } // if degenerate
1569  } // if raytrialgo
1570  } //for triangle
1571 
1572  return nintersections*ihavehit; //-ve if no hit but intersections of infinite ray for p1,
1573  // +ve if hit and intersections, 0 -nothing
1574 }
1575 
1576 int getPolyrepTriangleCount(struct X3D_Node *node){
1577  int iret;
1578  iret = 0;
1579  if(node->_intern){
1580  struct X3D_PolyRep *polyrep = (struct X3D_PolyRep *)node->_intern;
1581  iret = polyrep->ntri;
1582  }
1583  return iret;
1584 }
1585 int getPolyrepTriangleByIndex(struct X3D_Node *node, int index, float *v1, float *v2, float *v3){
1586  int iret;
1587  iret = 0;
1588  if(node->_intern){
1589  struct X3D_PolyRep *polyrep = (struct X3D_PolyRep *)node->_intern;
1590  veccopy3f(v1,&polyrep->actualCoord[(index*3 + 0)*3]);
1591  veccopy3f(v2,&polyrep->actualCoord[(index*3 + 1)*3]);
1592  veccopy3f(v3,&polyrep->actualCoord[(index*3 + 2)*3]);
1593  }
1594  return iret;
1595 
1596 }
1597 
1598 /* make the internal polyrep structure - this will contain the actual RUNTIME parameters for OpenGL */
1599 void compile_polyrep(void *innode, void *coord, void *fogCoord, void *color, void *normal, struct X3D_TextureCoordinate *texCoord) {
1600  struct X3D_Virt *virt;
1601  struct X3D_Node *node;
1602  struct X3D_PolyRep *polyrep;
1603 
1604  //printf ("compile_polyrep, innode %p coord %p color %p normal %p texCoord %p\n",innode,coord,color,normal,texCoord);
1605 
1606  node = X3D_NODE(innode);
1607  virt = virtTable[node->_nodeType];
1608 
1609  /* first time through; make the intern structure for this polyrep node */
1610  if(!node->_intern) {
1611 
1612  int i;
1613 
1614  node->_intern = MALLOC(struct X3D_PolyRep *, sizeof(struct X3D_PolyRep));
1615  memset(node->_intern,0,sizeof(struct X3D_PolyRep));
1616  polyrep = node->_intern;
1617  polyrep->ntri = -1;
1618  //polyrep->cindex = 0; polyrep->actualCoord = 0; polyrep->colindex = 0; polyrep->color = 0;
1619  //polyrep->norindex = 0; polyrep->normal = 0; polyrep->flat_normal = 0; polyrep->GeneratedTexCoords = 0;
1620  //polyrep->tri_indices = 0; polyrep->wire_indices = 0; polyrep->actualFog = 0;
1621  //polyrep->tcindex = 0;
1622  //polyrep->tcoordtype = 0;
1623  polyrep->streamed = FALSE;
1624  //polyrep->last_index_type = 0; polyrep->last_normal_type = 0;
1625 
1626 
1627  /* for Collision, default texture generation */
1628  polyrep->minVals[0] = 999999.9f;
1629  polyrep->minVals[1] = 999999.9f;
1630  polyrep->minVals[2] = 999999.9f;
1631  polyrep->maxVals[0] = -999999.9f;
1632  polyrep->maxVals[1] = -999999.9f;
1633  polyrep->maxVals[2] = -999999.9f;
1634 
1635  for (i=0; i<VBO_COUNT; i++)
1636  polyrep->VBO_buffers[i] = 0;
1637 
1638  /* printf ("generating buffers for node %p, type %s\n",p,stringNodeType(p->_nodeType)); */
1639  glGenBuffers(1,&polyrep->VBO_buffers[VERTEX_VBO]);
1640  glGenBuffers(1,&polyrep->VBO_buffers[INDEX_VBO]);
1641 
1642  /* printf ("they are %u %u %u %u\n",polyrep->VBO_buffers[0],polyrep->VBO_buffers[1],polyrep->VBO_buffers[2],polyrep->VBO_buffers[3]); */
1643 
1644  }
1645 
1646  polyrep = node->_intern;
1647 
1648  /* Android, for instance, needs the VBO_buffers re-created. Check to see if this is the case here */
1649  if (polyrep->VBO_buffers[VERTEX_VBO] == 0) {
1650  //ConsoleMessage ("re-creating VERTEX VBOs");
1651  glGenBuffers(1,&polyrep->VBO_buffers[VERTEX_VBO]);
1652  glGenBuffers(1,&polyrep->VBO_buffers[INDEX_VBO]);
1653  }
1654 
1655  /* if multithreading, tell the rendering loop that we are regenning this one */
1656  /* if singlethreading, this'll be set to TRUE before it is tested */
1657  polyrep->streamed = FALSE;
1658 
1659  FREE_IF_NZ(polyrep->cindex);
1660  FREE_IF_NZ(polyrep->actualCoord);
1661  FREE_IF_NZ(polyrep->GeneratedTexCoords[0]);
1662  FREE_IF_NZ(polyrep->colindex);
1663  FREE_IF_NZ(polyrep->color);
1664  FREE_IF_NZ(polyrep->norindex);
1665  FREE_IF_NZ(polyrep->normal);
1666  FREE_IF_NZ(polyrep->flat_normal);
1667  FREE_IF_NZ(polyrep->tcindex);
1668 
1669 
1670  /* make the node by calling the correct method */
1671  virt->mkpolyrep(node);
1672 
1673  /* now, put the generic internal structure into OpenGL arrays for faster rendering */
1674  /* if there were errors, then rep->ntri should be 0 */
1675  if (polyrep->ntri != 0) {
1676  //float *fogCoord = NULL;
1677  stream_polyrep(node, coord, fogCoord, color, normal, texCoord);
1678  /* and, tell the rendering process that this shape is now compiled */
1679  }
1680  //else wait for set_coordIndex to be converted to coordIndex
1681  polyrep->irep_change = node->_change;
1682 
1683 }
1684 
1685 void delete_polyrep(struct X3D_Node *node){
1686  // see if node has _intern, if so it's live scenery
1687  // delete opengl buffers used by polyrep
1688  // delete internal malloced items in polyrep
1689  // delete polyrep
1690  // null node's _intern field
1691  struct X3D_PolyRep *pr;
1692  if(!node) return;
1693  pr = node->_intern;
1694  if(pr){
1695  // ? apr 2015 I think the node->_intern = polyrep will only be populated
1696  // in the case of live scenery, not in ProtoDeclares, so if we are in here,
1697  // we should have live scenery, and that means gl buffers were assigned
1698  glDeleteBuffers(VBO_COUNT,pr->VBO_buffers);
1699 
1700  /* indicies for arrays. OpenGL ES 2.0 - unsigned short for the DrawArrays call */
1701  FREE_IF_NZ(pr->cindex); /* triples (per triangle) */
1702  FREE_IF_NZ(pr->colindex); /* triples (per triangle) */
1703  FREE_IF_NZ(pr->norindex);
1704  FREE_IF_NZ(pr->tcindex); /* triples or null */
1705  FREE_IF_NZ(pr->tri_indices);
1706  FREE_IF_NZ(pr->wire_indices);
1707  FREE_IF_NZ(pr->actualCoord); /* triples (per point) */
1708  FREE_IF_NZ(pr->actualFog); /* float (per point) */
1709  FREE_IF_NZ(pr->color); /* triples or null */
1710  FREE_IF_NZ(pr->normal); /* triples or null */
1711  FREE_IF_NZ(pr->flat_normal);
1712  FREE_IF_NZ(pr->GeneratedTexCoords[0]); /* triples (per triangle) of texture coords if there is no texCoord node */
1713  FREE_IF_NZ(pr);
1714  node->_intern = NULL;
1715  }
1716 };
Definition: Vector.h:36