FreeWRL / FreeX3D 4.3.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
51static void quaternion_multi_rotation(struct point_XYZ *ret, const Quaternion *quat, const struct point_XYZ * v, int count);
52static void add_translation (struct point_XYZ *arr, float x, float y, float z, int count);
53static 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
88typedef 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;
112void *Frustum_constructor(){
113 void *v = MALLOCV(sizeof(struct pFrustum));
114 memset(v,0,sizeof(struct pFrustum));
115 return v;
116}
117void 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
144void 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
163void 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
180//extent6f {xmax,xmin,ymax,ymin,zmax,zmin}
181float *extent6f_constructor(float *extent6, float xmin,float xmax, float ymin,float ymax, float zmin,float zmax){
182 float *e = extent6;
183 e[0]=xmax; e[1] = xmin; e[2]=ymax; e[3]=ymin; e[4]=zmax; e[5]=zmin;
184 return e;
185}
186float *extent6f_clear(float *extent6){
187 float *e = extent6;
188 //s max,min y max,min, z max,min
189 e[0]=-10000.0; e[1]=10000.0; e[2]=-10000.0; e[3]=10000.0; e[4]=-10000.0; e[5]=10000.0;
190 return e;
191}
192int extent6f_isSet(float *extent6){
193 //extents are set with min > max, so a way to tell
194 // if they are set is to check if min <= max or max >= min
195 int iret;
196 float *e = extent6;
197 //is max >= min for any dimensions? if so, then is set.
198 //iret = (e[0] >= e[1] && e[2] >= e[3] && e[4] >= e[5]) ? TRUE : FALSE;
199 //iret = (e[0] >= e[1] || e[2] >= e[3] || e[4] >= e[5]) ? TRUE : FALSE;
200 iret = (e[0] >= e[1] && e[2] >= e[3] && e[4] >= e[5]) ? TRUE : FALSE;
201 return iret;
202}
203float *extent6f_copy(float *eout6, float *ein6){
204 memcpy(eout6,ein6,6*sizeof(float));
205 return eout6;
206}
207void extent6f_to_vec3f(float *extent6, float *pmin, float *pmax){
208 int i;
209 for(i=0;i<3;i++){
210 pmin[i] = extent6[i*2 + 1];
211 pmax[i] = extent6[i*2 + 0];
212 }
213}
214void extent6f_from_vec3f2(float *extent6, float *pmin, float *pmax){
215 int i;
216 for(i=0;i<3;i++){
217 extent6[i*2 + 1] = pmin[i];
218 extent6[i*2 + 0] = pmax[i];
219 }
220}
221
222
223float *extent6f_union_extent6f(float *extent6, float *ein6){
224 int i,isa,isb;
225 isa = extent6f_isSet(extent6);
226 isb = extent6f_isSet(ein6);
227 if(isa && isb)
228 for(i=0;i<3;i++){
229 extent6[i*2 + 1] = min(extent6[i*2 + 1], ein6[i*2 + 1]);
230 extent6[i*2 + 0] = max(extent6[i*2 + 0], ein6[i*2 + 0]);
231 }
232 else if(isb) extent6f_copy(extent6,ein6);
233 return extent6;
234}
235float *extent6f_intersect_extent6f(float *extent6, float *eina, float *einb){
236 int i,isa,isb;
237 extent6f_clear(extent6);
238 isa = extent6f_isSet(eina);
239 isb = extent6f_isSet(einb);
240 if(isa && isb)
241 for(i=0;i<3;i++){
242 extent6[i*2 + 1] = max(eina[i*2 + 1], einb[i*2 + 1]);
243 extent6[i*2 + 0] = min(eina[i*2 + 0], einb[i*2 + 0]);
244 }
245 return extent6;
246}
247float *extent6f_union_vec3f(float *extent6, float *p3){
248 int i,isa,isb;
249 isa = extent6f_isSet(extent6);
250 if(!isa)
251 for(i=0;i<3;i++){
252 extent6[i*2 + 1] = p3[i];
253 extent6[i*2 + 0] = p3[i];
254 }
255 for(i=0;i<3;i++){
256 extent6[i*2 + 1] = min(extent6[i*2 + 1], p3[i]);
257 extent6[i*2 + 0] = max(extent6[i*2 + 0], p3[i]);
258 }
259 return extent6;
260}
261int extent6f_point_inside(float *extent6, float *pd){
262 int inside = TRUE;
263 for(int i=0;i<3;i++){
264 inside = inside && extent6[i*2 + 1] < pd[i];
265 inside = inside && pd[i] < extent6[i*2 + 0];
266 }
267 return inside;
268}
269float *extent6f_union_vec2f(float *extent6, float *p2){
270 int i,isa,isb;
271 isa = extent6f_isSet(extent6);
272 if(!isa)
273 for(i=0;i<2;i++){
274 extent6[i*2 + 1] = p2[i];
275 extent6[i*2 + 0] = p2[i];
276 }
277 for(i=0;i<2;i++){
278 extent6[i*2 + 1] = min(extent6[i*2 + 1], p2[i]);
279 extent6[i*2 + 0] = max(extent6[i*2 + 0], p2[i]);
280 }
281 return extent6;
282}
283void extent6f_to_box3f8(float *extent6, float *p3f8){
284 //generate 8 points from extent
285 int i,j,k,n;
286 n = 0;
287 for(k=0;k<2;k++)
288 for(j=0;j<2;j++)
289 for(i=0;i<2;i++){
290 p3f8[n*3 + 0] = extent6[0 + i];
291 p3f8[n*3 + 1] = extent6[2 + j];
292 p3f8[n*3 + 2] = extent6[4 + k];
293 n++;
294 }
295}
296float * extent6f_from_box3fn(float *extent6,float *p, int n){
297 int i,j;
298 extent6f_clear(extent6);
299 for(i=0;i<n;i++)
300 extent6f_union_vec3f(extent6,&p[i*3]);
301 return extent6;
302}
303float * extent6f_from_box2fn(float *extent6,float *p, int n){
304 int i,j;
305 extent6f_clear(extent6);
306 for(i=0;i<n;i++)
307 extent6f_union_vec2f(extent6,&p[i*2]);
308 return extent6;
309}
310float *extent6f_scale3f(float *eout6, float *ein6, float *s3){
311 int i;
312 for(i=0;i<3;i++){
313 eout6[i*2 + 0] = ein6[i*2 + 0] * s3[i];
314 eout6[i*2 + 1] = ein6[i*2 + 1] * s3[i];
315 }
316 return eout6;
317}
318float *extent6f_translate3f(float *eout6, float *ein6, float *p3){
319 int i;
320 for(i=0;i<3;i++){
321 eout6[i*2 + 0] = ein6[i*2 + 0] + p3[i];
322 eout6[i*2 + 1] = ein6[i*2 + 1] + p3[i];
323 }
324 return eout6;
325}
326float *extent6f_translate3d(float *eout6, float *ein6, double *p3){
327 int i;
328 for(i=0;i<3;i++){
329 eout6[i*2 + 0] = ein6[i*2 + 0] + p3[i];
330 eout6[i*2 + 1] = ein6[i*2 + 1] + p3[i];
331 }
332 return eout6;
333}
334float *extent6f_get_center3f(float *extent6, float *center3){
335 int i;
336 for(i=0;i<3;i++){
337 center3[i] = .5f*(extent6[i*2 + 0] + extent6[i*2 + 1]);
338 }
339 return center3;
340}
341float extent6f_get_maxsize(float *extent6){
342 float msize;
343 int i;
344 msize = 0.0f;
345 for(i=0;i<3;i++){
346 msize = max(msize,extent6[i*2 + 0] - extent6[i*2 + 1]);
347 }
348 return msize;
349}
350void extent6f2bbox(float *extent6, float* center, float *size){
351 //extent6: xmax,xmin,ymax,ymin,zmax,zmin
352 for(int i=0;i<3;i++){
353 if(extent6[2*i] >= extent6[2*i+1]){
354 center[i] = .5f*extent6[2*i] + .5f*extent6[2*i+1];
355 size[i] = extent6[2*i+0] - extent6[2*i+1];
356 }else{
357 center[i] = 0.0f;
358 size[i] = -1.0f;
359 }
360 }
361}
362void bbox2extent6f(float* center, float *size, float *extent6){
363
364 for(int i=0;i<3;i++){
365 if(size[i] >= 0.0f){
366 extent6[2*i +0] = center[i] + .5f*size[i]; //max
367 extent6[2*i +1] = center[i] - .5f*size[i]; //min
368 }else{
369 extent6[2*i +0] = -10000.0f; //max
370 extent6[2*i +1] = 10000.0f; //min
371 }
372 }
373}
374
375float extent6f_get_maxradius(float *extent6){
376
377 float radius, p3f8[8][3], pc[3], pd[3];
378 int i;
379 radius = 0.0f;
380 extent6f_get_center3f(extent6,pc);
381 extent6f_to_box3f8(extent6, p3f8[0]);
382 for(i=0;i<8;i++){
383 vecdif3f(pd,p3f8[i],pc);
384 radius = max(radius, veclength3f(pd));
385 }
386 return radius;
387}
388float *extent6f_rotate4f(float *eout6, float *ein6, float *vrot4){
389 int i;
390 float p3f[8][3];
391 double p3d[8][3];
392 Quaternion rq;
393
394 extent6f_to_box3f8(ein6,p3f[0]);
395 float2double(p3d[0],p3f[0],24);
396 vrmlrot_to_quaternion(&rq,vrot4[0],vrot4[1], vrot4[2], vrot4[3]);
397 for(i=0;i<8;i++){
398 quaternion_rotationd(p3d[i],&rq,p3d[i]);
399 }
400 double2float(p3f[0],p3d[0],24);
401 extent6f_from_box3fn(eout6,p3f[0],8);
402 return eout6;
403}
404
405float *extent6f_rotate4d(float *eout6, float *ein6, double *vrot4){
406 int i;
407 float p3f[8][3];
408 double p3d[8][3];
409 Quaternion rq;
410
411 extent6f_to_box3f8(ein6,p3f[0]);
412 float2double(p3d[0],p3f[0],24);
413 vrmlrot_to_quaternion(&rq,vrot4[0],vrot4[1], vrot4[2], vrot4[3]);
414 for(i=0;i<8;i++){
415 quaternion_rotationd(p3d[i],&rq,p3d[i]);
416 }
417 double2float(p3f[0],p3d[0],24);
418 extent6f_from_box3fn(eout6,p3f[0],8);
419 return eout6;
420}
421float *extent6f_mattransform4d(float *eout6,float *ein6, double *mat4){
422 int i;
423 float p3f[8][3];
424 double p3d[8][3];
425 Quaternion rq;
426 if(extent6f_isSet(ein6)){
427 extent6f_to_box3f8(ein6,p3f[0]);
428 float2double(p3d[0],p3f[0],24);
429 for(i=0;i<8;i++){
430 transformAFFINEd(p3d[i],p3d[i],mat4);
431 }
432 double2float(p3f[0],p3d[0],24);
433 extent6f_from_box3fn(eout6,p3f[0],8);
434 }else{
435 extent6f_clear(eout6);
436 }
437 return eout6;
438
439}
440float *orientedBBox2extent6f(float *extent6, float *obb12){
441 // Tiles3D section 3. https://github.com/CesiumGS/3d-tiles/blob/master/3d-tiles-overview.pdf
442 float *center = &obb12[0];
443 float *hx = &obb12[3];
444 float *hy = &obb12[6];
445 float *hz = &obb12[9];
446 float p3f[8][3], temp[3], temp2[3];
447 int ijk = 0;
448 for(int i=0;i<2;i++)
449 for(int j=0;j<2;j++)
450 for(int k=0;k<2;k++){
451 veccopy3f(temp,center);
452 vecadd3f(temp,temp,vecscale3f(temp2,hx,i?1.0f:-1.0f));
453 vecadd3f(temp,temp,vecscale3f(temp2,hy,j?1.0f:-1.0f));
454 vecadd3f(temp,temp,vecscale3f(temp2,hz,k?1.0f:-1.0f));
455 veccopy3f(p3f[ijk], temp);
456 ijk++;
457 }
458 extent6f_from_box3fn(extent6,p3f[0], 8);
459 return extent6;
460}
461float *orientedBBox2vec3fn(float *p3fn24, float *obb12){
462 // Tiles3D section 3. https://github.com/CesiumGS/3d-tiles/blob/master/3d-tiles-overview.pdf
463 float *center = &obb12[0];
464 float *hx = &obb12[3];
465 float *hy = &obb12[6];
466 float *hz = &obb12[9];
467 float *p3f[8], temp[3], temp2[3];
468 for(int i=0;i<8;i++) p3f[i] = &p3fn24[3*i];
469 int ijk = 0;
470 for(int i=0;i<2;i++)
471 for(int j=0;j<2;j++)
472 for(int k=0;k<2;k++){
473 veccopy3f(temp,center);
474 vecadd3f(temp,temp,vecscale3f(temp2,hx,i?1.0f:-1.0f));
475 vecadd3f(temp,temp,vecscale3f(temp2,hy,j?1.0f:-1.0f));
476 vecadd3f(temp,temp,vecscale3f(temp2,hz,k?1.0f:-1.0f));
477 veccopy3f(p3f[ijk], temp);
478 ijk++;
479 }
480 //for(int i=0;i<8;i++)
481 // printf("bvcoord %d %f %f %f\n",i,p3fn24[i*3],p3fn24[i*3+1],p3fn24[i*3+2]);
482 return p3fn24;
483}
484float *orientedBBox_mattransform4d(float *out12, float *obb12, double *mat4){
485 // Tiles3D section 3. https://github.com/CesiumGS/3d-tiles/blob/master/3d-tiles-overview.pdf
486 //H when transforming an OBB, the half- vector parts shall be transformed like normals are:
487 // using the transpose inverse
488 float fmat4[16], fmat3[9],fmat3i[9],normat[9];
489 matdouble2float4(fmat4,mat4);
490 mat423f(fmat3,fmat4);
491 matinverse3f(fmat3i,fmat3);
492 mattranspose3f(normat,fmat3i);
493 //transform half-vectors
494 for(int i=0;i<3;i++)
495 transform3x3f(&out12[(i+1)*3],&obb12[(i+1)*3],normat);
496 //transform the center
497 transformf(out12,obb12,mat4);
498 return out12;
499
500}
501float *orientedBBox_mattransformAFFINE4d(float *p3fn24, float *obb12, double *mat4){
502 // Tiles3D section 3. https://github.com/CesiumGS/3d-tiles/blob/master/3d-tiles-overview.pdf
503 //goal: transform into cuboid space using (modelview x projction) but don't divide by perspectives
504 // I think that's coboid space -1 to 1 on 3 axes
505 // then its easier to do extent checks.
506 float *p3f[8];
507 double d1[3],d2[3];
508 for(int i=0;i<8;i++) p3f[i] = &p3fn24[3*i];
509
510 orientedBBox2vec3fn(p3f[0],obb12);
511 for(int i=0;i<8;i++){
512 float2double(d1,p3f[i],3);
513 transformAFFINEd(d2,d1,mat4);
514 double2float(p3f[i],d2,3);
515 }
516 return p3fn24;
517}
518void extent6f_printf(float *extent6){
519 float *e = extent6;
520 printf("min,max x:%8.1f,%8.1f y:%8.1f,%8.1f z:%8.1f,%8.1f ",e[1],e[0],e[3],e[2],e[5],e[4]);
521}
522void union_group_extent(float *e6);
523void extent6f_setNodeExtentB(float *extent6, struct X3D_Node *node){
524 extent6f_copy(node->_extent,extent6);
525 union_group_extent(extent6);
526}
527void extent6f_setParentExtentB(float *extent6, struct X3D_Node *me){
528 int i,j;
529 struct X3D_Node *shapeParent;
530 struct X3D_Node *groupParent;
531 float *e = extent6;
532
533 #ifdef FRUSTUMVERBOSE
534 extent6f_printf(e);
535 printf(" extent6f_setNodeExtentB me %p nt %s\n",me,stringNodeType(me->_nodeType));
536 #endif
537
538 /* record this for ME for sorting purposes for sorting children fields */
539
540 if (me->_parentVector == NULL) {
541 #ifdef FRUSTUMVERBOSE
542 printf ("setExtent, parentVector NULL for node %p type %s\n",
543 me,stringNodeType(me->_nodeType));
544 #endif
545 return;
546 }
547
548 for (i=0; i<vectorSize(me->_parentVector); i++) {
549 shapeParent = vector_get(struct X3D_Node *, me->_parentVector,i);
550 extent6f_copy(shapeParent->_extent,e);
551 for (j=0; j<vectorSize(shapeParent->_parentVector); j++) {
552 groupParent = vector_get(struct X3D_Node *, shapeParent->_parentVector,j);
553
554 //extent6f_printf(e); printf(" e\n");
555 //extent6f_printf(groupParent->_extent); printf(" gp before\n");
556 extent6f_union_extent6f(groupParent->_extent,e);
557 //extent6f_printf(groupParent->_extent); printf(" gp after union\n");
558 }
559 }
560}
561//struct Planed {
562// double normal[3];
563// double d;
564//};
565//enum {
566// NEARP =0,
567// FARP,
568// BOTTOM,
569// TOP,
570// LEFT,
571// RIGHT,
572//};
573//static struct Planed pl[6];
574void planed_setCoefficients(struct Planed* p, double a, double b, double c, double d) {
575
576 // set the normal vector
577 vecsetd(p->normal,a,b,c);
578 //compute the lenght of the vector
579 double length = veclengthd(p->normal);
580 // normalize the vector
581 vecscaled(p->normal,p->normal,1.0/length);
582 // and divide d by th length as well
583 p->d = d/length;
584 vecscaled(p->p,p->normal,p->d);
585}
586int imat(int irow, int icol){
587 //int index = (irow-1)*4 + (icol-1);
588 int index = (icol-1)*4 + (irow-1);
589 return index;
590}
591void setFrustumPlanes(double *mvpMatrix, struct Planed *pl) {
592 double *m = mvpMatrix;
593 planed_setCoefficients(&pl[NEARP],
594 m[imat(3,1)] + m[imat(4,1)],
595 m[imat(3,2)] + m[imat(4,2)],
596 m[imat(3,3)] + m[imat(4,3)],
597 m[imat(3,4)] + m[imat(4,4)]);
598 planed_setCoefficients(&pl[FARP],
599 -m[imat(3,1)] + m[imat(4,1)],
600 -m[imat(3,2)] + m[imat(4,2)],
601 -m[imat(3,3)] + m[imat(4,3)],
602 -m[imat(3,4)] + m[imat(4,4)]);
603 planed_setCoefficients(&pl[BOTTOM],
604 m[imat(2,1)] + m[imat(4,1)],
605 m[imat(2,2)] + m[imat(4,2)],
606 m[imat(2,3)] + m[imat(4,3)],
607 m[imat(2,4)] + m[imat(4,4)]);
608 planed_setCoefficients(&pl[TOP],
609 -m[imat(2,1)] + m[imat(4,1)],
610 -m[imat(2,2)] + m[imat(4,2)],
611 -m[imat(2,3)] + m[imat(4,3)],
612 -m[imat(2,4)] + m[imat(4,4)]);
613 planed_setCoefficients(&pl[LEFT],
614 m[imat(1,1)] + m[imat(4,1)],
615 m[imat(1,2)] + m[imat(4,2)],
616 m[imat(1,3)] + m[imat(4,3)],
617 m[imat(1,4)] + m[imat(4,4)]);
618 planed_setCoefficients(&pl[RIGHT],
619 -m[imat(1,1)] + m[imat(4,1)],
620 -m[imat(1,2)] + m[imat(4,2)],
621 -m[imat(1,3)] + m[imat(4,3)],
622 -m[imat(1,4)] + m[imat(4,4)]);
623 //for(int i=0;i<6;i++){
624 // printf("plane[%d]= %lf %lf %lf, %lf\n",i,pl[i].normal[0],pl[i].normal[1],pl[i].normal[2],pl[i].d);
625 //}
626}
627enum {
628 OUTSIDE = 0,
629 INSIDE = 1,
630 INTERSECT = 2,
631};
632/*
633float *getVertexP(float *p, float *v, float *normal){
634 p = (xmin,ymin,zmin)
635 if (normal.x >= 0)
636 p.x = xmax;
637 if (normal.y >=0))
638 p.y = ymax;
639 if (normal.z >= 0)
640 p.z = zmax:
641}
642int frustum_boxInFrustum(struct Planed *frustum, float *abb) {
643 // http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/
644 int result = INSIDE;
645 //for each plane do ...
646 for(int i=0; i < 6; i++) {
647
648 // is the positive vertex outside?
649 if (pl[i].distance(b.getVertexP(pl[i].normal)) < 0)
650 return OUTSIDE;
651 // is the negative vertex outside?
652 else if (pl[i].distance(b.getVertexN(pl[i].normal)) < 0)
653 result = INTERSECT;
654 }
655 return(result);
656}
657*/
658int plane_intersect_plane_intersect_plane(struct Planed *p1, struct Planed *p2, struct Planed *p3, double *point){
659 //Granphics Gems I p.305
660 // computes point of intersection of 3 planes, if it exists returns TRUE and point, else FALSE
661 int intersection = FALSE;
662 double pi[3], ptemp1[3], ptemp2[3], detval;
663 vecsetd(pi,0.0,0.0,0.0);
664 vecscaled(ptemp2,veccrossd(ptemp1,p2->normal,p3->normal),vecdotd(p1->p,p1->normal));
665 vecaddd(pi,pi,ptemp2);
666 vecscaled(ptemp2,veccrossd(ptemp1,p3->normal,p1->normal),vecdotd(p2->p,p2->normal));
667 vecaddd(pi,pi,ptemp2);
668 vecscaled(ptemp2,veccrossd(ptemp1,p1->normal,p2->normal),vecdotd(p3->p,p3->normal));
669 vecaddd(pi,pi,ptemp2);
670 detval = det3d(p1->normal,p2->normal,p3->normal);
671 if( detval != 0.0){
672 intersection = TRUE;
673 vecscaled(point,pi,-1.0/detval);
674 //printf("> %lf %lf %lf\n",pi[0],pi[1],pi[2]);
675 }
676 return intersection;
677}
678
679double plane_distance_to_point(struct Planed *plane, double *p){
680 //assumes plane is normalized
681 double dist= vecdotd(plane->normal,p);
682 dist += plane->d;
683 return dist;
684}
685int frustum_point_inside(struct Planed *frustum_planes, double *p) {
686 //assumes 6 planes around frustum
687 int result = INSIDE;
688
689 for(int i=0; i < 6; i++) {
690 //if(i==1) continue; //H: far plane not far enough
691 if(plane_distance_to_point(&frustum_planes[i],p) < 0.0)
692 return OUTSIDE;
693 }
694 return(result);
695}
696int frustum_generate_corner_points(struct Planed *frustum_planes, float *pf24n){
697 //generates frusum corner points from planes,
698 //near plane clockwise starting wtih upper left, then far plane same order
699 //returns TRUE
700 int n=0;
701 int order [] = {LEFT,TOP,RIGHT,BOTTOM};
702 for(int i=0;i<2;i++){
703 for(int j=0;j<4;j++){
704 double pi[3];
705 int jj,kk,k;
706 jj = order[j];
707 k = j+1;
708 kk = order[k % 4];
709 if(!plane_intersect_plane_intersect_plane(&frustum_planes[i],&frustum_planes[jj],&frustum_planes[kk],pi))
710 return FALSE;
711 double2float(&pf24n[n*3],pi,3);
712 n++;
713 }
714 }
715 //for(int i=0;i<n;i++)
716 // printf("fc[%d] %f %f %f\n",i,pf24n[i*3],pf24n[i*3+1],pf24n[i*3+2]);
717 return TRUE;
718}
719
720int frustum_box_inside(struct Planed *frustum_planes, float *corners3f, int np) {
721 // http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes/
722 int result = INSIDE, out,in;
723
724 // for each plane do ...
725 for(int i=0; i < 6; i++) {
726
727 // reset counters for corners in and out
728 out=0;in=0;
729 // for each corner of the box do ...
730 // get out of the cycle as soon as a box as corners
731 // both inside and out of the frustum
732 for (int k = 0; k < np && (in==0 || out==0); k++) {
733 double corner[3];
734 // is the corner outside or inside
735 float2double(corner,&corners3f[k*3],3);
736 if( plane_distance_to_point(&frustum_planes[i], corner) < 0.0)
737 out++;
738 else
739 in++;
740 }
741 //if all corners are out
742 if (!in)
743 return (OUTSIDE);
744 // if some corners are out and others are in
745 else if (out)
746 result = INTERSECT;
747 }
748 return(result);
749 }
750
751
752void FRUSTUM_GEOELEVATIONGRID(struct X3D_Node *me){
753 int i;
754 if (me->_nodeType == NODE_GeoElevationGrid) {
755 if( extent6f_isSet(me->_extent)) {
756 float ef6[6];
757 struct X3D_GeoElevationGrid *node = (struct X3D_GeoElevationGrid *)me;
758 extent6f_rotate4d(ef6, me->_extent, node->__localOrient.c);
759 extent6f_translate3d(ef6,ef6,node->__autoOffset.c);
760 extent6f_setNodeExtentB(ef6,me);
761 }
762 }
763}
764
765
766
767/* does this current node actually fit in the Switch rendering scheme? */
768int is_Switchchild_inrange(struct X3D_Switch* node, struct X3D_Node* me) {
769 int wc = node->whichChoice;
770
771 /* is this VRML, or X3D?? */
772 int spec = X3D_PROTO(node->_executionContext)->__specversion;
773 if (spec < 300 || (node->choice).n) {
774 //if (node->__isX3D == 0) {
775 if(wc >= 0 && wc < ((node->choice).n)) {
776 void *p = ((node->choice).p[wc]);
777 return (X3D_NODE(p)==me);
778 }
779 } else {
780 if(wc >= 0 && wc < ((node->children).n)) {
781 void *p = ((node->children).p[wc]);
782 return (X3D_NODE(p)==me);
783 }
784 }
785 return FALSE;
786}
787
788
789/* does this current node actually display, according to the CADLayer scheme? */
790//int is_CADLayerchild_inrange(struct X3D_CADLayer *node, struct X3D_Node *me) {
791// int i;
792// for (i=0; i<node->children.n; i++) {
793//
794// /* if we have more children than we have indexes into visible field, just return TRUE */
795// if ((i >= node->visible.n) && (node->children.p[i] == me)) return TRUE;
796//
797// /* if not, if it is in the visible field, return true */
798// else if ((node->visible.p[i]) && (node->children.p[i] == me)) return TRUE;
799// }
800// /* not visible, so return false */
801// return FALSE;
802//}
803
804/* does this current node actually fit in the GeoLOD rendering scheme? */
805int is_GeoLODchild_inrange (struct X3D_GeoLOD* gpnode, struct X3D_Node *me) {
806 /* is this node part of the active path for rendering? */
807 int x,y;
808 y = FALSE;
809
810 for (x=0; x<gpnode->rootNode.n; x++) {
811 /* printf ("comparing %u:%u %d of %d, types me %s rootNodeField: %s\n",
812 me, X3D_NODE(gpnode->rootNode.p[x]),
813 x, gpnode->rootNode.n,
814 stringNodeType (me->_nodeType),
815 stringNodeType( X3D_NODE(gpnode->rootNode.p[x])->_nodeType)
816 );
817 */
818
819 if (me == X3D_NODE(gpnode->rootNode.p[x])) {
820 y=TRUE;
821 break;
822 }
823 }
824
825/*
826 if (y) printf ("GeoLOD, found child in rootNode "); else printf ("GeoLOD, child NOT part of ROOT ");
827 if (X3D_GEOLOD(geomParent)->__inRange) printf ("INRANGE "); else printf ("NOT inrange ");
828*/
829 /* is this one actually being rendered? */
830 return (y ^ gpnode->__inRange);
831}
832
833
834/* take the measurements of a geometry (eg, box), and save it. Note
835 * that what is given is a Shape, the values get pushed up to the
836 * Geometries grouping node parent. */
837
838
839
840
841void setExtent(float maxx, float minx, float maxy, float miny, float maxz, float minz, struct X3D_Node *me) {
842 float e[6];
843 extent6f_constructor(e,minx,maxx,miny,maxy,minz,maxz);
844 extent6f_setNodeExtentB(e,me);
845}
846
847static void quaternion_multi_rotation(struct point_XYZ *ret, const Quaternion *quat, const struct point_XYZ * v, int count){
848 int i;
849 for (i=0; i<count; i++) {
850 quaternion_rotation(ret, quat, v);
851 ret++; v++;
852 }
853}
854
855
856
857static void add_translation (struct point_XYZ *arr, float x, float y, float z, int count) {
858 int i;
859 for (i=0; i<count; i++) {
860 arr->x += (double)x;
861 arr->y += (double)y;
862 arr->z += (double)z;
863 arr++;
864 }
865}
866
867static void multiply_in_scale(struct point_XYZ *arr, float x, float y, float z, int count) {
868 int i;
869 for (i=0; i<count; i++) {
870 arr->x *= (double)x;
871 arr->y *= (double)y;
872 arr->z *= (double)z;
873 arr++;
874 }
875}
876
877
878void printmatrix(GLDOUBLE* mat) {
879 int i;
880 for(i = 0; i< 16; i++) {
881 printf("mat[%d] = %4.3f%s",i,mat[i],i==3 ? "\n" : i==7? "\n" : i==11? "\n" : "");
882 }
883 printf ("\n");
884
885}
886
887
888/* for children nodes; set the parent grouping nodes extent - we expect the center
889 * of the group to be passed in in the floats x,y,z */
890
891void propagateExtent(struct X3D_Node *me) {
892}
893
894/* perform all the viewpoint rotations for a point */
895/* send in a pointer for the result, the current bounding box point to rotate, and the current ModelView matrix */
896
897void moveAndRotateThisPoint(struct point_XYZ *mypt, double x, double y, double z, double *MM) {
898 float outF[3];
899 float inF[3];
900 inF[0] = (float) x; inF[1] = (float) y; inF[2] = (float) z;
901
902 /* transform this vertex via the modelview matrix */
903 transformf (outF,inF,MM);
904
905 #ifdef VERBOSE
906 printf ("transformed %4.2f %4.2f %4.2f, to %4.2f %4.2f %4.2f\n",inF[0], inF[1], inF[2],
907 outF[0], outF[1], outF[2]);
908 #endif
909 mypt->x = outF[0]; mypt->y=outF[1],mypt->z = outF[2];
910}
911
912
913/**************************************************************************************/
914
915/* get the center of the bounding box, rotate it, and find out how far it is Z distance from us.
916*/
917
918//BBoxFields described in
919//src/lib/scenegraph/RenderFuncs.h
921 struct SFVec3f bboxCenter;
922 struct SFVec3f bboxSize;
923 int visible;
924 int bboxDisplay;
925
926};
927
928//#define FRUSTUMVERBOSE
929void record_ZBufferDistance(struct X3D_Node *node, void *bbfv) {
930 GLDOUBLE modelMatrix[16];
931 double ex;
932 double ey;
933 double ez;
934 struct point_XYZ movedPt;
935 double minMovedDist;
936
937 struct BBoxFields *bbf = (struct BBoxFields*) bbfv;
938
939 minMovedDist = -1000000000;
940
941 if (APPROX(node->EXTENT_MAX_X,-10000.0)) {
942 #ifdef FRUSTUMVERBOSE
943 printf ("record_ZBufferDistance: EXTENT NOT INIT\n");
944 #endif //FRUSTUMVERBOSE
945 return;
946 }
947
948 float extent[6];
949 bbox2extent6f(bbf->bboxCenter.c,bbf->bboxSize.c,extent);
950
951 struct X3D_Node *bb = node;
952
953 #ifdef FRUSTUMVERBOSE
954 ttrenderstate rs = renderstate();
955 //if (rs->render_geom && (!rs->render_blend)) printf ("record_ZBufferDistance, geom and !blend\n");
956
957 printf ("\nrecord_ZBufferDistance for node %p nodeType %s size %4.2f %4.2f %4.2f ",
958 node, stringNodeType (node->_nodeType),
959 node->EXTENT_MAX_X - node->EXTENT_MIN_X,
960 node->EXTENT_MAX_Y - node->EXTENT_MIN_Y,
961 node->EXTENT_MAX_Z - node->EXTENT_MIN_Z
962 );
963
964 if (node->_nodeType == NODE_Shape) {
965 printf ("NODE: %s\n",stringNodeType(X3D_SHAPE(node)->geometry->_nodeType));
966 }
967
968
969 printf ("\n");
970
971 printf ("record_ZBufferDistance, bbox size %4.3f,%4.3f,%4.3f, center %4.3f,%4.3f,%4.3f\n",
972 bbf->bboxSize.c[0], bbf->bboxSize.c[1], bbf->bboxSize.c[2],
973 bbf->bboxCenter.c[0], bbf->bboxCenter.c[1], bbf->bboxCenter.c[2]);
974
975 //float extent[6];
976 //bbox2extent6f(bbf->bboxCenter.c,bbf->bboxSize.c,extent);
977 printf ("ext6f %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f\n",
978 extent[0],extent[1],extent[2],extent[3],extent[4],extent[5]);
979 printf ("oldext %4.2f %4.2f %4.2f %4.2f %4.2f %4.2f\n",
980 node->EXTENT_MAX_X,node->EXTENT_MIN_X,
981 node->EXTENT_MAX_Y,node->EXTENT_MIN_Y,
982 node->EXTENT_MAX_Z,node->EXTENT_MIN_Z);
983
984 //if (rs->render_geom) printf ("RD, render_geom\n");
985 //if (rs->render_blend) printf ("RD, render_blend\n");
986 //if (rs->render_vp) printf ("RD, render_vp\n");
987
988 #endif
989
990 /* get the current pos in modelMatrix land */
991 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
992
993 #ifdef FRUSTUMVERBOSE
994 printf ("modelMatrix:\n");
995 printf ("\t%3.2f %3.2f %2.2f %3.2f\n",
996 modelMatrix[0],modelMatrix[1],modelMatrix[2],modelMatrix[3]);
997 printf ("\t%3.2f %3.2f %2.2f %3.2f\n",
998 modelMatrix[4],modelMatrix[5],modelMatrix[6],modelMatrix[7]);
999 printf ("\t%3.2f %3.2f %2.2f %3.2f\n",
1000 modelMatrix[8],modelMatrix[9],modelMatrix[10],modelMatrix[11]);
1001 printf ("\t%3.2f %3.2f %2.2f %3.2f\n",
1002 modelMatrix[12],modelMatrix[13],modelMatrix[14],modelMatrix[15]);
1003 #endif //FRUSTUMVERBOSE
1004
1005 //#define DO_CENTER_ONLY
1006 #ifdef DO_CENTER_ONLY
1007 moveAndRotateThisPoint (&movedPt,
1008 bbf->bboxCenter.c[0],
1009 bbf->bboxCenter.c[1],
1010 bbf->bboxCenter.c[2],
1011 modelMatrix);
1012 printf ("movd point %f %f %f\n",movedPt.x,movedPt.y,movedPt.z);
1013 minMovedDist = movedPt.z;
1014 #else
1015 #define MIN_X 0
1016 #define MAX_X 1
1017 #define MIN_Y 2
1018 #define MAX_Y 3
1019 #define MIN_Z 4
1020 #define MAX_Z 5
1021
1022 /* printf ("moving all 8 points of this bounding box\n"); */
1023 ex= extent[MIN_X];
1024 ey= extent[MIN_Y];
1025 ez= extent[MIN_Z];
1026 moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
1027 if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
1028
1029 ex= extent[MIN_X];
1030 ey= extent[MIN_Y];
1031 ez= extent[MIN_Z];
1032 moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
1033 if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
1034
1035 ex= extent[MIN_X];
1036 ey= extent[MIN_Y];
1037 ez= extent[MIN_Z];
1038 moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
1039 if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
1040
1041 ex= extent[MIN_X];
1042 ey= extent[MAX_Y];
1043 ez= extent[MAX_Z];
1044 moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
1045 if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
1046
1047 ex= extent[MAX_X];
1048 ey= extent[MIN_Y];
1049 ez= extent[MIN_Z];
1050 moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
1051 if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
1052
1053 ex= extent[MAX_X];
1054 ey= extent[MIN_Y];
1055 ez= extent[MAX_Z];
1056 moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
1057 if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
1058
1059 ex= extent[MAX_X];
1060 ey= extent[MAX_Y];
1061 ez= extent[MIN_Z];
1062 moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
1063 if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
1064
1065 ex= extent[MAX_X];
1066 ey= extent[MAX_Y];
1067 ez= extent[MAX_Z];
1068 moveAndRotateThisPoint (&movedPt, ex,ey,ez,modelMatrix);
1069 if (movedPt.z > minMovedDist) minMovedDist = movedPt.z;
1070
1071 #endif //NOT DO_CENTER_ONLY
1072 node->_dist = minMovedDist;
1073
1074#ifdef FRUSTUMVERBOSE
1075 //printf ("I am at %lf %lf %lf\n",Viewer()->currentPosInModel.x, Viewer()->currentPosInModel.y, Viewer()->currentPosInModel.z);
1076 //printf ("and distance to the nearest corner of the BB for this node is %lf\n", node->_dist);
1077#endif //FRUSTUMVERBOSE
1078
1079#undef FRUSTUMVERBOSE
1080
1081}
1082
1083/***************************************************************************/
1084
1085void OcclusionStartofRenderSceneUpdateScene() {
1086
1087#ifdef OCCLUSION /* do we have hardware for occlusion culling? */
1088 int i;
1089 ppFrustum p;
1090 ttglobal tg = gglobal();
1091 p = (ppFrustum)gglobal()->Frustum.prv;
1092 /* each time through the event loop, we count the occluders. Note, that if, say, a
1093 shape was USED 100 times, that would be 100 occlude queries, BUT ONE SHAPE, thus
1094 there is not an implicit 1:1 mapping between shapes and occlude queries */
1095
1096 p->potentialOccluderCount = 0;
1097
1098 /* did we have a failure here ? */
1099 if (tg->Frustum.OccFailed) return;
1100
1101 /* have we been through this yet? */
1102 if (p->OccInitialized == FALSE) {
1103 #ifdef OCCLUSIONVERBOSE
1104 printf ("initializing OcclusionCulling...\n");
1105 #endif
1106 /* do we have an environment variable for this? */
1107 if (gglobal()->internalc.global_occlusion_disable) {
1108 tg->Frustum.OccFailed = TRUE;
1109 } else {
1110 s_renderer_capabilities_t *rdr_caps;
1111 rdr_caps = gglobal()->display.rdr_caps;
1112 if (rdr_caps->av_occlusion_q) {
1113
1114 #ifdef OCCLUSIONVERBOSE
1115 printf ("OcclusionStartofRenderSceneUpdateScene: have OcclusionQuery\n");
1116 #endif
1117
1118 /* we make the OccQuerySize larger than the maximum number of occluders,
1119 so we don't have to realloc too much */
1120 p->OccQuerySize = p->maxOccludersFound + 1000;
1121
1122 p->occluderNodePointer = MALLOC (void **, sizeof (void *) * p->OccQuerySize);
1123 p->OccQueries = MALLOC (GLuint *, sizeof(GLuint) * p->OccQuerySize);
1124 FW_GL_GENQUERIES(p->OccQuerySize,p->OccQueries);
1125 //ConsoleMessage ("generated %d queries, pointer %p",p->OccQuerySize,p->OccQueries);
1126 p->OccInitialized = TRUE;
1127 for (i=0; i<p->OccQuerySize; i++) {
1128 p->occluderNodePointer[i] = 0;
1129 }
1130 p->QueryCount = p->maxOccludersFound; /* for queries - we can do this number */
1131 #ifdef OCCLUSIONVERBOSE
1132 printf ("QueryCount now %d\n",p->QueryCount);
1133 #endif
1134
1135 } else {
1136 #ifdef OCCLUSIONVERBOSE
1137 printf ("OcclusionStartofRenderSceneUpdateScene: DO NOT have OcclusionQuery\n");
1138 #endif
1139
1140 /* we dont seem to have this extension here at runtime! */
1141 /* this happened, eg, on my Core4 AMD64 box with Mesa */
1142 tg->Frustum.OccFailed = TRUE;
1143 return;
1144 }
1145 }
1146
1147 }
1148
1149
1150 /* did we find more shapes than before? */
1151 if (p->maxOccludersFound > p->QueryCount) {
1152 if (p->maxOccludersFound > p->OccQuerySize) {
1153 /* printf ("have to regen queries\n"); */
1154 p->QueryCount = 0;
1155
1156 /* possibly previous had zero occluders, lets just not bother deleting for zero */
1157 if (p->OccQuerySize > 0) {
1158 FW_GL_DELETEQUERIES (p->OccQuerySize, p->OccQueries);
1159 FW_GL_FLUSH();
1160 }
1161
1162 p->OccQuerySize = p->maxOccludersFound + 1000;
1163 p->occluderNodePointer = REALLOC (p->occluderNodePointer,sizeof (void *) * p->OccQuerySize);
1164 p->OccQueries = REALLOC (p->OccQueries,sizeof (GLuint) * p->OccQuerySize);
1165 FW_GL_GENQUERIES(p->OccQuerySize,p->OccQueries);
1166 ConsoleMessage ("reinitialized queries... now %p",p->OccQueries);
1167 for (i=0; i<p->OccQuerySize; i++) {
1168 p->occluderNodePointer[i] = 0;
1169 }
1170 }
1171 p->QueryCount = p->maxOccludersFound; /* for queries - we can do this number */
1172 #ifdef OCCLUSIONVERBOSE
1173 printf ("QueryCount here is %d\n",p->QueryCount);
1174 #endif
1175
1176 }
1177
1178
1179// #ifdef OCCLUSIONVERBOSE
1180// glGetQueryiv(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &p->queryCounterBits);
1181// printf ("queryCounterBits %d\n",p->queryCounterBits);
1182// #endif
1183#endif /* OCCLUSION */
1184
1185}
1186
1187void OcclusionCulling () {
1188//non-occlusion visibilitysensor method: __Samples = 0 in startofloopnodeupdates
1189#ifdef OCCLUSION /* do we have hardware for occlusion culling? */
1190 int i;
1191 struct X3D_Shape *shapePtr;
1192 struct X3D_VisibilitySensor *visSenPtr;
1193 int checkCount;
1194 GLuint samples;
1195 ppFrustum p;
1196 ttglobal tg = gglobal();
1197 p = (ppFrustum)tg->Frustum.prv;
1198
1199//#ifdef OCCLUSIONVERBOSE
1200// {
1201// GLint query;
1202// glGetQueryiv(GL_SAMPLES_PASSED, GL_CURRENT_QUERY, &query);
1203// printf ("currentQuery is %d\n",query);
1204// }
1205//#endif
1206
1207 visSenPtr = NULL;
1208 shapePtr = NULL;
1209
1210 /* Step 0. go through list of assigned nodes, and either:
1211 - if we have OcclusionQueries: REMOVE the VF_hasVisibleChildren flag;
1212 - else, set every node to VF_hasVisibleChildren */
1213 zeroVisibilityFlag();
1214
1215 /* Step 1. did we have some problem with Occlusion ? */
1216 if (tg->Frustum.OccFailed) return;
1217
1218 /* Step 2. go through the list of "OccludeCount" nodes, and determine if they are visible.
1219 If they are not, then, we have to, at some point, make them visible, so that we can test again. */
1220 /* note that the potentialOccluderCount is only incremented if the __occludeCheckCount tells us
1221 that it should be checked again - see the interplay between the eventLoop stuff in OpenGLUtils.c
1222 and the OCCLUSION* defines in headers.h - we DO NOT generate a query every time through the loop */
1223
1224 //#ifdef OCCLUSIONVERBOSE
1225 //printf ("OcclusionCulling - potentialOccluderCount %d\n",p->potentialOccluderCount);
1226 //#endif
1227
1228 for (i=0; i<p->potentialOccluderCount; i++) {
1229 #ifdef OCCLUSIONVERBOSE
1230 printf ("checking node %d of %d\n",i, p->potentialOccluderCount);
1231 #endif
1232
1233 checkCount = 0;
1234
1235 /* get the check count field for this node - see if we did a check of this */
1236 shapePtr = X3D_SHAPE(p->occluderNodePointer[i]);
1237 if (shapePtr != NULL) {
1238 if (shapePtr->_nodeType == NODE_Shape) {
1239 visSenPtr = NULL;
1240 checkCount = shapePtr->__occludeCheckCount;
1241 } else if (shapePtr->_nodeType == NODE_VisibilitySensor) {
1242 visSenPtr = X3D_VISIBILITYSENSOR(shapePtr);
1243 shapePtr = NULL;
1244 checkCount = visSenPtr->__occludeCheckCount;
1245 } else {
1246 printf ("OcclusionCulling on node type %s not allowed\n",stringNodeType(shapePtr->_nodeType));
1247 return;
1248 }
1249 }
1250
1251 #ifdef OCCLUSIONVERBOSE
1252 if (shapePtr) printf ("OcclusionCulling, for a %s (index %d ptr %p) checkCount %d\n",stringNodeType(shapePtr->_nodeType),i,shapePtr,checkCount);
1253 else printf ("OcclusionCulling, for a %s (index %d) checkCount %d\n",stringNodeType(visSenPtr->_nodeType),i,checkCount);
1254 #endif
1255
1256 /* an Occlusion test will have been run on this one */
1257
1258 FW_GL_GETQUERYOBJECTUIV(p->OccQueries[i],GL_QUERY_RESULT_AVAILABLE,&p->OccResultsAvailable);
1259 PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY_RESULTS_AVAIL");
1260
1261 #define SLEEP_FOR_QUERY_RESULTS
1262 #ifdef SLEEP_FOR_QUERY_RESULTS
1263 /* for now, lets loop to see when we get results */
1264 while (p->OccResultsAvailable == GL_FALSE) {
1265 usleep(100);
1266 FW_GL_GETQUERYOBJECTUIV(p->OccQueries[i],GL_QUERY_RESULT_AVAILABLE,&p->OccResultsAvailable);
1267 PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY_RESULTS_AVAIL");
1268 }
1269 #endif
1270
1271
1272 #ifdef OCCLUSIONVERBOSE
1273 if (p->OccResultsAvailable == GL_FALSE) printf ("results not ready for %d\n",i);
1274 #endif
1275
1276
1277 /* if we are NOT ready; we keep the count going, but we do NOT change the results of VisibilitySensors */
1278 if (p->OccResultsAvailable == GL_FALSE) samples = 10000;
1279
1280 FW_GL_GETQUERYOBJECTUIV (p->OccQueries[i], GL_QUERY_RESULT, &samples);
1281 PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY");
1282
1283 #ifdef OCCLUSIONVERBOSE
1284 printf ("i %d checkc %d samples %d\n",i,checkCount,samples);
1285 #endif
1286
1287 if (p->occluderNodePointer[i] != 0) {
1288
1289 /* if this is a VisibilitySensor, record the samples */
1290 if (visSenPtr != NULL) {
1291
1292 #ifdef OCCLUSIONVERBOSE
1293 printf ("OcclusionCulling, found VisibilitySensor at %d, fragments %d active %d\n",i,samples,checkCount);
1294 #endif
1295
1296
1297 /* if this is a DEF/USE, we might already have done this one, as we have same
1298 node pointer used in other places. */
1299 if (checkCount != OCCCHECKNEXTLOOP) {
1300
1301 if (samples > 0) {
1302 visSenPtr->__visible = TRUE;
1303 visSenPtr->__occludeCheckCount = OCCCHECKNEXTLOOP; /* look for this EVERY time through */
1304 visSenPtr->__Samples = samples;
1305 } else {
1306 visSenPtr->__occludeCheckCount = OCCCHECKSOON; /* check again soon */
1307 visSenPtr->__visible =FALSE;
1308 visSenPtr->__Samples = 0;
1309 }
1310
1311 /* } else {
1312 printf ("shape, already have checkCount == OCCCHECKNEXTLOOP, not changing visibility params\n");
1313
1314 */
1315 }
1316 }
1317
1318
1319 /* is this is Shape? */
1320 else if (shapePtr != NULL) {
1321 #ifdef OCCLUSIONVERBOSE
1322 printf ("OcclusionCulling, found Shape %d, fragments %d active %d\n",i,samples,checkCount);
1323 #endif
1324 //if (samples == 0) ConsoleMessage ("invisible shape %d, fragments %d",i,samples);
1325
1326 /* if this is a DEF/USE, we might already have done this one, as we have same
1327 node pointer used in other places. */
1328 if (checkCount != OCCWAIT) {
1329
1330 /* is this node visible? If so, tell the parents! */
1331 if (samples > OCCSHAPESAMPLESIZE) {
1332 TRACE_MSG ("Shape %p is VISIBLE\n",shapePtr);
1333 shapePtr->__visible = TRUE;
1334 shapePtr->__occludeCheckCount= OCCWAIT; /* wait a little while before checking again */
1335 shapePtr->__Samples = samples;
1336 } else {
1337 TRACE_MSG ("Shape %p is NOT VISIBLE\n",shapePtr);
1338 shapePtr->__visible=FALSE;
1339 shapePtr->__occludeCheckCount = OCCCHECKSOON; /* check again soon */
1340 shapePtr->__Samples = 0;
1341 }
1342 /* } else {
1343 printf ("shape, already have checkCount == OCCWAIT, not changing visibility params\n");
1344 */
1345 }
1346 }
1347 }
1348 }
1349#endif /* OCCLUSION */
1350}
1351
1352/* shut down the occlusion stuff */
1353void zeroOcclusion(void) {
1354
1355#ifdef OCCLUSION /* do we have hardware for occlusion culling? */
1356
1357 int i;
1358 ppFrustum p;
1359 ttglobal tg = gglobal();
1360 p= (ppFrustum)tg->Frustum.prv;
1361
1362 if (tg->Frustum.OccFailed) return;
1363
1364 #ifdef OCCLUSIONVERBOSE
1365 printf ("zeroOcclusion - potentialOccluderCount %d\n",p->potentialOccluderCount);
1366 #endif
1367
1368 for (i=0; i<p->potentialOccluderCount; i++) {
1369#ifdef OCCLUSIONVERBOSE
1370 printf ("checking node %d of %d\n",i, p->potentialOccluderCount);
1371#endif
1372
1373 FW_GL_GETQUERYOBJECTUIV(p->OccQueries[i],GL_QUERY_RESULT_AVAILABLE,&p->OccResultsAvailable);
1374 PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY_RESULTS_AVAIL");
1375#ifdef SLEEP_FOR_QUERY_RESULTS
1376 /* for now, lets loop to see when we get results */
1377 while (p->OccResultsAvailable == GL_FALSE) {
1378#ifdef OCCLUSIONVERBOSE
1379 printf ("zero - waiting and looping for results\n");
1380#endif
1381 usleep(1000);
1382 FW_GL_GETQUERYOBJECTUIV(p->OccQueries[i],GL_QUERY_RESULT_AVAILABLE,&p->OccResultsAvailable);
1383 PRINT_GL_ERROR_IF_ANY("FW_GL_GETQUERYOBJECTUIV::QUERY_RESULTS_AVAIL");
1384 }
1385#endif
1386 }
1387#ifdef OCCLUSIONVERBOSE
1388 printf ("zeroOcclusion - done waiting\n");
1389#endif
1390
1391 p->QueryCount = 0;
1392
1393 // debugging
1394 //if (p->OccQueries) {
1395 // ConsoleMessage ("p->OccQueries exists, p->OccQuerySize %p, p->OccQueries %p",p->OccQuerySize, p->OccQueries);
1396 //}
1397 //if(p->OccQueries)
1398 //glDeleteQueries (p->OccQuerySize, p->OccQueries);
1399 //FW_GL_FLUSH();
1400
1401 p->OccQuerySize=0;
1402 p->maxOccludersFound = 0;
1403 p->OccInitialized = FALSE;
1404 p->potentialOccluderCount = 0;
1405 //ConsoleMessage ("freeing OccQueries %p",p->OccQueries);
1406 FREE_IF_NZ(p->OccQueries);
1407 FREE_IF_NZ(p->occluderNodePointer);
1408#endif /* OCCLUSION */
1409}