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