FreeWRL/FreeX3D  3.0.0
Frustum.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 "../main/headers.h"
39 #include "../scenegraph/quaternion.h"
40 #include "../scenegraph/Viewer.h"
41 #include "Frustum.h"
42 #include "../opengl/OpenGL_Utils.h"
43 #include "../scenegraph/LinearAlgebra.h"
44 
45 
46 #include "Textures.h"
47 #include <float.h>
48 
49 //#define FRUSTUMVERBOSE
50 
51 static void quaternion_multi_rotation(struct point_XYZ *ret, const Quaternion *quat, const struct point_XYZ * v, int count);
52 static void add_translation (struct point_XYZ *arr, float x, float y, float z, int count);
53 static void multiply_in_scale(struct point_XYZ *arr, float x, float y, float z, int count);
54 
55 
56 
57 /*********************************************************************
58  * OLD - NOW USE Occlusion tests
59  * Frustum calculations. Definitive work (at least IMHO) is thanks to
60  * Steven Baker - look at http://sjbaker.org/steve/omniv/frustcull.html/
61  *
62  * Thanks Steve!
63  *
64  */
65 
66 
67 #undef OCCLUSIONVERBOSE
68 
69 #ifdef OCCLUSION
70 
71  /* if we have a visible Shape node, how long should we wait until we try to determine
72  if it is still visible? */
73  #define OCCWAIT 20
74 
75  /* we have a visibility sensor, we want to really see when it becomes invis. */
76  #define OCCCHECKNEXTLOOP 1
77 
78  /* we are invisible - don't let it go too long before we try to see visibility */
79  #define OCCCHECKSOON 4
80 
81  /* how many samples of a Shape are needed before it becomes visible? If it is too
82  small, don't worry about displaying it If this number is too large, "flashing"
83  will occur, as the shape is dropped, while still displaying (the number) of pixels
84  on the screen */
85  #define OCCSHAPESAMPLESIZE 1
86 #endif //OCCLUSION
87 
88 typedef struct pFrustum{
89  /* Occlusion VisibilitySensor code */
90  GLuint *OccQueries;// = NULL;
91 
92  /* newer occluder code */
93  GLuint potentialOccluderCount;// = 0;
94  void ** occluderNodePointer;// = NULL;
95 
96  /* older occluder code */
97  #ifdef OCCLUSION
98  int maxOccludersFound;// = 0;
99  int QueryCount;// = 0;
100  int OccInitialized;// = FALSE;
101  #endif
102 
103  GLuint OccQuerySize;//=0;
104 
105  // #ifdef OCCLUSIONVERBOSE
106  // GLint queryCounterBits;
107  // #endif
108 
109  GLuint OccResultsAvailable;// = FALSE;
110 
111 }* ppFrustum;
112 void *Frustum_constructor(){
113  void *v = MALLOCV(sizeof(struct pFrustum));
114  memset(v,0,sizeof(struct pFrustum));
115  return v;
116 }
117 void Frustum_init(struct tFrustum *t){
118  //public
119  t->OccFailed = FALSE;
120  //private
121  t->prv = Frustum_constructor();
122  {
123  ppFrustum p = (ppFrustum)t->prv;
124  /* Occlusion VisibilitySensor code */
125  p->OccQueries = NULL;
126 
127  /* newer occluder code */
128  p->potentialOccluderCount = 0;
129  p->occluderNodePointer = NULL;
130 
131  /* older occluder code */
132  #ifdef OCCLUSION
133  p->maxOccludersFound = 0;
134  p->QueryCount = 0;
135  p->OccInitialized = FALSE;
136  #endif
137 
138  p->OccQuerySize=0;
139 
140  p->OccResultsAvailable = FALSE;
141  }
142 }
143 
144 void beginOcclusionQuery(struct X3D_VisibilitySensor* node, int render_geometry)
145 {
146  ppFrustum p = (ppFrustum)gglobal()->Frustum.prv;
147  if (render_geometry) {
148  if (p->potentialOccluderCount < p->OccQuerySize) {
149  TRACE_MSG ("beginOcclusionQuery, potoc %d occQ %d\n",p->potentialOccluderCount, p->OccQuerySize);
150  if (node->__occludeCheckCount < 0) {
151  TRACE_MSG ("beginOcclusionQuery, query %u, node %s\n",p->potentialOccluderCount, stringNodeType(node->_nodeType));
152 #if !defined(GL_ES_VERSION_2_0)
153 //void glBeginQuery(GLenum, GLuint);
154 
155  FW_GL_BEGIN_QUERY(GL_SAMPLES_PASSED, p->OccQueries[p->potentialOccluderCount]);
156 #endif
157  p->occluderNodePointer[p->potentialOccluderCount] = (void *)node;
158  }
159  }
160  }
161 }
162 
163 void endOcclusionQuery(struct X3D_VisibilitySensor* node, int render_geometry)
164 {
165  ppFrustum p = (ppFrustum)gglobal()->Frustum.prv;
166  if (render_geometry) {
167  if (p->potentialOccluderCount < p->OccQuerySize) {
168  if (node->__occludeCheckCount < 0) {
169  TRACE_MSG ("glEndQuery node %p\n",node);
170 #if !defined( GL_ES_VERSION_2_0 )
171  FW_GL_END_QUERY(GL_SAMPLES_PASSED);
172 #endif
173  p->potentialOccluderCount++;
174  }
175  }
176  }
177 }
178 
179 #define PROP_EXTENT_CHECK \
180  if (maxx > geomParent->EXTENT_MAX_X) {geomParent->EXTENT_MAX_X = maxx; touched = TRUE;} \
181  if (minx < geomParent->EXTENT_MIN_X) {geomParent->EXTENT_MIN_X = minx; touched = TRUE;} \
182  if (maxy > geomParent->EXTENT_MAX_Y) {geomParent->EXTENT_MAX_Y = maxy; touched = TRUE;} \
183  if (miny < geomParent->EXTENT_MIN_Y) {geomParent->EXTENT_MIN_Y = miny; touched = TRUE;} \
184  if (maxz > geomParent->EXTENT_MAX_Z) {geomParent->EXTENT_MAX_Z = maxz; touched = TRUE;} \
185  if (minz < geomParent->EXTENT_MIN_Z) {geomParent->EXTENT_MIN_Z = minz; touched = TRUE;}
186 
187 #define FRUSTUM_TRANS(myNodeType) \
188  if (me->_nodeType == NODE_##myNodeType) { \
189  /* have we actually done a propagateExtent on this one? Because we look at ALL points in a boundingBox, \
190  because of rotations, we HAVE to ensure that the default values are not there, otherwise we will \
191  take the "inside out" boundingBox as being correct! */ \
192  \
193  /* has this node actually been extented away from the default? */ \
194  \
195  if (!APPROX(me->EXTENT_MAX_X,-10000.0)) { \
196  struct X3D_##myNodeType *node; \
197  Quaternion rq; \
198  struct point_XYZ inxyz[8]; struct point_XYZ outxyz[8]; \
199  node = (struct X3D_##myNodeType *)me; \
200  \
201  /* make up a "cube" with vertexes being our bounding box */ \
202  BBV(0,MAX_X,MAX_Y,MAX_Z); \
203  BBV(1,MAX_X,MAX_Y,MIN_Z); \
204  BBV(2,MAX_X,MIN_Y,MAX_Z); \
205  BBV(3,MAX_X,MIN_Y,MIN_Z); \
206  BBV(4,MIN_X,MAX_Y,MAX_Z); \
207  BBV(5,MIN_X,MAX_Y,MIN_Z); \
208  BBV(6,MIN_X,MIN_Y,MAX_Z); \
209  BBV(7,MIN_X,MIN_Y,MIN_Z); \
210  \
211  /* 1: REVERSE CENTER */ \
212  if (node->__do_center) { \
213  add_translation(inxyz,-node->center.c[0],-node->center.c[1],-node->center.c[2],8); \
214  } \
215  \
216  /* 2: REVERSE SCALE ORIENTATION */ \
217  if (node->__do_scaleO) { \
218  vrmlrot_to_quaternion(&rq,node->scaleOrientation.c[0], node->scaleOrientation.c[1], node->scaleOrientation.c[2], -node->scaleOrientation.c[3]); \
219  quaternion_multi_rotation(outxyz,&rq,inxyz,8); \
220  \
221  /* copy these points back out */ \
222  memcpy (inxyz,outxyz,8*sizeof(struct point_XYZ)); \
223  } \
224  \
225  /* 3: SCALE */ \
226  if (node->__do_scale) { \
227  /* FW_GL_SCALE_F(node->scale.c[0],node->scale.c[1],node->scale.c[2]); */ \
228  multiply_in_scale(inxyz,node->scale.c[0],node->scale.c[1],node->scale.c[2],8); \
229  } \
230  \
231  /* 4: SCALEORIENTATION */ \
232  if (node->__do_scaleO) { \
233  vrmlrot_to_quaternion(&rq,node->scaleOrientation.c[0], node->scaleOrientation.c[1], node->scaleOrientation.c[2], -node->scaleOrientation.c[3]); \
234  quaternion_multi_rotation(outxyz,&rq,inxyz,8); \
235  \
236  /* copy these points back out */ \
237  memcpy (inxyz,outxyz,8*sizeof(struct point_XYZ)); \
238  } \
239  \
240  /* 5: ROTATION */ \
241  if (node->__do_rotation) { \
242  /* FW_GL_ROTATE_F(my_rotation, node->rotation.c[0],node->rotation.c[1],node->rotation.c[2]); */ \
243  vrmlrot_to_quaternion(&rq,node->rotation.c[0], node->rotation.c[1], node->rotation.c[2], node->rotation.c[3]); \
244  quaternion_multi_rotation(outxyz,&rq,inxyz,8); \
245  \
246  /* copy these points back out */ \
247  memcpy (inxyz,outxyz,8*sizeof(struct point_XYZ)); \
248  } \
249  \
250  /* 6: CENTER */ \
251  if (node->__do_center) { \
252  /* FW_GL_TRANSLATE_F(node->center.c[0],node->center.c[1],node->center.c[2]); */ \
253  add_translation(inxyz,node->center.c[0],node->center.c[1],node->center.c[2],8); \
254  } \
255 \
256  /* 7: TRANSLATION */ \
257  if (node->__do_trans) { \
258  /* FW_GL_TRANSLATE_F(node->translation.c[0],node->translation.c[1],node->translation.c[2]); */ \
259  add_translation(inxyz,node->translation.c[0],node->translation.c[1],node->translation.c[2],8); \
260  } \
261  \
262  \
263  /* work changes into extent */ \
264  /* because we have materially moved this Transform, the WHOLE Bounding Box has moved, too, \
265  thus we do not bother to test against OLD max/min values */ \
266  maxx = -FLT_MAX; maxy = -FLT_MAX; maxz = -FLT_MAX; \
267  minx = FLT_MAX; miny = FLT_MAX; minz = FLT_MAX; \
268  for (i=0; i<8; i++) { \
269  if (inxyz[i].x > maxx) maxx = (float)inxyz[i].x; \
270  if (inxyz[i].y > maxy) maxy = (float)inxyz[i].y; \
271  if (inxyz[i].z > maxz) maxz = (float)inxyz[i].z; \
272  if (inxyz[i].x < minx) minx = (float)inxyz[i].x; \
273  if (inxyz[i].y < miny) miny = (float)inxyz[i].y; \
274  if (inxyz[i].z < minz) minz = (float)inxyz[i].z; \
275  } \
276  } \
277  }
278 
279 
280 #define FRUSTUM_GEOLOCATION \
281  if (me->_nodeType == NODE_GeoLocation) { \
282  /* have we actually done a propagateExtent on this one? Because we look at ALL points in a boundingBox, \
283  because of rotations, we HAVE to ensure that the default values are not there, otherwise we will \
284  take the "inside out" boundingBox as being correct! */ \
285  \
286  /* has this node actually been extented away from the default? */ \
287  \
288  if (!APPROX(me->EXTENT_MAX_X,-10000.0)) { \
289  struct X3D_GeoLocation *node; \
290  Quaternion rq; \
291  struct point_XYZ inxyz[8]; struct point_XYZ outxyz[8]; \
292  node = (struct X3D_GeoLocation *)me; \
293  \
294  /* make up a "cube" with vertexes being our bounding box */ \
295  BBV(0,MAX_X,MAX_Y,MAX_Z); \
296  BBV(1,MAX_X,MAX_Y,MIN_Z); \
297  BBV(2,MAX_X,MIN_Y,MAX_Z); \
298  BBV(3,MAX_X,MIN_Y,MIN_Z); \
299  BBV(4,MIN_X,MAX_Y,MAX_Z); \
300  BBV(5,MIN_X,MAX_Y,MIN_Z); \
301  BBV(6,MIN_X,MIN_Y,MAX_Z); \
302  BBV(7,MIN_X,MIN_Y,MIN_Z); \
303  \
304 \
305  /* 5: ROTATION */ \
306  vrmlrot_to_quaternion(&rq,node->__localOrient.c[0], node->__localOrient.c[1], node->__localOrient.c[2], node->__localOrient.c[3]); \
307  quaternion_multi_rotation(outxyz,&rq,inxyz,8); \
308  \
309  /* copy these points back out */ \
310  memcpy (inxyz,outxyz,8*sizeof(struct point_XYZ)); \
311  \
312  /* 7: TRANSLATION */ \
313  /* FW_GL_TRANSLATE_F(node->translation.c[0],node->translation.c[1],node->translation.c[2]); */ \
314  /*printf ("doing translation %f %f %f\n", node->__movedCoords.c[0],node->__movedCoords.c[1],node->__movedCoords.c[2]); */ \
315  add_translation(inxyz,(float) node->__movedCoords.c[0],(float) node->__movedCoords.c[1],(float) node->__movedCoords.c[2],8); \
316  \
317  \
318  \
319  /* work changes into extent */ \
320  /* because we have materially moved this Transform, the WHOLE Bounding Box has moved, too, \
321  thus we do not bother to test against OLD max/min values */ \
322  maxx = -FLT_MAX; maxy = -FLT_MAX; maxz = -FLT_MAX; \
323  minx = FLT_MAX; miny = FLT_MAX; minz = FLT_MAX; \
324  for (i=0; i<8; i++) { \
325  if (inxyz[i].x > maxx) maxx = (float) inxyz[i].x; \
326  if (inxyz[i].y > maxy) maxy = (float) inxyz[i].y; \
327  if (inxyz[i].z > maxz) maxz = (float) inxyz[i].z; \
328  if (inxyz[i].x < minx) minx = (float) inxyz[i].x; \
329  if (inxyz[i].y < miny) miny = (float) inxyz[i].y; \
330  if (inxyz[i].z < minz) minz = (float) inxyz[i].z; \
331  } \
332  } \
333  }
334 
335 #define FRUSTUM_GEOTRANS \
336  if (me->_nodeType == NODE_GeoTransform) { \
337  /* have we actually done a propagateExtent on this one? Because we look at ALL points in a boundingBox, \
338  because of rotations, we HAVE to ensure that the default values are not there, otherwise we will \
339  take the "inside out" boundingBox as being correct! */ \
340  \
341  /* has this node actually been extented away from the default? */ \
342  \
343  if (!APPROX(me->EXTENT_MAX_X,-10000.0)) { \
344  struct X3D_GeoTransform *node; \
345  Quaternion rq; \
346  struct point_XYZ inxyz[8]; struct point_XYZ outxyz[8]; \
347  node = (struct X3D_GeoTransform *)me; \
348  \
349  /* make up a "cube" with vertexes being our bounding box */ \
350  BBV(0,MAX_X,MAX_Y,MAX_Z); \
351  BBV(1,MAX_X,MAX_Y,MIN_Z); \
352  BBV(2,MAX_X,MIN_Y,MAX_Z); \
353  BBV(3,MAX_X,MIN_Y,MIN_Z); \
354  BBV(4,MIN_X,MAX_Y,MAX_Z); \
355  BBV(5,MIN_X,MAX_Y,MIN_Z); \
356  BBV(6,MIN_X,MIN_Y,MAX_Z); \
357  BBV(7,MIN_X,MIN_Y,MIN_Z); \
358  \
359  /* 1: REVERSE CENTER */ \
360  if (node->__do_center) { \
361  add_translation(inxyz,(float) (-node->geoCenter.c[0]), (float) (-node->geoCenter.c[1]),(float)(-node->geoCenter.c[2]),8); \
362  } \
363  \
364  /* 2: REVERSE SCALE ORIENTATION */ \
365  if (node->__do_scaleO) { \
366  vrmlrot_to_quaternion(&rq,node->scaleOrientation.c[0], node->scaleOrientation.c[1], node->scaleOrientation.c[2], -node->scaleOrientation.c[3]); \
367  quaternion_multi_rotation(outxyz,&rq,inxyz,8); \
368  memcpy (inxyz,outxyz,8*sizeof(struct point_XYZ)); \
369  } \
370  \
371  /* 3: SCALE */ \
372  if (node->__do_scale) { \
373  multiply_in_scale(inxyz,node->scale.c[0],node->scale.c[1],node->scale.c[2],8); \
374  } \
375  \
376  /* 4: SCALEORIENTATION */ \
377  if (node->__do_scaleO) { \
378  vrmlrot_to_quaternion(&rq,node->scaleOrientation.c[0], node->scaleOrientation.c[1], node->scaleOrientation.c[2], -node->scaleOrientation.c[3]); \
379  quaternion_multi_rotation(outxyz,&rq,inxyz,8); \
380  memcpy (inxyz,outxyz,8*sizeof(struct point_XYZ)); \
381  } \
382  \
383  /* 5: ROTATION */ \
384  if (node->__do_rotation) { \
385  vrmlrot_to_quaternion(&rq,node->rotation.c[0], node->rotation.c[1], node->rotation.c[2], node->rotation.c[3]); \
386  quaternion_multi_rotation(outxyz,&rq,inxyz,8); \
387  memcpy (inxyz,outxyz,8*sizeof(struct point_XYZ)); \
388  } \
389  \
390  /* 6: CENTER */ \
391  if (node->__do_center) { \
392  add_translation(inxyz,(float)node->geoCenter.c[0],(float)node->geoCenter.c[1],(float)node->geoCenter.c[2],8); \
393  } \
394  add_translation (inxyz,(float) X3D_GEOTRANSFORM(node)->__movedCoords.c[0], (float) X3D_GEOTRANSFORM(node)->__movedCoords.c[1], (float) X3D_GEOTRANSFORM(node)->__movedCoords.c[2],8); \
395 \
396  vrmlrot_to_quaternion(&rq,X3D_GEOTRANSFORM(node)->__localOrient.c[0], X3D_GEOTRANSFORM(node)->__localOrient.c[1], X3D_GEOTRANSFORM(node)->__localOrient.c[2], X3D_GEOTRANSFORM(node)->__localOrient.c[3]); \
397  quaternion_multi_rotation(outxyz,&rq,inxyz,8); \
398  memcpy (inxyz,outxyz,8*sizeof(struct point_XYZ)); \
399  /* 7: TRANSLATION */ \
400  if (node->__do_trans) { \
401  add_translation(inxyz,node->translation.c[0],node->translation.c[1],node->translation.c[2],8); \
402  } \
403  \
404  \
405  /* work changes into extent */ \
406  /* because we have materially moved this Transform, the WHOLE Bounding Box has moved, too, \
407  thus we do not bother to test against OLD max/min values */ \
408  maxx = -FLT_MAX; maxy = -FLT_MAX; maxz = -FLT_MAX; \
409  minx = FLT_MAX; miny = FLT_MAX; minz = FLT_MAX; \
410  for (i=0; i<8; i++) { \
411  if (inxyz[i].x > maxx) maxx = (float) inxyz[i].x; \
412  if (inxyz[i].y > maxy) maxy = (float) inxyz[i].y; \
413  if (inxyz[i].z > maxz) maxz = (float) inxyz[i].z; \
414  if (inxyz[i].x < minx) minx = (float) inxyz[i].x; \
415  if (inxyz[i].y < miny) miny = (float) inxyz[i].y; \
416  if (inxyz[i].z < minz) minz = (float) inxyz[i].z; \
417  } \
418  } \
419  }
420 
421 
422 
423 
424 /* does this current node actually fit in the Switch rendering scheme? */
425 int is_Switchchild_inrange(struct X3D_Switch *node, struct X3D_Node *me) {
426  int wc = node->whichChoice;
427 
428  /* is this VRML, or X3D?? */
429  if (node->__isX3D == 0) {
430  if(wc >= 0 && wc < ((node->choice).n)) {
431  void *p = ((node->choice).p[wc]);
432  return (X3D_NODE(p)==me);
433  }
434  } else {
435  if(wc >= 0 && wc < ((node->children).n)) {
436  void *p = ((node->children).p[wc]);
437  return (X3D_NODE(p)==me);
438  }
439  }
440  return FALSE;
441 }
442 
443 
444 /* does this current node actually display, according to the CADLayer scheme? */
445 int is_CADLayerchild_inrange(struct X3D_CADLayer *node, struct X3D_Node *me) {
446  int i;
447  for (i=0; i<node->children.n; i++) {
448 
449  /* if we have more children than we have indexes into visible field, just return TRUE */
450  if ((i >= node->visible.n) && (node->children.p[i] == me)) return TRUE;
451 
452  /* if not, if it is in the visible field, return true */
453  else if ((node->visible.p[i]) && (node->children.p[i] == me)) return TRUE;
454  }
455  /* not visible, so return false */
456  return FALSE;
457 }
458 
459 /* does this current node actually fit in the GeoLOD rendering scheme? */
460 int is_GeoLODchild_inrange (struct X3D_GeoLOD* gpnode, struct X3D_Node *me) {
461  /* is this node part of the active path for rendering? */
462  int x,y;
463  y = FALSE;
464 
465  for (x=0; x<gpnode->rootNode.n; x++) {
466  /* printf ("comparing %u:%u %d of %d, types me %s rootNodeField: %s\n",
467  me, X3D_NODE(gpnode->rootNode.p[x]),
468  x, gpnode->rootNode.n,
469  stringNodeType (me->_nodeType),
470  stringNodeType( X3D_NODE(gpnode->rootNode.p[x])->_nodeType)
471  );
472  */
473 
474  if (me == X3D_NODE(gpnode->rootNode.p[x])) {
475  y=TRUE;
476  break;
477  }
478  }
479 
480 /*
481  if (y) printf ("GeoLOD, found child in rootNode "); else printf ("GeoLOD, child NOT part of ROOT ");
482  if (X3D_GEOLOD(geomParent)->__inRange) printf ("INRANGE "); else printf ("NOT inrange ");
483 */
484  /* is this one actually being rendered? */
485  return (y ^ gpnode->__inRange);
486 }
487 
488 
489 /* take the measurements of a geometry (eg, box), and save it. Note
490  * that what is given is a Shape, the values get pushed up to the
491  * Geometries grouping node parent. */
492 
493 
494 /* this is used for collision in transformChildren - don't bother going through
495  children of a transform if there is nothing close... */
496 
497 void setExtent(float maxx, float minx, float maxy, float miny, float maxz, float minz, struct X3D_Node *me) {
498  int c,d;
499  struct X3D_Node *shapeParent;
500  struct X3D_Node *geomParent;
501  int touched;
502 
503  UNUSED(touched); //compiler warning mitigation
504 
505  #ifdef FRUSTUMVERBOSE
506  printf ("setExtent maxx %f minx %f maxy %f miny %f maxz %f minz %f me %p nt %s\n",
507  maxx, minx, maxy, miny, maxz, minz, me, stringNodeType(me->_nodeType));
508  #endif
509 
510  /* record this for ME for sorting purposes for sorting children fields */
511  me->EXTENT_MAX_X = maxx; me->EXTENT_MIN_X = minx;
512  me->EXTENT_MAX_Y = maxy; me->EXTENT_MIN_Y = miny;
513  me->EXTENT_MAX_Z = maxz; me->EXTENT_MIN_Z = minz;
514 
515  if (me->_parentVector == NULL) {
516  #ifdef FRUSTUMVERBOSE
517  printf ("setExtent, parentVector NULL for node %p type %s\n",
518  me,stringNodeType(me->_nodeType));
519  #endif
520  return;
521  }
522 
523  for (c=0; c<vectorSize(me->_parentVector); c++) {
524  shapeParent = vector_get(struct X3D_Node *, me->_parentVector,c);
525 
526  /* record this for ME for sorting purposes for sorting children fields */
527  shapeParent->EXTENT_MAX_X = maxx; shapeParent->EXTENT_MIN_X = minx;
528  shapeParent->EXTENT_MAX_Y = maxy; shapeParent->EXTENT_MIN_Y = miny;
529  shapeParent->EXTENT_MAX_Z = maxz; shapeParent->EXTENT_MIN_Z = minz;
530 
531  #ifdef FRUSTUMVERBOSE
532  if (shapeParent == NULL)
533  printf ("parent %u of %u is %p, is null\n",c,vectorSize(me->_parentVector),shapeParent);
534  else
535  printf ("parent %u of %u is %p, type %s\n",c,vectorSize(me->_parentVector),shapeParent,stringNodeType(shapeParent->_nodeType));
536  #endif
537 
538  for (d=0; d<vectorSize(shapeParent->_parentVector); d++) {
539  geomParent = vector_get(struct X3D_Node *, shapeParent->_parentVector,d);
540 
541  #ifdef FRUSTUMVERBOSE
542  printf ("setExtent in loop, parent %u of shape %s is %s\n",c,stringNodeType(shapeParent->_nodeType),
543  stringNodeType(geomParent->_nodeType));
544 
545  /* is there a problem with this geomParent? */
546  if (!checkNode(geomParent, __FILE__, __LINE__)) printf ("problem here with checkNode\n");
547  #endif
548 
549 
550  /* note, maxz is positive, minz is negative, distance should be negative, so we take a negative distance,
551  and subtract the "positive" z value to get the closest point, then take the negative distance,
552  and subtract the "negative" z value to get the far distance */
553 
554  PROP_EXTENT_CHECK;
555 
556  #ifdef FRUSTUMVERBOSE
557  printf ("setExtent - now I am %p (%s) has extent maxx %f minx %f maxy %f miny %f maxz %f minz %f\n",
558  me, stringNodeType(me->_nodeType),
559  me->EXTENT_MAX_X ,
560  me->EXTENT_MIN_X ,
561  me->EXTENT_MAX_Y ,
562  me->EXTENT_MIN_Y ,
563  me->EXTENT_MAX_Z ,
564  me->EXTENT_MIN_Z);
565  printf ("setExtent - now parent %p (%s) has extent maxx %f minx %f maxy %f miny %f maxz %f minz %f\n",
566  geomParent, stringNodeType(geomParent->_nodeType),
567  geomParent->EXTENT_MAX_X ,
568  geomParent->EXTENT_MIN_X ,
569  geomParent->EXTENT_MAX_Y ,
570  geomParent->EXTENT_MIN_Y ,
571  geomParent->EXTENT_MAX_Z ,
572  geomParent->EXTENT_MIN_Z);
573  #endif
574 
575  }
576  }
577 }
578 
579 static void quaternion_multi_rotation(struct point_XYZ *ret, const Quaternion *quat, const struct point_XYZ * v, int count){
580  int i;
581  for (i=0; i<count; i++) {
582  quaternion_rotation(ret, quat, v);
583  ret++; v++;
584  }
585 }
586 
587 
588 #define BBV(num,XX,YY,ZZ) \
589  inxyz[num].x= (double) (me->EXTENT_##XX); \
590  inxyz[num].y= (double) (me->EXTENT_##YY); \
591  inxyz[num].z= (double) (me->EXTENT_##ZZ);
592 
593 static void add_translation (struct point_XYZ *arr, float x, float y, float z, int count) {
594  int i;
595  for (i=0; i<count; i++) {
596  arr->x += (double)x;
597  arr->y += (double)y;
598  arr->z += (double)z;
599  arr++;
600  }
601 }
602 
603 static void multiply_in_scale(struct point_XYZ *arr, float x, float y, float z, int count) {
604  int i;
605  for (i=0; i<count; i++) {
606  arr->x *= (double)x;
607  arr->y *= (double)y;
608  arr->z *= (double)z;
609  arr++;
610  }
611 }
612 
613 
614 void printmatrix(GLDOUBLE* mat) {
615  int i;
616  for(i = 0; i< 16; i++) {
617  printf("mat[%d] = %4.3f%s",i,mat[i],i==3 ? "\n" : i==7? "\n" : i==11? "\n" : "");
618  }
619  printf ("\n");
620 
621 }
622 
623 
624 /* for children nodes; set the parent grouping nodes extent - we expect the center
625  * of the group to be passed in in the floats x,y,z */
626 
627 void propagateExtent(struct X3D_Node *me) {
628  float minx, miny, minz, maxx, maxy, maxz;
629  int i;
630  struct X3D_Node *geomParent;
631  int touched;
632 
633  if (me==NULL) return;
634 
635 
636  #ifdef FRUSTUMVERBOSE
637  printf ("propextent Iam %s, myExtent (%4.2f %4.2f) (%4.2f %4.2f) (%4.2f %4.2f) me %p parents %d\n",
638  stringNodeType(me->_nodeType),
639  me->EXTENT_MAX_X, me->EXTENT_MIN_X,
640  me->EXTENT_MAX_Y, me->EXTENT_MIN_Y,
641  me->EXTENT_MAX_Z, me->EXTENT_MIN_Z,
642  me, vectorSize(me->_parentVector));
643  #endif
644 
645 
646  if (me->_parentVector == NULL) {
647  ConsoleMessage ("propagateExtent, parentVector NULL, me %p %s\n",
648  me,stringNodeType(me->_nodeType));
649  return;
650  }
651 
652  /* calculate the maximum of the current position, and add the previous extent */
653  /* these MIGHT be overwritten if we have a Transform node here */
654  /* these values are used in PROP_EXTENT_CHECK */
655  maxx = me->EXTENT_MAX_X; minx = me->EXTENT_MIN_X;
656  maxy = me->EXTENT_MAX_Y; miny = me->EXTENT_MIN_Y;
657  maxz = me->EXTENT_MAX_Z; minz = me->EXTENT_MIN_Z;
658 
659  /* is this a transform? Should we add in the translated position?? */
660  FRUSTUM_TRANS(Transform);
661  FRUSTUM_GEOTRANS;
662  FRUSTUM_GEOLOCATION;
663  FRUSTUM_TRANS(HAnimSite);
664  FRUSTUM_TRANS(HAnimJoint);
665 
666 
667  for (i=0; i<vectorSize(me->_parentVector); i++) {
668  geomParent = vector_get(struct X3D_Node *, me->_parentVector, i);
669 
670  /* do we propagate for this parent? */
671  touched = FALSE;
672 
673  /* switch nodes - only propagate extent back up if the node is "active" */
674  switch (geomParent->_nodeType) {
675  case NODE_GeoLOD:
676  if (is_GeoLODchild_inrange(X3D_GEOLOD(geomParent), me)) {
677  PROP_EXTENT_CHECK;
678  }
679  break;
680  case NODE_LOD:
681  /* works for both X3D and VRML syntax; compare with the "_selected" field */
682  if (me == X3D_LODNODE(geomParent)->_selected) {
683  PROP_EXTENT_CHECK;
684  }
685  break;
686 
687  case NODE_Switch:
688  if (is_Switchchild_inrange(X3D_SWITCH(geomParent), me)) {
689  PROP_EXTENT_CHECK;
690  }
691  break;
692  case NODE_CADLayer:
693  if (is_CADLayerchild_inrange(X3D_CADLAYER(geomParent),me)) {
694  PROP_EXTENT_CHECK;
695  }
696  break;
697  default: {
698  PROP_EXTENT_CHECK;
699  }
700  }
701 
702 
703  #ifdef FRUSTUMVERBOSE
704  printf ("after transform calcs me (%p %s) my parent %d is (%p %s) ext %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f\n",
705  me, stringNodeType(me->_nodeType),i,geomParent, stringNodeType(geomParent->_nodeType),
706  geomParent->EXTENT_MAX_X, geomParent->EXTENT_MIN_X,
707  geomParent->EXTENT_MAX_Y, geomParent->EXTENT_MIN_Y,
708  geomParent->EXTENT_MAX_Z, geomParent->EXTENT_MIN_Z);
709  #endif
710 
711  /* now, send these up the line, assuming this child makes the extent larger */
712  if (touched) propagateExtent(geomParent);
713  }
714 }
715 
716 /* perform all the viewpoint rotations for a point */
717 /* send in a pointer for the result, the current bounding box point to rotate, and the current ModelView matrix */
718 
719 void moveAndRotateThisPoint(struct point_XYZ *mypt, double x, double y, double z, double *MM) {
720  float outF[3];
721  float inF[3];
722  inF[0] = (float) x; inF[1] = (float) y; inF[2] = (float) z;
723 
724  /* transform this vertex via the modelview matrix */
725  transformf (outF,inF,MM);
726 
727  #ifdef VERBOSE
728  printf ("transformed %4.2f %4.2f %4.2f, to %4.2f %4.2f %4.2f\n",inF[0], inF[1], inF[2],
729  outF[0], outF[1], outF[2]);
730  #endif
731  mypt->x = outF[0]; mypt->y=outF[1],mypt->z = outF[2];
732 }
733 
734 
735 /**************************************************************************************/
736 
737 /* get the center of the bounding box, rotate it, and find out how far it is Z distance from us.
738 */
739 
740 
741 void record_ZBufferDistance(struct X3D_Node *node) {
742  GLDOUBLE modelMatrix[16];
743  double ex;
744  double ey;
745  double ez;
746  struct point_XYZ movedPt;
747  double minMovedDist;
748 
749  minMovedDist = -1000000000;
750 
751  #ifdef FRUSTUMVERBOSE
752  printf ("\nrecordDistance for node %p nodeType %s size %4.2f %4.2f %4.2f ",node, stringNodeType (node->_nodeType),
753  node->EXTENT_MAX_X - node->EXTENT_MIN_X,
754  node->EXTENT_MAX_Y - node->EXTENT_MIN_Y,
755  node->EXTENT_MAX_Z - node->EXTENT_MIN_Z
756  );
757 
758  if (APPROX(node->EXTENT_MAX_X,-10000.0)) printf ("EXTENT NOT INIT");
759 
760  printf ("\n");
761  printf ("recordDistance, max,min %f:%f, %f:%f, %f:%f\n",
762  node->EXTENT_MAX_X , node->EXTENT_MIN_X,
763  node->EXTENT_MAX_Y , node->EXTENT_MIN_Y,
764  node->EXTENT_MAX_Z , node->EXTENT_MIN_Z);
765  #endif
766 
767  /* get the current pos in modelMatrix land */
768  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
769 
770 #ifdef TRY_ONLY_ONE_POINT
771 #ifdef TRY_RADIUS
772  /* get radius of bounding box around its origin */
773  ex = (node->EXTENT_MAX_X - node->EXTENT_MIN_X) / 2.0;
774  ey = (node->EXTENT_MAX_Y - node->EXTENT_MIN_Y) / 2.0;
775  ez = (node->EXTENT_MAX_Z - node->EXTENT_MIN_Z) / 2.0;
776  printf (" ex %lf ey %lf ez %lf\n",ex,ey,ez);
777 #else
778  /* get the center of the bounding box */
779  ex = node->EXTENT_MAX_X + node->EXTENT_MIN_X;
780  ey = node->EXTENT_MAX_Y + node->EXTENT_MIN_Y;
781  ez = node->EXTENT_MAX_Z + node->EXTENT_MIN_Z;
782 #endif
783 
784 
785  /* rotate the center of this point */
786  moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
787  printf ("%lf %lf %lf centre is %lf %lf %lf\n",ex,ey,ez,movedPt.x, movedPt.y, movedPt.z);
788  minMovedDist = movedPt.z;
789 
790 #else
791 
792  /* printf ("moving all 8 points of this bounding box\n"); */
793  ex = node->EXTENT_MIN_X;
794  ey = node->EXTENT_MIN_Y;
795  ez = node->EXTENT_MIN_Z;
796  moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
797  if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
798  /* printf ("%lf %lf %lf moved is %lf %lf %lf\n",ex,ey,ez,movedPt.x, movedPt.y, movedPt.z); */
799 
800  ex = node->EXTENT_MIN_X;
801  ey = node->EXTENT_MIN_Y;
802  ez = node->EXTENT_MAX_Z;
803  moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
804  if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
805  /* printf ("%lf %lf %lf moved is %lf %lf %lf\n",ex,ey,ez,movedPt.x, movedPt.y, movedPt.z); */
806 
807  ex = node->EXTENT_MIN_X;
808  ey = node->EXTENT_MAX_Y;
809  ez = node->EXTENT_MIN_Z;
810  moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
811  if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
812  /* printf ("%lf %lf %lf moved is %lf %lf %lf\n",ex,ey,ez,movedPt.x, movedPt.y, movedPt.z); */
813 
814  ex = node->EXTENT_MIN_X;
815  ey = node->EXTENT_MAX_Y;
816  ez = node->EXTENT_MAX_Z;
817  moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
818  if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
819  /* printf ("%lf %lf %lf moved is %lf %lf %lf\n",ex,ey,ez,movedPt.x, movedPt.y, movedPt.z); */
820 
821  ex = node->EXTENT_MAX_X;
822  ey = node->EXTENT_MIN_Y;
823  ez = node->EXTENT_MIN_Z;
824  moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
825  if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
826  /* printf ("%lf %lf %lf moved is %lf %lf %lf\n",ex,ey,ez,movedPt.x, movedPt.y, movedPt.z); */
827 
828  ex = node->EXTENT_MAX_X;
829  ey = node->EXTENT_MIN_Y;
830  ez = node->EXTENT_MAX_Z;
831  moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
832  if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
833  /* printf ("%lf %lf %lf moved is %lf %lf %lf\n",ex,ey,ez,movedPt.x, movedPt.y, movedPt.z); */
834 
835  ex = node->EXTENT_MAX_X;
836  ey = node->EXTENT_MAX_Y;
837  ez = node->EXTENT_MIN_Z;
838  moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
839  if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
840  /* printf ("%lf %lf %lf moved is %lf %lf %lf\n",ex,ey,ez,movedPt.x, movedPt.y, movedPt.z); */
841 
842  ex = node->EXTENT_MAX_X;
843  ey = node->EXTENT_MAX_Y;
844  ez = node->EXTENT_MAX_Z;
845  moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
846  if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
847  /* printf ("%lf %lf %lf moved is %lf %lf %lf\n",ex,ey,ez,movedPt.x, movedPt.y, movedPt.z); */
848 #endif
849 
850  node->_dist = minMovedDist;
851 
852 #ifdef FRUSTUMVERBOSE
853  printf ("I am at %lf %lf %lf\n",Viewer()->currentPosInModel.x, Viewer()->currentPosInModel.y, Viewer()->currentPosInModel.z);
854  printf ("and distance to the nearest corner of the BB for this node is %lf\n", node->_dist);
855 #endif
856 
857 
858 
859 #undef FRUSTUMVERBOSE
860 
861 }
862 
863 /***************************************************************************/
864 
865 void OcclusionStartofRenderSceneUpdateScene() {
866 
867 #ifdef OCCLUSION /* do we have hardware for occlusion culling? */
868  int i;
869  ppFrustum p;
870  ttglobal tg = gglobal();
871  p = (ppFrustum)gglobal()->Frustum.prv;
872  /* each time through the event loop, we count the occluders. Note, that if, say, a
873  shape was USED 100 times, that would be 100 occlude queries, BUT ONE SHAPE, thus
874  there is not an implicit 1:1 mapping between shapes and occlude queries */
875 
876  p->potentialOccluderCount = 0;
877 
878  /* did we have a failure here ? */
879  if (tg->Frustum.OccFailed) return;
880 
881  /* have we been through this yet? */
882  if (p->OccInitialized == FALSE) {
883  #ifdef OCCLUSIONVERBOSE
884  printf ("initializing OcclusionCulling...\n");
885  #endif
886  /* do we have an environment variable for this? */
887  if (gglobal()->internalc.global_occlusion_disable) {
888  tg->Frustum.OccFailed = TRUE;
889  } else {
890  s_renderer_capabilities_t *rdr_caps;
891  rdr_caps = gglobal()->display.rdr_caps;
892  if (rdr_caps->av_occlusion_q) {
893 
894  #ifdef OCCLUSIONVERBOSE
895  printf ("OcclusionStartofRenderSceneUpdateScene: have OcclusionQuery\n");
896  #endif
897 
898  /* we make the OccQuerySize larger than the maximum number of occluders,
899  so we don't have to realloc too much */
900  p->OccQuerySize = p->maxOccludersFound + 1000;
901 
902  p->occluderNodePointer = MALLOC (void **, sizeof (void *) * p->OccQuerySize);
903  p->OccQueries = MALLOC (GLuint *, sizeof(GLuint) * p->OccQuerySize);
904  FW_GL_GENQUERIES(p->OccQuerySize,p->OccQueries);
905  //ConsoleMessage ("generated %d queries, pointer %p",p->OccQuerySize,p->OccQueries);
906  p->OccInitialized = TRUE;
907  for (i=0; i<p->OccQuerySize; i++) {
908  p->occluderNodePointer[i] = 0;
909  }
910  p->QueryCount = p->maxOccludersFound; /* for queries - we can do this number */
911  #ifdef OCCLUSIONVERBOSE
912  printf ("QueryCount now %d\n",p->QueryCount);
913  #endif
914 
915  } else {
916  #ifdef OCCLUSIONVERBOSE
917  printf ("OcclusionStartofRenderSceneUpdateScene: DO NOT have OcclusionQuery\n");
918  #endif
919 
920  /* we dont seem to have this extension here at runtime! */
921  /* this happened, eg, on my Core4 AMD64 box with Mesa */
922  tg->Frustum.OccFailed = TRUE;
923  return;
924  }
925  }
926 
927  }
928 
929 
930  /* did we find more shapes than before? */
931  if (p->maxOccludersFound > p->QueryCount) {
932  if (p->maxOccludersFound > p->OccQuerySize) {
933  /* printf ("have to regen queries\n"); */
934  p->QueryCount = 0;
935 
936  /* possibly previous had zero occluders, lets just not bother deleting for zero */
937  if (p->OccQuerySize > 0) {
938  FW_GL_DELETEQUERIES (p->OccQuerySize, p->OccQueries);
939  FW_GL_FLUSH();
940  }
941 
942  p->OccQuerySize = p->maxOccludersFound + 1000;
943  p->occluderNodePointer = REALLOC (p->occluderNodePointer,sizeof (void *) * p->OccQuerySize);
944  p->OccQueries = REALLOC (p->OccQueries,sizeof (GLuint) * p->OccQuerySize);
945  FW_GL_GENQUERIES(p->OccQuerySize,p->OccQueries);
946  ConsoleMessage ("reinitialized queries... now %p",p->OccQueries);
947  for (i=0; i<p->OccQuerySize; i++) {
948  p->occluderNodePointer[i] = 0;
949  }
950  }
951  p->QueryCount = p->maxOccludersFound; /* for queries - we can do this number */
952  #ifdef OCCLUSIONVERBOSE
953  printf ("QueryCount here is %d\n",p->QueryCount);
954  #endif
955 
956  }
957 
958 
959 // #ifdef OCCLUSIONVERBOSE
960 // glGetQueryiv(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &p->queryCounterBits);
961 // printf ("queryCounterBits %d\n",p->queryCounterBits);
962 // #endif
963 #endif /* OCCLUSION */
964 
965 }
966 
967 void OcclusionCulling () {
968 //non-occlusion visibilitysensor method: __Samples = 0 in startofloopnodeupdates
969 #ifdef OCCLUSION /* do we have hardware for occlusion culling? */
970  int i;
971  struct X3D_Shape *shapePtr;
972  struct X3D_VisibilitySensor *visSenPtr;
973  int checkCount;
974  GLuint samples;
975  ppFrustum p;
976  ttglobal tg = gglobal();
977  p = (ppFrustum)tg->Frustum.prv;
978 
979 //#ifdef OCCLUSIONVERBOSE
980 // {
981 // GLint query;
982 // glGetQueryiv(GL_SAMPLES_PASSED, GL_CURRENT_QUERY, &query);
983 // printf ("currentQuery is %d\n",query);
984 // }
985 //#endif
986 
987  visSenPtr = NULL;
988  shapePtr = NULL;
989 
990  /* Step 0. go through list of assigned nodes, and either:
991  - if we have OcclusionQueries: REMOVE the VF_hasVisibleChildren flag;
992  - else, set every node to VF_hasVisibleChildren */
993  zeroVisibilityFlag();
994 
995  /* Step 1. did we have some problem with Occlusion ? */
996  if (tg->Frustum.OccFailed) return;
997 
998  /* Step 2. go through the list of "OccludeCount" nodes, and determine if they are visible.
999  If they are not, then, we have to, at some point, make them visible, so that we can test again. */
1000  /* note that the potentialOccluderCount is only incremented if the __occludeCheckCount tells us
1001  that it should be checked again - see the interplay between the eventLoop stuff in OpenGLUtils.c
1002  and the OCCLUSION* defines in headers.h - we DO NOT generate a query every time through the loop */
1003 
1004  //#ifdef OCCLUSIONVERBOSE
1005  //printf ("OcclusionCulling - potentialOccluderCount %d\n",p->potentialOccluderCount);
1006  //#endif
1007 
1008  for (i=0; i<p->potentialOccluderCount; i++) {
1009  #ifdef OCCLUSIONVERBOSE
1010  printf ("checking node %d of %d\n",i, p->potentialOccluderCount);
1011  #endif
1012 
1013  checkCount = 0;
1014 
1015  /* get the check count field for this node - see if we did a check of this */
1016  shapePtr = X3D_SHAPE(p->occluderNodePointer[i]);
1017  if (shapePtr != NULL) {
1018  if (shapePtr->_nodeType == NODE_Shape) {
1019  visSenPtr = NULL;
1020  checkCount = shapePtr->__occludeCheckCount;
1021  } else if (shapePtr->_nodeType == NODE_VisibilitySensor) {
1022  visSenPtr = X3D_VISIBILITYSENSOR(shapePtr);
1023  shapePtr = NULL;
1024  checkCount = visSenPtr->__occludeCheckCount;
1025  } else {
1026  printf ("OcclusionCulling on node type %s not allowed\n",stringNodeType(shapePtr->_nodeType));
1027  return;
1028  }
1029  }
1030 
1031  #ifdef OCCLUSIONVERBOSE
1032  if (shapePtr) printf ("OcclusionCulling, for a %s (index %d ptr %p) checkCount %d\n",stringNodeType(shapePtr->_nodeType),i,shapePtr,checkCount);
1033  else printf ("OcclusionCulling, for a %s (index %d) checkCount %d\n",stringNodeType(visSenPtr->_nodeType),i,checkCount);
1034  #endif
1035 
1036  /* an Occlusion test will have been run on this one */
1037 
1038  FW_GL_GETQUERYOBJECTUIV(p->OccQueries[i],GL_QUERY_RESULT_AVAILABLE,&p->OccResultsAvailable);
1039  PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY_RESULTS_AVAIL");
1040 
1041  #define SLEEP_FOR_QUERY_RESULTS
1042  #ifdef SLEEP_FOR_QUERY_RESULTS
1043  /* for now, lets loop to see when we get results */
1044  while (p->OccResultsAvailable == GL_FALSE) {
1045  usleep(100);
1046  FW_GL_GETQUERYOBJECTUIV(p->OccQueries[i],GL_QUERY_RESULT_AVAILABLE,&p->OccResultsAvailable);
1047  PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY_RESULTS_AVAIL");
1048  }
1049  #endif
1050 
1051 
1052  #ifdef OCCLUSIONVERBOSE
1053  if (p->OccResultsAvailable == GL_FALSE) printf ("results not ready for %d\n",i);
1054  #endif
1055 
1056 
1057  /* if we are NOT ready; we keep the count going, but we do NOT change the results of VisibilitySensors */
1058  if (p->OccResultsAvailable == GL_FALSE) samples = 10000;
1059 
1060  FW_GL_GETQUERYOBJECTUIV (p->OccQueries[i], GL_QUERY_RESULT, &samples);
1061  PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY");
1062 
1063  #ifdef OCCLUSIONVERBOSE
1064  printf ("i %d checkc %d samples %d\n",i,checkCount,samples);
1065  #endif
1066 
1067  if (p->occluderNodePointer[i] != 0) {
1068 
1069  /* if this is a VisibilitySensor, record the samples */
1070  if (visSenPtr != NULL) {
1071 
1072  #ifdef OCCLUSIONVERBOSE
1073  printf ("OcclusionCulling, found VisibilitySensor at %d, fragments %d active %d\n",i,samples,checkCount);
1074  #endif
1075 
1076 
1077  /* if this is a DEF/USE, we might already have done this one, as we have same
1078  node pointer used in other places. */
1079  if (checkCount != OCCCHECKNEXTLOOP) {
1080 
1081  if (samples > 0) {
1082  visSenPtr->__visible = TRUE;
1083  visSenPtr->__occludeCheckCount = OCCCHECKNEXTLOOP; /* look for this EVERY time through */
1084  visSenPtr->__Samples = samples;
1085  } else {
1086  visSenPtr->__occludeCheckCount = OCCCHECKSOON; /* check again soon */
1087  visSenPtr->__visible =FALSE;
1088  visSenPtr->__Samples = 0;
1089  }
1090 
1091  /* } else {
1092  printf ("shape, already have checkCount == OCCCHECKNEXTLOOP, not changing visibility params\n");
1093 
1094  */
1095  }
1096  }
1097 
1098 
1099  /* is this is Shape? */
1100  else if (shapePtr != NULL) {
1101  #ifdef OCCLUSIONVERBOSE
1102  printf ("OcclusionCulling, found Shape %d, fragments %d active %d\n",i,samples,checkCount);
1103  #endif
1104  //if (samples == 0) ConsoleMessage ("invisible shape %d, fragments %d",i,samples);
1105 
1106  /* if this is a DEF/USE, we might already have done this one, as we have same
1107  node pointer used in other places. */
1108  if (checkCount != OCCWAIT) {
1109 
1110  /* is this node visible? If so, tell the parents! */
1111  if (samples > OCCSHAPESAMPLESIZE) {
1112  TRACE_MSG ("Shape %p is VISIBLE\n",shapePtr);
1113  shapePtr->__visible = TRUE;
1114  shapePtr->__occludeCheckCount= OCCWAIT; /* wait a little while before checking again */
1115  shapePtr->__Samples = samples;
1116  } else {
1117  TRACE_MSG ("Shape %p is NOT VISIBLE\n",shapePtr);
1118  shapePtr->__visible=FALSE;
1119  shapePtr->__occludeCheckCount = OCCCHECKSOON; /* check again soon */
1120  shapePtr->__Samples = 0;
1121  }
1122  /* } else {
1123  printf ("shape, already have checkCount == OCCWAIT, not changing visibility params\n");
1124  */
1125  }
1126  }
1127  }
1128  }
1129 #endif /* OCCLUSION */
1130 }
1131 
1132 /* shut down the occlusion stuff */
1133 void zeroOcclusion(void) {
1134 
1135 #ifdef OCCLUSION /* do we have hardware for occlusion culling? */
1136 
1137  int i;
1138  ppFrustum p;
1139  ttglobal tg = gglobal();
1140  p= (ppFrustum)tg->Frustum.prv;
1141 
1142  if (tg->Frustum.OccFailed) return;
1143 
1144  #ifdef OCCLUSIONVERBOSE
1145  printf ("zeroOcclusion - potentialOccluderCount %d\n",p->potentialOccluderCount);
1146  #endif
1147 
1148  for (i=0; i<p->potentialOccluderCount; i++) {
1149 #ifdef OCCLUSIONVERBOSE
1150  printf ("checking node %d of %d\n",i, p->potentialOccluderCount);
1151 #endif
1152 
1153  FW_GL_GETQUERYOBJECTUIV(p->OccQueries[i],GL_QUERY_RESULT_AVAILABLE,&p->OccResultsAvailable);
1154  PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY_RESULTS_AVAIL");
1155 #ifdef SLEEP_FOR_QUERY_RESULTS
1156  /* for now, lets loop to see when we get results */
1157  while (p->OccResultsAvailable == GL_FALSE) {
1158 #ifdef OCCLUSIONVERBOSE
1159  printf ("zero - waiting and looping for results\n");
1160 #endif
1161  usleep(1000);
1162  FW_GL_GETQUERYOBJECTUIV(p->OccQueries[i],GL_QUERY_RESULT_AVAILABLE,&p->OccResultsAvailable);
1163  PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY_RESULTS_AVAIL");
1164  }
1165 #endif
1166  }
1167 #ifdef OCCLUSIONVERBOSE
1168  printf ("zeroOcclusion - done waiting\n");
1169 #endif
1170 
1171  p->QueryCount = 0;
1172 
1173  // debugging
1174  //if (p->OccQueries) {
1175  // ConsoleMessage ("p->OccQueries exists, p->OccQuerySize %p, p->OccQueries %p",p->OccQuerySize, p->OccQueries);
1176  //}
1177  //if(p->OccQueries)
1178  //glDeleteQueries (p->OccQuerySize, p->OccQueries);
1179  //FW_GL_FLUSH();
1180 
1181  p->OccQuerySize=0;
1182  p->maxOccludersFound = 0;
1183  p->OccInitialized = FALSE;
1184  p->potentialOccluderCount = 0;
1185  //ConsoleMessage ("freeing OccQueries %p",p->OccQueries);
1186  FREE_IF_NZ(p->OccQueries);
1187  FREE_IF_NZ(p->occluderNodePointer);
1188 #endif /* OCCLUSION */
1189 }