FreeWRL/FreeX3D  3.0.0
Component_Navigation.c
1 /*
2 
3 
4 X3D Navigation 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 "../main/headers.h"
39 
40 #include "../x3d_parser/Bindable.h"
41 #include "LinearAlgebra.h"
42 #include "Collision.h"
43 #include "quaternion.h"
44 #include "Viewer.h"
45 #include "../opengl/Frustum.h"
46 #include "Children.h"
47 #include "../opengl/OpenGL_Utils.h"
48 #include "../scenegraph/RenderFuncs.h"
49 
50 
51 struct X3D_Node *getActiveLayerBoundViewpoint();
52 void prep_Viewpoint (struct X3D_Viewpoint *node) {
53  double a1;
54  GLint viewPort[10];
56  if (!renderstate()->render_vp) return;
57  viewer = Viewer();
58 
59  /* printf ("prep_Viewpoint: vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
60  render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision); */
61 
62 
63  /* printf ("RVP, node %d ib %d sb %d gepvp\n",node,node->isBound,node->set_bind);
64  printf ("VP stack %d tos %d\n",viewpoint_tos, viewpoint_stack[viewpoint_tos]); */
65 
66 
67 
68  /* check the set_bind eventin to see if it is TRUE or FALSE */
69  /* code to perform binding is now in set_viewpoint. */
70 
71  /* we will never get here unless we are told that we are active by the scene graph; actually
72  doing this test can screw us up, so DO NOT do this test!
73  if(!node->isBound) return;
74  */
75  if((struct X3D_Node*)node == getActiveLayerBoundViewpoint() && !node->_donethispass){
76  node->_donethispass = 1; //if the vp id DEF/USED multiple places in the scengraph,
77  // this test takes the first one (and helps exit render_node early around virt->children)
78 
79 
80  /* printf ("Component_Nav, found VP is %d, (%s)\n",node,node->description->strptr); */
81 
82 
83  /* perform Viewpoint translations */
84  if (viewer->SLERPing) {
85 
86  double tickFrac;
87  Quaternion slerpedDiff;
88 
89  struct point_XYZ antipos;
90 
91  /* printf ("slerping in togl, type %s\n", VIEWER_STRING(viewer_type)); */
92  tickFrac = (TickTime() - viewer->startSLERPtime)/viewer->transitionTime;
93 
94  quaternion_slerp (&slerpedDiff,&viewer->startSLERPprepVPQuat,&viewer->prepVPQuat,tickFrac);
95 
96  quaternion_togl(&slerpedDiff);
97 
98  antipos.x = viewer->AntiPos.x * tickFrac + (viewer->startSLERPAntiPos.x * (1.0 - tickFrac));
99  antipos.y = viewer->AntiPos.y * tickFrac + (viewer->startSLERPAntiPos.y * (1.0 - tickFrac));
100  antipos.z = viewer->AntiPos.z * tickFrac + (viewer->startSLERPAntiPos.z * (1.0 - tickFrac));
101 
102  FW_GL_TRANSLATE_D(-antipos.x, -antipos.y, -antipos.z);
103 
104  } else {
105 
106  //quaternion_togl(&viewer->prepVPQuat);
107  {
108  //dug9slerp this fix works with a test file VP_set_orientation.x3d
109  Quaternion q3;
110  vrmlrot_to_quaternion(&q3,node->orientation.c[0],node->orientation.c[1],node->orientation.c[2],-node->orientation.c[3]);
111  quaternion_togl(&q3);
112  }
113  FW_GL_TRANSLATE_D(-node->position.c[0],-node->position.c[1],-node->position.c[2]);
114  }
115 
116  /* now, lets work on the Viewpoint fieldOfView */
117  FW_GL_GETINTEGERV(GL_VIEWPORT, viewPort);
118  if(viewPort[2] > viewPort[3]) {
119  a1=0;
120  viewer->fieldofview = node->fieldOfView/3.1415926536*180;
121  } else {
122  a1 = node->fieldOfView;
123  a1 = atan2(sin(a1),viewPort[2]/((float)viewPort[3]) * cos(a1));
124  viewer->fieldofview = a1/3.1415926536*180;
125  }
126  }
127  // printf ("render_Viewpoint, bound to %d, fieldOfView %f \n",node,node->fieldOfView);
128 }
129 
130 
131 void prep_OrthoViewpoint (struct X3D_OrthoViewpoint *node) {
132  int ind;
133 
134  if (!renderstate()->render_vp) return;
135 
136  /* printf ("prep_OrthoViewpoint: vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
137  render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision); */
138 
139 
140  /* printf ("RVP, node %d ib %d sb %d gepvp\n",node,node->isBound,node->set_bind);
141  printf ("VP stack %d tos %d\n",viewpoint_tos, viewpoint_stack[viewpoint_tos]); */
142 
143  /* check the set_bind eventin to see if it is TRUE or FALSE */
144  /* code to perform binding is now in set_viewpoint. */
145 
146  /* we will never get here unless we are told that we are active by the scene graph; actually
147  doing this test can screw us up, so DO NOT do this test!
148  if(!node->isBound) return;
149  */
150 
151  /* printf ("Component_Nav, found VP is %d, (%s)\n",node,node->description->strptr); */
152  if((struct X3D_Node*)node == getActiveLayerBoundViewpoint() && !node->_donethispass){
153  node->_donethispass = 1; //if the vp id DEF/USED multiple places in the scengraph,
154 
155 
156  /* perform OrthoViewpoint translations */
157  FW_GL_ROTATE_RADIANS(-node->orientation.c[3],node->orientation.c[0],node->orientation.c[1],
158  node->orientation.c[2]);
159  FW_GL_TRANSLATE_D(-node->position.c[0],-node->position.c[1],-node->position.c[2]);
160 
161  /* now, lets work on the OrthoViewpoint fieldOfView */
162  if (node->fieldOfView.n == 4) {
163  for (ind=0; ind<4; ind++) {
164  Viewer()->orthoField[ind] = (double) node->fieldOfView.p[ind];
165  }
166  //Viewer()->ortho = TRUE;
167  }
168 
169  // printf ("render_OrthoViewpoint, bound to %d, fieldOfView %f \n",node,node->fieldOfView);
170  }
171 }
172 
173 /******************************************************************************************/
174 
175 void proximity_Billboard (struct X3D_Billboard *node) {
176  /* printf ("prox_billboard, do nothing\n"); */
177 }
178 
179 void prep_Billboard (struct X3D_Billboard *node) {
180  struct point_XYZ vpos, ax, cp, cp2, arcp;
181  static const struct point_XYZ orig = {0.0, 0.0, 0.0};
182  static const struct point_XYZ zvec = {0.0, 0.0, 1.0};
183  struct orient_XYZA viewer_orient;
184  GLDOUBLE mod[16];
185  GLDOUBLE proj[16];
186  int align;
187  double len, len2, angle;
188  int sign;
189 
190  RECORD_DISTANCE
191 
192  ax.x = node->axisOfRotation.c[0];
193  ax.y = node->axisOfRotation.c[1];
194  ax.z = node->axisOfRotation.c[2];
195  align = (APPROX(VECSQ(ax),0));
196 
197  quaternion_to_vrmlrot(&(Viewer()->Quat),
198  &(viewer_orient.x), &(viewer_orient.y),
199  &(viewer_orient.z), &(viewer_orient.a));
200 
201  FW_GL_PUSH_MATRIX();
202 
203  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, mod);
204  if(0){
205  FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, proj);
206  FW_GLU_UNPROJECT(orig.x, orig.y, orig.z, mod, proj, viewport, &vpos.x, &vpos.y, &vpos.z);
207  }
208  if(1){
209  //feature-AFFINE_GLU_UNPROJECT
210  double modi[16];
211  matinverseAFFINE(modi,mod);
212  transform(&vpos,&orig,modi);
213  }
214  len = VECSQ(vpos);
215  if (APPROX(len, 0)) { return; }
216  VECSCALE(vpos, 1/sqrt(len));
217 
218  if (align) {
219  ax.x = viewer_orient.x;
220  ax.y = viewer_orient.y;
221  ax.z = viewer_orient.z;
222  }
223 
224  VECCP(ax, zvec, arcp);
225  len = VECSQ(arcp);
226  if (APPROX(len, 0)) { return; }
227 
228  len = VECSQ(ax);
229  if (APPROX(len, 0)) { return; }
230  VECSCALE(ax, 1/sqrt(len));
231 
232  VECCP(vpos, ax, cp); /* cp is now 90deg to both vector and axis */
233  len = sqrt(VECSQ(cp));
234  if (APPROX(len, 0)) {
235  FW_GL_ROTATE_RADIANS(-viewer_orient.a, ax.x, ax.y, ax.z);
236  return;
237  }
238  VECSCALE(cp, 1/len);
239 
240  /* Now, find out angle between this and z axis */
241  VECCP(cp, zvec, cp2);
242 
243  len2 = VECPT(cp, zvec); /* cos(angle) */
244  len = sqrt(VECSQ(cp2)); /* this is abs(sin(angle)) */
245 
246  /* Now we need to find the sign first */
247  if (VECPT(cp, arcp) > 0) { sign = -1; } else { sign = 1; }
248  angle = atan2(len2, sign*len);
249 
250  FW_GL_ROTATE_RADIANS(angle, ax.x, ax.y, ax.z);
251 }
252 
253 void fin_Billboard (struct X3D_Billboard *node) {
254  UNUSED(node);
255  FW_GL_POP_MATRIX();
256 }
257 
258 
259 void child_Billboard (struct X3D_Billboard *node) {
260  int nc = node->children.n;
261  //LOCAL_LIGHT_SAVE
262 
263 
264  /* any children at all? */
265  if (nc==0) return;
266 
267  #ifdef CHILDVERBOSE
268  printf("RENDER BILLBOARD START %d (%d)\n",node, nc);
269  #endif
270 
271  /* do we have a local light for a child? */
272  //LOCAL_LIGHT_CHILDREN(node->children);
273  prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
274 
275  /* now, just render the non-directionalLight children */
276  normalChildren(node->children);
277 
278  if (renderstate()->render_geom && (!renderstate()->render_blend)) {
279  EXTENTTOBBOX
280  }
281 
282  #ifdef CHILDVERBOSE
283  printf("RENDER BILLBOARD END %d\n",node);
284  #endif
285  fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
286 
287  //LOCAL_LIGHT_OFF
288 }
289 
290 
291 /******************************************************************************************/
292 
293 //
294 //void render_NavigationInfo (struct X3D_NavigationInfo *node) {
295 // /* check the set_bind eventin to see if it is TRUE or FALSE */
296 // ttglobal tg = gglobal();
297 // if (node->set_bind < 100) {
298 // if (node->set_bind == 1) set_naviinfo(node);
299 // bind_node (X3D_NODE(node), getActiveBindableStacks(tg)->navigation);
300 // }
301 // if(!node->isBound) return;
302 //}
303 
304 
305 /*
306 Nov 28, 2016 we aren't doing collision->proxy
307 COLLISION_PROXY
308 http://www.web3d.org/documents/specifications/19775-1/V3.3/Part01/components/navigation.html#Collision
309 """
310 The collision proxy, defined in the proxy field, is any legal children node as described in 10.2.1 Grouping and children node types that is used as a substitute for the Collision node's children during collision detection. The proxy is used strictly for collision detection; it is not drawn.
311 """
312 http://www.web3d.org/x3d/content/examples/Basic/development/ProxyShapeExampleIndex.html
313 - example showing you can re-order / change the order / length of children field and proxy should still be proxy
314 */
315 
316 void child_Collision (struct X3D_Collision *node) {
317  int nc = node->children.n;
318  int i;
319  struct X3D_Node *tmpN;
320 
321  if(renderstate()->render_collision) {
322  /* test against the collide field (vrml) enabled (x3d) and that we actually have a proxy field */
323  if((node->collide) && (node->enabled) && !(node->proxy)) {
324  struct sCollisionInfo OldCollisionInfo;
325  struct sCollisionInfo * ci = CollisionInfo();
326  OldCollisionInfo = *ci;
327  for(i=0; i<nc; i++) {
328  void *p = ((node->children).p[i]);
329  #ifdef CHILDVERBOSE
330  printf("RENDER COLLISION %d CHILD %d\n",node, p);
331  #endif
332  render_node(p);
333  }
334  if((!APPROX(ci->Offset.x,
335  OldCollisionInfo.Offset.x)) ||
336  (!APPROX(ci->Offset.y,
337  OldCollisionInfo.Offset.y)) ||
338  (!APPROX(ci->Offset.z,
339  OldCollisionInfo.Offset.z))) {
340  /* old code was:
341  if(CollisionInfo.Offset.x != OldCollisionInfo.Offset.x ||
342  CollisionInfo.Offset.y != OldCollisionInfo.Offset.y ||
343  CollisionInfo.Offset.z != OldCollisionInfo.Offset.z) { */
344  /*collision occured
345  * bit 0 gives collision, bit 1 gives change */
346  node->__hit = (node->__hit & 1) ? 1 : 3;
347  } else
348  node->__hit = (node->__hit & 1) ? 2 : 0;
349 
350  }
351  if(node->proxy) {
352  POSSIBLE_PROTO_EXPANSION(struct X3D_Node *, node->proxy,tmpN)
353  render_node(tmpN);
354  }
355 
356  } else { /*standard group behaviour*/
357  //LOCAL_LIGHT_SAVE
358 
359  #ifdef CHILDVERBOSE
360  printf("RENDER COLLISIONCHILD START %d (%d)\n",node, nc);
361  #endif
362 
363  /* do we have a local light for a child? */
364  //LOCAL_LIGHT_CHILDREN(node->children);
365  prep_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
366 
367  /* now, just render the non-directionalLight children */
368  normalChildren(node->children);
369 
370  #ifdef CHILDVERBOSE
371  printf("RENDER COLLISIONCHILD END %d\n",node);
372  #endif
373  //LOCAL_LIGHT_OFF
374  fin_sibAffectors((struct X3D_Node*)node,&node->__sibAffectors);
375 
376  }
377 }
378 
379 /* LOD changes between X3D and VRML - level and children fields are "equivalent" */
380 void child_LOD (struct X3D_LOD *node) {
381 
382 /*
383 if (node->_selected != NULL) {
384 struct X3D_Node *selno = X3D_NODE(node->_selected);
385 printf ("childLOD %p (root %p), flags %x ",selno,rootNode,selno->_renderFlags);
386 if ((selno->_renderFlags & VF_Viewpoint) == VF_Viewpoint) printf ("VF_Viewpoint ");
387 if ((selno->_renderFlags & VF_Geom) == VF_Geom) printf ("VF_Geom ");
388 if ((selno->_renderFlags & VF_localLight) == VF_localLight) printf ("VF_localLight ");
389 if ((selno->_renderFlags & VF_Sensitive) == VF_Sensitive) printf ("VF_Sensitive ");
390 if ((selno->_renderFlags & VF_Blend) == VF_Blend) printf ("VF_Blend ");
391 if ((selno->_renderFlags & VF_Proximity) == VF_Proximity) printf ("VF_Proximity ");
392 if ((selno->_renderFlags & VF_Collision) == VF_Collision) printf ("VF_Collision ");
393 if ((selno->_renderFlags & VF_globalLight) == VF_globalLight) printf ("VF_globalLight ");
394 if ((selno->_renderFlags & VF_hasVisibleChildren) == VF_hasVisibleChildren) printf ("VF_hasVisibleChildren ");
395 if ((selno->_renderFlags & VF_shouldSortChildren) == VF_shouldSortChildren) printf ("VF_shouldSortChildren ");
396 printf ("\n");
397 }
398 */
399  render_node(node->_selected);
400 }
401 
402 
403 /* calculate the LOD distance */
404 void proximity_LOD (struct X3D_LOD *node) {
405  GLDOUBLE mod[16];
406  GLDOUBLE proj[16];
407  struct point_XYZ vec;
408  double dist;
409  int nran = (node->range).n;
410  int nnod = (node->level).n;
411  int xnod = (node->children).n;
412 
413  int i;
414 
415  /* no range, display the first node, if it exists */
416  if(!nran) {
417  if (node->__isX3D) {
418  if (nnod > 0) node->_selected = (node->children).p[0];
419  else node->_selected = NULL;
420  } else {
421  if (xnod > 0) node->_selected = (node->level).p[0];
422  else node->_selected = NULL;
423  }
424  return;
425  }
426 
427  /* calculate which one to display */
428  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, mod);
429  if(0){
430  //this is centered on the front face of the frustum, about .1 away from avatar center (approximately correct)
431  /* printf ("LOD, mat %f %f %f\n",mod[12],mod[13],mod[14]); */
432  FW_GL_GETDOUBLEV(GL_PROJECTION_MATRIX, proj);
433  FW_GLU_UNPROJECT(0,0,0,mod,proj,viewport, &vec.x,&vec.y,&vec.z);
434  //printf("old vec= %f %f %f\n", vec.x,vec.y,vec.z);
435  }
436  if(1){
437  //feature-AFFINE_GLU_UNPROJECT
438  //this is centered on the avatar (correct)
439  double modi[16];
440  struct point_XYZ orig = {0.0,0.0,0.0};
441  matinverseAFFINE(modi,mod);
442  transform(&vec,&orig,modi);
443  //printf("new vec= %f %f %f\n", vec.x,vec.y,vec.z);
444  //printf("\n");
445  }
446  vec.x -= (node->center).c[0];
447  vec.y -= (node->center).c[1];
448  vec.z -= (node->center).c[2];
449 
450  dist = sqrt(VECSQ(vec));
451  i = 0;
452 
453  while (i<nran) {
454  if(dist < ((node->range).p[i])) { break; }
455  i++;
456  }
457 
458  /* is this VRML or X3D? */
459  if (node->__isX3D) {
460  if (xnod > 0) {
461  /* X3D "children" field */
462  if(i >= xnod) i = xnod-1;
463  node->_selected = (node->children).p[i];
464  /* printf ("selecting X3D nod %d \n",i); */
465  } else node->_selected = NULL;
466 
467  } else {
468  if (nnod > 0) {
469  /* VRML "range" field */
470  if(i >= nnod) i = nnod-1;
471  node->_selected = (node->level).p[i];
472  /* printf ("selecting vrml nod\n"); */
473  } else { node->_selected = NULL; }
474  }
475 }
476 
477 
478 
479 /************************************************************************
480  *
481  * ViewpointGroup Node
482  *
483  ************************************************************************/
484  void add_node_to_broto_context(struct X3D_Proto *currentContext,struct X3D_Node *node);
485 
486 void compile_ViewpointGroup (struct X3D_ViewpointGroup *node) {
487  struct X3D_ProximitySensor *pn;
488 
489  /* check if we need to create the proximity node */
490  if (node->__proxNode == NULL) {
491  /* create proximity */
492  pn = (struct X3D_ProximitySensor *) createNewX3DNode(NODE_ProximitySensor);
493  if(node->_executionContext)
494  add_node_to_broto_context(X3D_PROTO(node->_executionContext),X3D_NODE(pn));
495 
496  /* any changes needed here?? */
497  node->__proxNode = (void *)pn;
498 
499  /* link this in so the VF_Proximity flag will propagate */
500  ADD_PARENT(X3D_NODE(pn),X3D_NODE(node));
501  }
502 
503  /* get the Proximity Node */
504  pn = X3D_PROXIMITYSENSOR(node->__proxNode);
505 
506  /* copy size, center over */
507  memcpy (&pn->center, &node->center, sizeof (float)*3);
508  memcpy (&pn->size, &node->size, sizeof (float)*3);
509 
510  /* enable it */
511  pn->enabled=TRUE;
512 
513  /* tell the proximity that it has changed */
514  pn->_change++;
515 
516  MARK_NODE_COMPILED
517 }
518 
519 
520 void child_ViewpointGroup (struct X3D_ViewpointGroup *node) {
521  int i;
522 
523  /* do we have an attached proximity node? If so, we'll be flagged to do
524  the sensitive pass */
525 
526  /* printf ("child_ViewpointGroup, this %u rf %x \n",node,node->_renderFlags);
527  printf (" ..., render_hier vp %d geom %d light %d sens %d blend %d prox %d col %d\n",
528  render_vp,render_geom,render_light,render_sensitive,render_blend,render_proximity,render_collision); */
529 
530  if (renderstate()->render_proximity) {
531  if (node->__proxNode != NULL) {
532  /* printf ("have prox, rendering it\n"); */
533  render_node(X3D_NODE(node->__proxNode));
534 
535  /* printf ("prox active %d\n",X3D_PROXIMITYSENSOR(node->__proxNode)->isActive); */
536  }
537 
538  }
539 
540  if (!renderstate()->render_vp) return;
541 
542  /* render the viewpoints - one of these will be active */
543  for(i=0; i<node->children.n; i++) {
544  struct X3D_Node *p = X3D_NODE(node->children.p[i]);
545  if (p != NULL) {
546  render_node(p);
547  }
548  }
549 
550 }
551 
Definition: Viewer.h:196