FreeWRL / FreeX3D 4.3.0
Component_EnvironSensor.c
1/*
2
3
4X3D Environmental Sensors Component
5
6*/
7
8
9/****************************************************************************
10 This file is part of the FreeWRL/FreeX3D Distribution.
11
12 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13
14 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15 it under the terms of the GNU Lesser Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26****************************************************************************/
27
28
29
30#include <config.h>
31#include <system.h>
32#include <display.h>
33#include <internal.h>
34
35#include <libFreeWRL.h>
36
37#include "../vrml_parser/Structs.h"
38#include "../vrml_parser/CRoutes.h"
39#include "../main/headers.h"
40
41#include "LinearAlgebra.h"
42#include "Component_Geospatial.h"
43#include "../opengl/Frustum.h"
44#include "../opengl/OpenGL_Utils.h"
45#include "../scenegraph/Component_Shape.h"
46#include "../scenegraph/RenderFuncs.h"
47
49//int candoVisibility = TRUE;
51 /* can we do a VisibiltySensor? Only if we have OpenGL support for OcclusionCulling */
52 int candoVisibility;// = TRUE;
53
55
56static void *Component_EnvironSensor_constructor(){
57 void *v = MALLOCV(sizeof(struct pComponent_EnvironSensor));
58 memset(v,0,sizeof(struct pComponent_EnvironSensor));
59 return v;
60}
61
62// iglobal.c calls this one.
63void Component_EnvironSensor_init(struct tComponent_EnvironSensor *t){
64 //public
65 //private
66 t->prv = Component_EnvironSensor_constructor();
67 {
69 /* can we do a VisibiltySensor? Only if we have OpenGL support for OcclusionCulling */
70 p->candoVisibility = TRUE;
71
72 }
73}
74
75#ifdef VISIBILITYOCCLUSION
76
77static void rendVisibilityBox (struct X3D_VisibilitySensor *node);
78#endif
79
80//PROXIMITYSENSOR(ProximitySensor,center,,);
81
82/* ProximitySensor and GeoProximitySensor are same "code" at this stage of the game */
83//#define PROXIMITYSENSOR(type,center,initializer1,initializer2)
84void render_ProximitySensor (struct X3D_ProximitySensor *node) {
85 //just for rendering the extent/bounding box
86 if(renderstate()->render_boxes) extent6f_draw(node->_extent);
87}
88void proximity_ProximitySensor (struct X3D_ProximitySensor *node) {
89 /* Viewer pos = t_r2 */
90 double cx,cy,cz;
91 double len;
92 struct point_XYZ dr1r2;
93 struct point_XYZ dr2r3;
94 struct point_XYZ nor1,nor2;
95 struct point_XYZ ins;
96 static const struct point_XYZ yvec = {0,0.05,0};
97 static const struct point_XYZ zvec = {0,0,-0.05};
98 static const struct point_XYZ zpvec = {0,0,0.05};
99 static const struct point_XYZ orig = {0,0,0};
100 struct point_XYZ t_zvec, t_yvec, t_orig, t_center;
101 GLDOUBLE modelMatrix[16];
102 GLDOUBLE projMatrix[16];
103 GLDOUBLE view2prox[16];
104
105 if(!((node->enabled))) return;
106 //initializer1
107 //initializer2
108
109 /* printf (" vp %d geom %d light %d sens %d blend %d prox %d col %d\n",*/
110 /* render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision);*/
111
112 /* transforms viewers coordinate space into sensors coordinate space.
113 * this gives the orientation of the viewer relative to the sensor.
114 */
115 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
116 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, projMatrix);
117 FW_GLU_UNPROJECT(orig.x,orig.y,orig.z,modelMatrix,projMatrix,viewport,
118 &t_orig.x,&t_orig.y,&t_orig.z);
119 FW_GLU_UNPROJECT(zvec.x,zvec.y,zvec.z,modelMatrix,projMatrix,viewport,
120 &t_zvec.x,&t_zvec.y,&t_zvec.z);
121 FW_GLU_UNPROJECT(yvec.x,yvec.y,yvec.z,modelMatrix,projMatrix,viewport,
122 &t_yvec.x,&t_yvec.y,&t_yvec.z);
123 matinverse(view2prox,modelMatrix);
124 transform(&t_center,&orig, view2prox);
125
126
127 /*printf ("\n");
128 printf ("unprojected, t_orig (0,0,0) %lf %lf %lf\n",t_orig.x, t_orig.y, t_orig.z);
129 printf ("unprojected, t_yvec (0,0.05,0) %lf %lf %lf\n",t_yvec.x, t_yvec.y, t_yvec.z);
130 printf ("unprojected, t_zvec (0,0,-0.05) %lf %lf %lf\n",t_zvec.x, t_zvec.y, t_zvec.z);
131 */
132 cx = t_center.x - ((node->center ).c[0]);
133 cy = t_center.y - ((node->center ).c[1]);
134 cz = t_center.z - ((node->center ).c[2]);
135
136 if(((node->size).c[0]) == 0 || ((node->size).c[1]) == 0 || ((node->size).c[2]) == 0) return;
137 {
138 float cc[3];
139 vecscale3f(cc,node->size.c,.5);
140 extent6f_constructor(node->_extent,-cc[0],cc[0],-cc[1],cc[1],-cc[2],cc[2]);
141 }
142 if(fabs(cx) > ((node->size).c[0])/2 ||
143 fabs(cy) > ((node->size).c[1])/2 ||
144 fabs(cz) > ((node->size).c[2])/2) {
145 //printf ("outside (Geo)ProximitySensor\n");
146 return;
147 }
148 //printf ("within (Geo)ProximitySensor\n");
149
150 /* Ok, we now have to compute... */
151 (node->__hit) = 1;
152
153 /* Position */
154 ((node->__t1).c[0]) = (float)t_center.x;
155 ((node->__t1).c[1]) = (float)t_center.y;
156 ((node->__t1).c[2]) = (float)t_center.z;
157
158 VECDIFF(t_zvec,t_orig,dr1r2); /* Z axis */
159 VECDIFF(t_yvec,t_orig,dr2r3); /* Y axis */
160
161 /* printf (" dr1r2 %lf %lf %lf\n",dr1r2.x, dr1r2.y, dr1r2.z);
162 printf (" dr2r3 %lf %lf %lf\n",dr2r3.x, dr2r3.y, dr2r3.z);
163 */
164
165 len = sqrt(VECSQ(dr1r2)); VECSCALE(dr1r2,1/len);
166 len = sqrt(VECSQ(dr2r3)); VECSCALE(dr2r3,1/len);
167
168 /* printf ("scaled dr1r2 %lf %lf %lf\n",dr1r2.x, dr1r2.y, dr1r2.z);
169 printf ("scaled dr2r3 %lf %lf %lf\n",dr2r3.x, dr2r3.y, dr2r3.z);
170 */
171
172 /*
173 printf("PROX_INT: (%f %f %f) (%f %f %f) (%f %f %f)\n (%f %f %f) (%f %f %f)\n",
174 t_orig.x, t_orig.y, t_orig.z,
175 t_zvec.x, t_zvec.y, t_zvec.z,
176 t_yvec.x, t_yvec.y, t_yvec.z,
177 dr1r2.x, dr1r2.y, dr1r2.z,
178 dr2r3.x, dr2r3.y, dr2r3.z
179 );
180 */
181
182 if(fabs(VECPT(dr1r2, dr2r3)) > 0.001) {
183 printf ("Sorry, can't handle unevenly scaled ProximitySensors yet :("
184 "dp: %f v: (%f %f %f) (%f %f %f)\n", VECPT(dr1r2, dr2r3),
185 dr1r2.x,dr1r2.y,dr1r2.z,
186 dr2r3.x,dr2r3.y,dr2r3.z
187 );
188 return;
189 }
190
191
192 if(APPROX(dr1r2.z,1.0)) {
193 /* rotation */
194 ((node->__t2).c[0]) = (float) 0;
195 ((node->__t2).c[1]) = (float) 0;
196 ((node->__t2).c[2]) = (float) 1;
197 ((node->__t2).c[3]) = (float) atan2(-dr2r3.x,dr2r3.y);
198 } else if(APPROX(dr2r3.y,1.0)) {
199 /* rotation */
200 ((node->__t2).c[0]) = (float) 0;
201 ((node->__t2).c[1]) = (float) 1;
202 ((node->__t2).c[2]) = (float) 0;
203 ((node->__t2).c[3]) = (float) atan2(dr1r2.x,dr1r2.z);
204 } else {
205 /* Get the normal vectors of the possible rotation planes */
206 nor1 = dr1r2;
207 nor1.z -= 1.0;
208 nor2 = dr2r3;
209 nor2.y -= 1.0;
210
211 /* Now, the intersection of the planes, obviously cp */
212 VECCP(nor1,nor2,ins);
213
214 len = sqrt(VECSQ(ins)); VECSCALE(ins,1/len);
215
216 /* the angle */
217 VECCP(dr1r2,ins, nor1);
218 VECCP(zpvec, ins, nor2);
219 len = sqrt(VECSQ(nor1)); VECSCALE(nor1,1/len);
220 len = sqrt(VECSQ(nor2)); VECSCALE(nor2,1/len);
221 VECCP(nor1,nor2,ins);
222
223 ((node->__t2).c[3]) = (float) -atan2(sqrt(VECSQ(ins)), VECPT(nor1,nor2));
224
225 /* rotation - should normalize sometime... */
226 ((node->__t2).c[0]) = (float) ins.x;
227 ((node->__t2).c[1]) = (float) ins.y;
228 ((node->__t2).c[2]) = (float) ins.z;
229 }
230 /*
231 printf("NORS: (%f %f %f) (%f %f %f) (%f %f %f)\n",
232 nor1.x, nor1.y, nor1.z,
233 nor2.x, nor2.y, nor2.z,
234 ins.x, ins.y, ins.z
235 );
236 */
237}
238
239
240
241
242/* ProximitySensor code for ClockTick */
243void do_ProximitySensorTick( void *ptr) {
244 struct X3D_ProximitySensor *node = (struct X3D_ProximitySensor *)ptr;
245
246 /* if not enabled, do nothing */
247 if (!node) return;
248 if (node->__oldEnabled != node->enabled) {
249 node->__oldEnabled = node->enabled;
250 MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_ProximitySensor, enabled));
251 }
252 if (!node->enabled) return;
253
254 /* did we get a signal? */
255 if (node->__hit) {
256 //avatar inside proximity sensor
257 if (!node->isActive) {
258 #ifdef SEVERBOSE
259 printf ("PROX - initial defaults\n");
260 #endif
261
262 node->isActive = TRUE;
263 node->enterTime = TickTime();
264 MARK_EVENT (ptr, offsetof(struct X3D_ProximitySensor, isActive));
265 MARK_EVENT (ptr, offsetof(struct X3D_ProximitySensor, enterTime));
266 }
267
268 /* now, has anything changed? */
269 if (memcmp ((void *) &node->position_changed,(void *) &node->__t1,sizeof(struct SFColor))) {
270 #ifdef SEVERBOSE
271 printf ("PROX - position changed!!! \n");
272 #endif
273
274 memcpy ((void *) &node->position_changed,
275 (void *) &node->__t1,sizeof(struct SFColor));
276 MARK_EVENT (ptr, offsetof(struct X3D_ProximitySensor, position_changed));
277 }
278 if (memcmp ((void *) &node->orientation_changed, (void *) &node->__t2,sizeof(struct SFRotation))) {
279 #ifdef SEVERBOSE
280 printf ("PROX - orientation changed!!!\n ");
281 #endif
282
283 memcpy ((void *) &node->orientation_changed,
284 (void *) &node->__t2,sizeof(struct SFRotation));
285 MARK_EVENT (ptr, offsetof(struct X3D_ProximitySensor, orientation_changed));
286 }
287 } else {
288 //avatar outside proximity sensor or not enabled
289 if (node->isActive) {
290 #ifdef SEVERBOSE
291 printf ("PROX - stopping\n");
292 #endif
293
294 node->isActive = FALSE;
295 node->exitTime = TickTime();
296 MARK_EVENT (ptr, offsetof(struct X3D_ProximitySensor, isActive));
297
298 MARK_EVENT (ptr, offsetof(struct X3D_ProximitySensor, exitTime));
299 }
300 }
301 node->__hit=FALSE;
302}
303
304
305
306void transformMBB(GLDOUBLE *rMBBmin, GLDOUBLE *rMBBmax, GLDOUBLE *matTransform, GLDOUBLE* inMBBmin, GLDOUBLE* inMBBmax);
307int transformMBB4d(GLDOUBLE *rMBBmin, GLDOUBLE *rMBBmax, GLDOUBLE *matTransform, GLDOUBLE* inMBBmin, GLDOUBLE* inMBBmax, int isAffine);
308int __gluInvertMatrixd(const GLDOUBLE m[16], GLDOUBLE invOut[16]);
309void __gluMultMatrixVecd(const GLDOUBLE matrix[16], const GLDOUBLE in[4], GLDOUBLE out[4]);
310
311
312static void twoPoints2RayMatrix(double *ptnear, double* ptfar, double* rayMatrix){
313 double R1[16], R2[16], R3[16], T[16], rayMatrixInverse[16];
314 double *A, *B, C[3];
315 double yaw, pitch;
316
317 A = ptnear;
318 B = ptfar;
319 //nearside point
320 mattranslate(T,A[0],A[1],A[2]);
321 vecdifd(C,B,A);
322 vecnormald(C,C);
323 if(0) printf("Cdif %f %f %f\n",C[0],C[1],C[2]);
324 yaw = atan2(C[0],-C[2]);
325 matrixFromAxisAngle4d(R1, -yaw, 0.0, 1.0, 0.0);
326 transformAFFINEd(C,C,R1);
327 if(0) printf("Yawed Cdif %f %f %f\n",C[0],C[1],C[2]);
328 pitch = atan2(C[1],-C[2]);
329 if(0) printf("atan2 yaw=%f pitch=%f\n",yaw,pitch);
330 pitch = -pitch;
331 if(0) printf("[yaw=%f pitch=%f\n",yaw,pitch);
332
333 matrixFromAxisAngle4d(R1, pitch, 1.0, 0.0, 0.0);
334 if(0) printmatrix2(R1,"pure R1");
335 matrixFromAxisAngle4d(R2, yaw, 0.0, 1.0, 0.0);
336 if(0) printmatrix2(R2,"pure R2");
337 matmultiplyAFFINE(R3,R1,R2);
338 if(0) printmatrix2(R3,"R3=R1*R2");
339 matmultiplyAFFINE(rayMatrixInverse,R3, T);
340 matinverseAFFINE(rayMatrix,rayMatrixInverse);
341
342}
343
344static int frustumHitsMBB(float *extent){
345 //goal say if an extent is maybe inside (err toward inside) of the view frustum
346 //http://cgvr.informatik.uni-bremen.de/teaching/cg_literatur/lighthouse3d_view_frustum_culling/index.html
347 // overlap tests: https://developer.mozilla.org/en-US/docs/Games/Techniques/3D_collision_detection
348 // cuboid space: frustum is a -1 to 1 cube
349 GLDOUBLE modelMatrix[16], projectionMatrix[16];
350 int i,isIn;
351 GLDOUBLE smin[3], smax[3], shapeMBBmin[3], shapeMBBmax[3];
352
353 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
354 FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, projectionMatrix);
355
356 /* generate mins and maxes for avatar cylinder in avatar space to represent the avatar collision volume */
357 for(i=0;i<3;i++)
358 {
359 shapeMBBmin[i] = extent[i*2 + 1];
360 shapeMBBmax[i] = extent[i*2];
361 }
362 //check view space is it behind the frontplane / viewpoint
363 transformMBB(smin,smax,modelMatrix,shapeMBBmin,shapeMBBmax); //transform shape's MBB into view space
364 isIn = TRUE;
365 isIn = smin[2] < 0.0; //-z is in front of viewpoint
366 if(isIn){
367 //plane check: rotate so lower left corner of screen is in center and do xy comparison
368 // repeat for upper-right
369 /*
370 frustum-plane aligned method
371 - in view space (apply modelview, but not projection)
372 - plus a translation and rotation so looking straight down a side of frustum
373 - then can do simple X or Y test if something is out
374 - to reduce flops, can rotate so looking down corner-edge (2 planes intersect) and do X,Y
375 - then only need 2 runs to check 4 planes
376 How: - (similar to pickray-style matrix method - see mainloop.c setup_pickray0() about line 5409 july 2016)
377 1. generate near+far frustum corner points:
378 - unproject a couple of cuboid points along a corner of the frustom: x-1,y-1, near (z=1) and far (z=-1 or vice versa)
379 2. from the 2 points compute a yaw, and a pitch, using atan2 etc
380 3. make a rotation matrix from yaw and pitch
381 4. from the near point make a Translation
382 5. multiply the rotation and translation
383 6. maybe inverse, depending on which way you're going.
384 7. then you could concatonate that matrix with your modelview
385 8. transform your geom node extent using this concatonated matrix
386 9. check transformed shape MBB/AABB against x=0 and y=0 planes: if to the left, then out, if above then out.
387 10. repeat for diagonal edge/corner of frustum x=1,y=1 in cuboid space
388 11. check near and far planes if you want to, although near is done by cone planes except a little near-cone, and far: who cares.
389 */
390 int k;
391 double rayMatrix[16], modelMatrixPlus[16], projInverse[16], nearplane, farplane;
392 double A[4], B[4], a[4], b[4];
393
394 //we are working in something close to view space, so
395 //-transform frustum cuboid to view via projection inverse, to set up 'plus'
396 //-transform node extent to view via modelview matrix, 'plus' a bit to align with frustum
397
398 // OLDCODE iret = __gluInvertMatrixd( projectionMatrix, projInverse);
399
400 //k: from lower-left corner of frustum to upper-right corner...
401 for(k=-1;k<=1;k+=2)
402 {
403 double xy;
404 xy = 1.0*k; //use -1,-1 for lower-left, 1,1 for upper-right
405 a[0] = a[1] = b[0] = b[1] = xy;
406 a[3] = b[3] = 1.0; //homogenous .w for full 4x4
407
408 //nearside point
409 a[2] = -1.0;
410 __gluMultMatrixVecd(projInverse, a, A);
411 vecscaled(A,A,1.0/A[3]); //divide by homogenous .w
412 nearplane = A[2]; //near and far set elsewhere: ie .1 - 21000, here we recover nearplane, could use for testing
413
414 //farside point
415 b[2] = 1.0;
416 __gluMultMatrixVecd(projInverse, b, B);
417 vecscaled(B,B,1.0/B[3]);
418 farplane = B[2];
419
420 twoPoints2RayMatrix(A,B,rayMatrix); //compute 'plus' part
421
422 matmultiplyAFFINE(modelMatrixPlus,modelMatrix,rayMatrix);
423
424 //transform shape's MBB into frustum-plane (frustum corner) aligned space
425 transformMBB(smin,smax,modelMatrixPlus,shapeMBBmin,shapeMBBmax);
426 //now fustum corner is at xy 0,0, so its a simple xy test against 0
427 for(i=0;i<2;i++){
428 if(k==-1)
429 isIn = isIn && smax[i] > 0.0;
430 if(k==1)
431 isIn = isIn && smin[i] < 0.0;
432 }
433 }
434 if(isIn){
435 //check near and far planes
436 transformMBB(smin,smax,modelMatrix,shapeMBBmin,shapeMBBmax);
437 isIn = isIn && smin[2] < nearplane; //these are -ve numbers - z is positive backwards
438 isIn = isIn && smax[2] > farplane;
439 }
440 }
441
442 return isIn;
443}
444
445
446void other_VisibilitySensor (struct X3D_VisibilitySensor *node) {
447 // http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/envsensor.html#VisibilitySensor
448 //ttrenderstate rs;
449 ttglobal tg = gglobal();
450 /* if not enabled, do nothing */
451 if (!node) return;
452 if (!node->enabled)
453 return;
454 {
455 ppComponent_EnvironSensor p = (ppComponent_EnvironSensor)tg->Component_EnvironSensor.prv;
456 if (!p->candoVisibility) return;
457 //aabb method
458 /* first time through, if we have a visibility sensor, but do not have the OpenGL ability to
459 use it, we print up a console message */
460 //1. transform local axix-aligned bounding box AABB from local to cuboid
461 // cuboid_aabb = projection * modelview * local_aabb
462 //2. intersect cuboid_aabb with cuboid which is -1 to 1 in 3 dimensions
463 //3. if they don't intersect, not visible, else maybe visible
464 {
465 //update extent in case size or center changed
466 int i, ihit;
467 float emin[3], emax[3];
468 vecadd3f(emax, node->center.c, node->size.c);
469 vecdif3f(emin, node->center.c, node->size.c);
470 for(i=0;i<3;i++)
471 {
472 node->_extent[i*2 + 1] = emin[i];
473 node->_extent[i*2] = emax[i];
474 }
475 ihit = frustumHitsMBB(node->_extent);
476 if(ihit){
477 node->__Samples++; //initialized to 0 once each frame elsewhere
478 //can come in here multiple times per frame: once per each viewport (stereo 2, quad 4) x once per each DEF/USE
479 //if any DEF/USE or viewport visible, then __visible = TRUE:
480 //if visibility was different on last frame, then send events
481
482 }
483 }
484
485#ifdef VISIBILITYOCCLUSION
486 //occlusion method
487 if (tg->Frustum.OccFailed) {
488 p->candoVisibility = FALSE;
489 ConsoleMessage("VisibilitySensor: OpenGL on this machine does not support GL_ARB_occlusion_query");
490 return;
491 }
492
493 rs = renderstate();
494 RECORD_DISTANCE
495
496 if (rs->render_blend) {
497
498 //BEGINOCCLUSIONQUERY
499 beginOcclusionQuery(node,renderstate()->render_geom);
500 LIGHTING_OFF
501 DISABLE_CULL_FACE
502
503 rendVisibilityBox(node);
504
505 ENABLE_CULL_FACE
506 LIGHTING_ON
507
508 //ENDOCCLUSIONQUERY
509 endOcclusionQuery(node,renderstate()->render_geom);
510 }
511#endif
512 }
513}
514
515
516#ifdef VISIBILITYOCCLUSION
517
518static void rendVisibilityBox (struct X3D_VisibilitySensor *node) {
519#ifdef HAVE_TO_REIMPLEMENT
520 extern GLfloat boxnorms[]; /* in CFuncs/statics.c*/
521 float *pt;
522 float x = ((node->size).c[0])/2;
523 float y = ((node->size).c[1])/2;
524 float z = ((node->size).c[2])/2;
525 float cx = node->center.c[0];
526 float cy = node->center.c[1];
527 float cz = node->center.c[2];
528
529 /* test for <0 of sides */
530 if ((x < 0) || (y < 0) || (z < 0)) return;
531
532 /* for BoundingBox calculations */
533 setExtent(cx+x, cx-x, cx+y, cx-y, cx+z, cx-z,X3D_NODE(node));
534
535
536 /* printf ("VISIBILITY BOXc vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
537 render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision); */
538
539 if NODE_NEEDS_COMPILING {
540 /* have to regen the shape*/
541 MARK_NODE_COMPILED
542
543 /* MALLOC memory (if possible)*/
544 /* do not worry about the __points.n field; we know the size by default */
545 if (!node->__points.p) node->__points.p = MALLOC (struct SFVec3f*, sizeof(struct SFVec3f)*(36));
546
547
548 /* now, create points; 4 points per face.*/
549 pt = (float *) node->__points.p;
550
551 #define PTF0 *pt++ = cx+x; *pt++ = cy+y; *pt++ = cz+z;
552 #define PTF1 *pt++ = cx-x; *pt++ = cy+y; *pt++ = cz+z;
553 #define PTF2 *pt++ = cx-x; *pt++ = cy-y; *pt++ = cz+z;
554 #define PTF3 *pt++ = cx+x; *pt++ = cy-y; *pt++ = cz+z;
555 #define PTR0 *pt++ = cx+x; *pt++ = cy+y; *pt++ = cz-z;
556 #define PTR1 *pt++ = cx-x; *pt++ = cy+y; *pt++ = cz-z;
557 #define PTR2 *pt++ = cx-x; *pt++ = cy-y; *pt++ = cz-z;
558 #define PTR3 *pt++ = cx+x; *pt++ = cy-y; *pt++ = cz-z;
559
560
561 PTF0 PTF1 PTF2 PTF0 PTF2 PTF3 /* front */
562 PTR2 PTR1 PTR0 PTR3 PTR2 PTR0 /* back */
563 PTF0 PTR0 PTR1 PTF0 PTR1 PTF1 /* top */
564 PTF3 PTF2 PTR2 PTF3 PTR2 PTR3 /* bottom */
565 PTF0 PTF3 PTR3 PTF0 PTR3 PTR0 /* right */
566 PTF1 PTR1 PTR2 PTF1 PTR2 PTF2 /* left */
567
568 /* finished, and have good data */
569 }
570
571 FW_GL_DEPTHMASK(FALSE);
572 /* note the ALPHA of zero - totally transparent */
573
574 //OLDCODE FW_GL_COLOR4F(0.0f, 1.0f, 0.0f, 0.0f);
575
576 /* Draw it; assume VERTEX and NORMALS already defined.*/
577 FW_GL_VERTEX_POINTER(3,GL_FLOAT,0,(GLfloat *)node->__points.p);
578 FW_GL_NORMAL_POINTER(GL_FLOAT,0,boxnorms);
579
580 /* do the array drawing; sides are simple 0-1-2-3, 4-5-6-7, etc quads */
581 sendArraysToGPU (GL_TRIANGLES, 0, 36);
582 FW_GL_DEPTHMASK(TRUE);
583#endif// HAVE_TO_REIMPLEMENT
584}
585#endif // VISIBILITYOCCLUSION
586
587
588void do_VisibilitySensorTick (void *ptr) {
589 struct X3D_VisibilitySensor *node = (struct X3D_VisibilitySensor *) ptr;
590
591 /* if not enabled, do nothing */
592 if (!node) return;
593 if (node->__oldEnabled != node->enabled) {
594 node->__oldEnabled = node->enabled;
595 MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_VisibilitySensor, enabled));
596 }
597 if (!node->enabled) return;
598 /* are we enabled? */
599
600 #ifdef SEVERBOSE
601 printf ("do_VisibilitySensorTick, samples %d\n",node->__samples);
602 #endif
603
604 if (node->__Samples > 0) {
605 if (!node->isActive) {
606 #ifdef SEVERBOSE
607 printf ("visibilitysensor - now active\n");
608 #endif
609
610 node->isActive = 1;
611 node->enterTime = TickTime();
612 MARK_EVENT (ptr, offsetof(struct X3D_VisibilitySensor, isActive));
613 MARK_EVENT (ptr, offsetof(struct X3D_VisibilitySensor, enterTime));
614 }
615 } else {
616 if (node->isActive) {
617 #ifdef SEVERBOSE
618 printf ("visibilitysensor - going inactive\n");
619 #endif
620
621 node->isActive = 0;
622 node->exitTime = TickTime();
623 MARK_EVENT (ptr, offsetof(struct X3D_VisibilitySensor, isActive));
624 MARK_EVENT (ptr, offsetof(struct X3D_VisibilitySensor, exitTime));
625 }
626 }
627 node->__Samples = 0; //clear for next frame count
628}
629/* don't need - all done in do_TransformSensor
630void other_TransformSensor (struct X3D_TransformSensor *node) {
631 // if not enabled, do nothing
632 if (!node) return;
633 if (!node->enabled)
634 return;
635
636 {
637 //aabb method
638 //1. transform local axix-aligned bounding box AABB from local to cuboid
639 // cuboid_aabb = projection * modelview * local_aabb
640 //2. intersect cuboid_aabb with cuboid which is -1 to 1 in 3 dimensions
641 //3. if they don't intersect, not visible, else maybe visible
642 {
643 //update extent in case size or center changed
644 int i, ihit;
645 float emin[3], emax[3];
646 vecadd3f(emax, node->center.c, node->size.c);
647 vecdif3f(emin, node->center.c, node->size.c);
648 for(i=0;i<3;i++)
649 {
650 node->_extent[i*2 + 1] = emin[i];
651 node->_extent[i*2] = emax[i];
652 }
654 //if(ihit){
655 //}
656 }
657 }
658}
659*/
660 int overlapMBBs(GLDOUBLE *MBBmin1, GLDOUBLE *MBBmax1, GLDOUBLE *MBBmin2, GLDOUBLE* MBBmax2);
661
662/*
663TransformSensor
664 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/envsensor.html#TransformSensor
665 - added in specs v3.2
666 - a targetObject (Node) can be USEd in multiple places, each place with a different modelview matrix state
667 - so how implement on the node end? This is similar/analogous to the problem with the picksensor component:
668 freewrl is great at viewer / node interactions, but not node/node. we seem to be missing something. But what?
669 - a more general node/node interaction table for picksensors, transformsensors and any other node-node interaction
670 General USE-USE system
671 how:
672 1) renderfuncs struct USEHIT { node *node; modelviewMatrix mvm; }
673 functions: usehit_add(node*,mvm,flag), USEHIT = usehit_next(node*); usehit_clear();
674 2) (sensornode*,do_sensorfunc) tuple registered, sensornode knows target node and
675 a) flags target and self on one pass with VF_USE,
676 b) then searches on next pass for self and other in double loop and does all USE_USE combinations
677 c) end of do_first() calls usehit_clear() for fresh transforms on next pass
678*/
679
680
681// ticks are a good place to summarize activites from various places around the scenegraph
682// do_tick is called once per frame, from outside of render_hier, so there's no modelview matrix on stack
683// http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/envsensor.html#TransformSensor
684// "Instanced (DEF/USE) TransformSensor nodes use the union of all the boxes to check for enter and exit."
685void do_TransformSensorTick (void *ptr) {
686 int ishit,i;
687 usehit *mehit, *uhit;
688 struct X3D_Node *unode,*menode;
689 struct X3D_TransformSensor *node = (struct X3D_TransformSensor *) ptr;
690
691 // if not enabled, do nothing
692 if (!node) return;
693 if (node->__oldEnabled != node->enabled) {
694 node->__oldEnabled = node->enabled;
695 MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_TransformSensor, enabled));
696 }
697 // are we enabled?
698 if (!node->enabled) return;
699 //if the sensor has zero size its equivalent to not-enabled - can't send events accroding to specs
700 if(((node->size).c[0]) <= 0.0f || ((node->size).c[1]) <= 0.0f || ((node->size).c[2]) <= 0.0f) return;
701
702 #ifdef SEVERBOSE
703 printf ("do_TransformSensorTick enabled\n");
704 #endif
705
706 //temp clear hit flag
707 ishit = 0;
708 mehit = NULL;
709 unode = node->targetObject;
710 menode = (struct X3D_Node*)node; //upcaste
711 if(unode){
712 //check all USE-USE combinations of this node and targetObject
713 //find next this
714 while((mehit = usehit_next(menode,mehit))){
715 //int iret;
716 double meinv[16],memin[3],memax[3];
717 float emin[3], emax[3], halfsize[3];
718
719 matinverseAFFINE(meinv,mehit->mvm);
720 //iret = __gluInvertMatrixd( mehit->mvm, meinv);
721
722 if(0){
723 //check inverse
724 double ident[16];
725 int j;
726 matmultiplyAFFINE(ident,meinv,mehit->mvm);
727
728 printf("inverse check do_TransformSensor\n");
729 for(i=0;i<4;i++){
730 for(j=0;j<4;j++) printf("%lf ",ident[i*3+j]);
731 printf("\n");
732 }
733 printf("\n");
734 }
735 //update extent on me, in case center or size has changed
736 vecscale3f(halfsize,node->size.c,.5f);
737 vecadd3f(emax, node->center.c, halfsize);
738 vecdif3f(emin, node->center.c, halfsize);
739 for(i=0;i<3;i++)
740 {
741 node->_extent[i*2 + 1] = emin[i];
742 node->_extent[i*2] = emax[i];
743 }
744 for(i=0;i<3;i++)
745 {
746 memin[i] = node->_extent[i*2 + 1];
747 memax[i] = node->_extent[i*2];
748 }
749
750 //find next target
751 uhit = NULL;
752 while((uhit = usehit_next(unode,uhit))){
753 //see if they intersect, if so do something about it
754 //-prepare matrixTarget2this
755 double u2me[16], umin[3],umax[3],uumin[3],uumax[3];
756 matmultiplyAFFINE(u2me,uhit->mvm,meinv);
757 //-transform target AABB/MBB from target space to this space
758 for(i=0;i<3;i++)
759 {
760 umin[i] = unode->_extent[i*2 + 1];
761 umax[i] = unode->_extent[i*2];
762 }
763 transformMBB(uumin,uumax,u2me,umin,umax);
764 //-see if AABB intersect
765 if( overlapMBBs(memin, memax, uumin, uumax) ){
766 //-if so take action
767 static const struct point_XYZ yvec = {0,0.05,0};
768 static const struct point_XYZ zvec = {0,0,-0.05};
769 static const struct point_XYZ zpvec = {0,0,0.05};
770 static const struct point_XYZ orig = {0,0,0};
771 struct point_XYZ t_zvec, t_yvec, t_orig; //, t_center;
772 struct point_XYZ nor1,nor2;
773 struct point_XYZ ins;
774 double len;
775 struct point_XYZ dr1r2;
776 struct point_XYZ dr2r3;
777 double t1u[3], t1me[3];
778
779 ishit++;
780 if (!node->isActive) {
781 #ifdef SEVERBOSE
782 printf ("transformensor - now active\n");
783 #endif
784
785 node->isActive = 1;
786 node->enterTime = TickTime();
787 MARK_EVENT (ptr, offsetof(struct X3D_TransformSensor, isActive));
788 MARK_EVENT (ptr, offsetof(struct X3D_TransformSensor, enterTime));
789 }
790 // has target position or orientation changed wrt transform sensor?
791 // if so send position_changed / orientation_changed events
792 //transform position
793 for(i=0;i<3;i++) t1u[i] = (umin[i] + umax[i])*.5;
794 transformAFFINEd(t1me,t1u,u2me);
795 for(i=0;i<3;i++) node->__t1.c[i] = (float)t1me[i] - node->center.c[i];
796 if (memcmp ((void *) &node->position_changed,(void *) &node->__t1,sizeof(struct SFColor))) {
797 #ifdef SEVERBOSE
798 printf ("PROX - position changed!!! \n");
799 #endif
800
801 memcpy ((void *) &node->position_changed,
802 (void *) &node->__t1,sizeof(struct SFColor));
803 MARK_EVENT (ptr, offsetof(struct X3D_TransformSensor, position_changed));
804 }
805 //transform orientation
806 transformAFFINE(&t_yvec,&yvec,u2me);
807 transformAFFINE(&t_zvec,&zvec,u2me);
808 transformAFFINE(&t_orig,&orig,u2me);
809 VECDIFF(t_zvec,t_orig,dr1r2); /* Z axis */
810 VECDIFF(t_yvec,t_orig,dr2r3); /* Y axis */
811
812 /* printf (" dr1r2 %lf %lf %lf\n",dr1r2.x, dr1r2.y, dr1r2.z);
813 printf (" dr2r3 %lf %lf %lf\n",dr2r3.x, dr2r3.y, dr2r3.z);
814 */
815
816 len = sqrt(VECSQ(dr1r2)); VECSCALE(dr1r2,1/len);
817 len = sqrt(VECSQ(dr2r3)); VECSCALE(dr2r3,1/len);
818
819 /* printf ("scaled dr1r2 %lf %lf %lf\n",dr1r2.x, dr1r2.y, dr1r2.z);
820 printf ("scaled dr2r3 %lf %lf %lf\n",dr2r3.x, dr2r3.y, dr2r3.z);
821 */
822
823 /*
824 printf("PROX_INT: (%f %f %f) (%f %f %f) (%f %f %f)\n (%f %f %f) (%f %f %f)\n",
825 t_orig.x, t_orig.y, t_orig.z,
826 t_zvec.x, t_zvec.y, t_zvec.z,
827 t_yvec.x, t_yvec.y, t_yvec.z,
828 dr1r2.x, dr1r2.y, dr1r2.z,
829 dr2r3.x, dr2r3.y, dr2r3.z
830 );
831 */
832
833 if(fabs(VECPT(dr1r2, dr2r3)) > 0.001) {
834 printf ("Sorry, can't handle unevenly scaled TransformSensors yet :("
835 "dp: %f v: (%f %f %f) (%f %f %f)\n", VECPT(dr1r2, dr2r3),
836 dr1r2.x,dr1r2.y,dr1r2.z,
837 dr2r3.x,dr2r3.y,dr2r3.z
838 );
839 return;
840 }
841
842
843 if(APPROX(dr1r2.z,1.0)) {
844 /* rotation */
845 ((node->__t2).c[0]) = (float) 0;
846 ((node->__t2).c[1]) = (float) 0;
847 ((node->__t2).c[2]) = (float) 1;
848 ((node->__t2).c[3]) = (float) atan2(-dr2r3.x,dr2r3.y);
849 } else if(APPROX(dr2r3.y,1.0)) {
850 /* rotation */
851 ((node->__t2).c[0]) = (float) 0;
852 ((node->__t2).c[1]) = (float) 1;
853 ((node->__t2).c[2]) = (float) 0;
854 ((node->__t2).c[3]) = (float) atan2(dr1r2.x,dr1r2.z);
855 } else {
856 /* Get the normal vectors of the possible rotation planes */
857 nor1 = dr1r2;
858 nor1.z -= 1.0;
859 nor2 = dr2r3;
860 nor2.y -= 1.0;
861
862 /* Now, the intersection of the planes, obviously cp */
863 VECCP(nor1,nor2,ins);
864
865 len = sqrt(VECSQ(ins)); VECSCALE(ins,1/len);
866
867 /* the angle */
868 VECCP(dr1r2,ins, nor1);
869 VECCP(zpvec, ins, nor2);
870 len = sqrt(VECSQ(nor1)); VECSCALE(nor1,1/len);
871 len = sqrt(VECSQ(nor2)); VECSCALE(nor2,1/len);
872 VECCP(nor1,nor2,ins);
873
874 ((node->__t2).c[3]) = (float) -atan2(sqrt(VECSQ(ins)), VECPT(nor1,nor2));
875
876 /* rotation - should normalize sometime... */
877 ((node->__t2).c[0]) = (float) ins.x;
878 ((node->__t2).c[1]) = (float) ins.y;
879 ((node->__t2).c[2]) = (float) ins.z;
880 }
881
882 if (memcmp ((void *) &node->orientation_changed, (void *) &node->__t2,sizeof(struct SFRotation))) {
883 #ifdef SEVERBOSE
884 printf ("PROX - orientation changed!!!\n ");
885 #endif
886
887 memcpy ((void *) &node->orientation_changed,
888 (void *) &node->__t2,sizeof(struct SFRotation));
889 MARK_EVENT (ptr, offsetof(struct X3D_TransformSensor, orientation_changed));
890 }
891 }
892 }
893 }
894
895 if(!ishit){
896 if (node->isActive) {
897 #ifdef SEVERBOSE
898 printf ("transformsensor - going inactive\n");
899 #endif
900
901 node->isActive = 0;
902 node->exitTime = TickTime();
903 MARK_EVENT (ptr, offsetof(struct X3D_TransformSensor, isActive));
904 MARK_EVENT (ptr, offsetof(struct X3D_TransformSensor, exitTime));
905 }
906 }
907
908 //ask this node and target node to both save their modelviewmatrix for each USE, when visited, on the upcoming frame (do_ called from do_first())
909 node->targetObject->_renderFlags |= VF_USE;
910 }
911 node->_renderFlags |= VF_USE;
912
913}