FreeWRL/FreeX3D  3.0.0
SensInterps.c
1 /*
2 
3 
4 Do Sensors and Interpolators in C, not in perl.
5 
6 Interps are the "EventsProcessed" fields of interpolators.
7 
8 */
9 
10 
11 /****************************************************************************
12  This file is part of the FreeWRL/FreeX3D Distribution.
13 
14  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
15 
16  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
17  it under the terms of the GNU Lesser Public License as published by
18  the Free Software Foundation, either version 3 of the License, or
19  (at your option) any later version.
20 
21  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
22  but WITHOUT ANY WARRANTY; without even the implied warranty of
23  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24  GNU General Public License for more details.
25 
26  You should have received a copy of the GNU General Public License
27  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
28 ****************************************************************************/
29 
30 
31 
32 #include <config.h>
33 #include <system.h>
34 #include <display.h>
35 #include <internal.h>
36 
37 #include <libFreeWRL.h>
38 #include <list.h>
39 
40 #include "../vrml_parser/Structs.h"
41 #include "../input/InputFunctions.h"
42 #include "../opengl/LoadTextures.h" /* for finding a texture url in a multi url */
43 
44 
45 #include "../main/headers.h"
46 #include "../opengl/OpenGL_Utils.h"
47 #include "../scenegraph/RenderFuncs.h"
48 
49 #include "../x3d_parser/Bindable.h"
50 #include "../scenegraph/LinearAlgebra.h"
51 #include "../scenegraph/Collision.h"
52 #include "../scenegraph/quaternion.h"
53 #include "../scenegraph/sounds.h"
54 #include "../vrml_parser/CRoutes.h"
55 #include "../opengl/OpenGL_Utils.h"
56 #include "../opengl/Textures.h" /* for finding a texture url in a multi url */
57 
58 #include "SensInterps.h"
59 
60 
61 
62 /* when we get a new sound source, what is the number for this? */
63 //int SoundSourceNumber = 0;
64 typedef struct pSensInterps{
65  int stub;
66 }* ppSensInterps;
67 void *SensInterps_constructor(){
68  void *v = MALLOCV(sizeof(struct pSensInterps));
69  memset(v,0,sizeof(struct pSensInterps));
70  return v;
71 }
72 void SensInterps_init(struct tSensInterps *t)
73 {
74  //public
75  //private
76  t->prv = SensInterps_constructor();
77  {
78  //ppSensInterps p = (ppSensInterps)t->prv;
79  }
80 }
81 
82 
84 //void locateAudioSource (struct X3D_AudioClip *node);
85 
86 
87 /* time dependent sensor nodes- check/change activity state */
88 void do_active_inactive (
89  int *act, /* pointer to are we active or not? */
90  double *inittime, /* pointer to nodes inittime */
91  double *startt, /* pointer to nodes startTime */
92  double *stopt, /* pointer to nodes stop time */
93  int loop, /* nodes loop field */
94  double myDuration, /* duration of cycle */
95  double speed, /* speed field */
96  double elapsedTime /* cumulative non-paused time */
97 ) {
98 
99  /* what we do now depends on whether we are active or not */
100  /* gcc seemed to have problems mixing double* and floats in a function
101  call, so make them all doubles. Note duplicate printfs in
102  do_active_inactive call - uncomment and make sure all are identical
103  printf ("called ");
104  printf ("act %d ",*act);
105  printf ("initt %lf ",*inittime);
106  printf ("startt %lf ",*startt);
107  printf ("stopt %lf ",*stopt);
108  printf ("loop %d ",loop);
109  printf ("myDuration %lf ",myDuration);
110  printf ("speed %f\n",speed);
111  */
112  double ticktime = TickTime(); //changes once per frame, not in here
113 
114  if (*act == 1) { /* active - should we stop? */
115  #ifdef SEVERBOSE
116  printf ("is active tick %f startt %f stopt %f\n",
117  TickTime(), *startt, *stopt);
118  #endif
119 
120  if (ticktime > *stopt) {
121  if (*startt >= *stopt) {
122  /* cases 1 and 2 */
123  if (!(loop)) {
124  /*printf ("case 1 and 2, not loop md %f sp %f fabs %f\n",
125  myDuration, speed, fabs(myDuration/speed));
126  */
127 
128  /* if (speed != 0) */
129  if (! APPROX(speed, 0)) {
130  //if (ticktime >= (*startt + fabs(myDuration/speed))) {
131  if (elapsedTime >= fabs(myDuration/speed) ) {
132  #ifdef SEVERBOSE
133  printf ("stopping case x\n");
134  printf ("TickTime() %f\n",ticktime);
135  printf ("startt %f\n",*startt);
136  printf ("myDuration %f\n",myDuration);
137  printf ("speed %f\n",speed);
138  #endif
139 
140  *act = 0;
141  *stopt = ticktime;
142  }
143  }
144  }
145  } else {
146  #ifdef SEVERBOSE
147  printf ("stopping case z\n");
148  #endif
149 
150  *act = 0;
151  *stopt = ticktime;
152  }
153  }
154  }
155 
156  /* immediately process start events; as per spec. */
157  if (*act == 0) { /* active - should we start? */
158  /* printf ("is not active TickTime %f startt %f\n",TickTime(),*startt); */
159 
160  if (ticktime >= *startt) {
161  /* We just might need to start running */
162 
163  if (ticktime >= *stopt) {
164  /* lets look at the initial conditions; have not had a stoptime
165  event (yet) */
166 
167  if (loop) {
168  if (*startt >= *stopt) {
169  /* VRML standards, table 4.2 case 2 */
170  /* printf ("CASE 2\n"); */
171  /* Umut Sezen's code: */
172  if (!(*startt > 0)) *startt = ticktime;
173  *act = 1;
174  }
175  } else if (*startt >= *stopt) {
176  if (*startt > *inittime) {
177  /* ie, we have an event */
178  /* printf ("case 1 here\n"); */
179  /* we should be running VRML standards, table 4.2 case 1 */
180  /* Umut Sezen's code: */
181  if (!(*startt > 0))
182  *startt = ticktime;
183  *act = 1;
184  }
185  }
186  } else {
187  /* printf ("case 3 here\n"); */
188  /* we should be running -
189  VRML standards, table 4.2 cases 1 and 2 and 3 */
190  /* Umut Sezen's code: */
191  if (!(*startt > 0)) *startt = ticktime;
192  *act = 1;
193  }
194  }
195  }
196 }
197 
198 
199 /* Interpolators - local routine, look for the appropriate key */
200 int find_key (int kin, float frac, float *keys) {
201  int counter;
202 
203  for (counter=1; counter <= kin; counter++) {
204  if (frac <keys[counter]) {
205  return counter;
206  }
207  }
208  return kin; /* huh? not found! */
209 }
210 
211 
212 /* ScalarInterpolators - return only one float */
213 void do_OintScalar (void *node) {
214  /* ScalarInterpolator - store final value in px->value_changed */
215  struct X3D_ScalarInterpolator *px;
216  int kin, kvin;
217  float *kVs;
218  int counter;
219 
220  if (!node) return;
221  px = (struct X3D_ScalarInterpolator *) node;
222  kin = px->key.n;
223  kvin = px->keyValue.n;
224  kVs = px->keyValue.p;
225 
226  MARK_EVENT (node, offsetof (struct X3D_ScalarInterpolator, value_changed));
227 
228  /* make sure we have the keys and keyValues */
229  if ((kvin == 0) || (kin == 0)) {
230  px->value_changed = (float) 0.0;
231  return;
232  }
233  if (kin>kvin) kin=kvin; /* means we don't use whole of keyValue, but... */
234 
235  #ifdef SEVERBOSE
236  printf ("ScalarInterpolator, kin %d kvin %d, vc %f\n",kin,kvin,px->value_changed);
237  #endif
238 
239  /* set_fraction less than or greater than keys */
240  if (px->set_fraction <= px->key.p[0]) {
241  px->value_changed = kVs[0];
242  } else if (px->set_fraction >= px->key.p[kin-1]) {
243  px->value_changed = kVs[kvin-1];
244  } else {
245  /* have to go through and find the key before */
246  counter=find_key(kin,(float)(px->set_fraction),px->key.p);
247  px->value_changed =
248  (px->set_fraction - px->key.p[counter-1]) /
249  (px->key.p[counter] - px->key.p[counter-1]) *
250  (kVs[counter] - kVs[counter-1]) +
251  kVs[counter-1];
252  }
253 }
254 
255 
256 void do_OintNormal(void *node) {
257  struct X3D_NormalInterpolator *px;
258  int kin, kvin/* , counter */;
259  struct SFVec3f *kVs;
260  struct SFVec3f *valchanged;
261 
262  int thisone, prevone; /* which keyValues we are interpolating between */
263  int tmp;
264  float interval; /* where we are between 2 values */
265  struct point_XYZ normalval; /* different structures for normalization calls */
266  int kpkv; /* keys per key value */
267  int indx;
268  int myKey;
269 
270  if (!node) return;
271  px = (struct X3D_NormalInterpolator *) node;
272 
273 
274  #ifdef SEVERBOSE
275  printf ("debugging OintCoord keys %d kv %d vc %d\n",px->keyValue.n, px->key.n,px->value_changed.n);
276  #endif
277 
278  MARK_EVENT (node, offsetof (struct X3D_NormalInterpolator, value_changed));
279 
280  kin = px->key.n;
281  kvin = px->keyValue.n;
282  kVs = px->keyValue.p;
283  kpkv = kvin/kin;
284 
285  /* do we need to (re)allocate the value changed array? */
286  if (kpkv != px->value_changed.n) {
287  #ifdef SEVERBOSE
288  printf ("refactor valuechanged array. n %d sizeof p %d\n",
289  kpkv,sizeof (struct SFColor) * kpkv);
290  #endif
291  if (px->value_changed.n != 0) {
292  FREE_IF_NZ (px->value_changed.p);
293  }
294  px->value_changed.n = kpkv;
295  px->value_changed.p = MALLOC (struct SFVec3f*, sizeof (struct SFVec3f) * kpkv);
296  }
297 
298  /* shortcut valchanged; have to put it here because might be reMALLOC'd */
299  valchanged = px->value_changed.p;
300 
301 
302  /* make sure we have the keys and keyValues */
303  if ((kvin == 0) || (kin == 0)) {
304  #ifdef SEVERBOSE
305  printf ("no keys or keyValues yet\n");
306  #endif
307 
308  for (indx = 0; indx < kpkv; indx++) {
309  valchanged[indx].c[0] = (float) 0.0;
310  valchanged[indx].c[1] = (float) 0.0;
311  valchanged[indx].c[2] = (float) 0.0;
312  }
313  return;
314  }
315  if (kin>kvin) kin=kvin; /* means we don't use whole of keyValue, but... */
316 
317 
318  #ifdef SEVERBOSE
319  printf ("debugging, kpkv %d, px->value_changed.n %d\n", kpkv, px->value_changed.n);
320  printf ("NormalInterpolator, kpkv %d\n",kpkv);
321  #endif
322 
323 
324  /* set_fraction less than or greater than keys */
325  if (px->set_fraction <= px->key.p[0]) {
326  #ifdef SEVERBOSE
327  printf ("COINT out1\n");
328  #endif
329 
330  for (indx = 0; indx < kpkv; indx++) {
331  memcpy ((void *)&valchanged[indx],
332  (void *)&kVs[indx], sizeof (struct SFColor));
333  }
334  #ifdef SEVERBOSE
335  printf ("COINT out1 copied\n");
336  #endif
337  } else if (px->set_fraction >= px->key.p[kin-1]) {
338  #ifdef SEVERBOSE
339  printf ("COINT out2\n");
340  #endif
341 
342  for (indx = 0; indx < kpkv; indx++) {
343  memcpy ((void *)&valchanged[indx],
344  (void *)&kVs[kvin-kpkv+indx],
345  sizeof (struct SFColor));
346  }
347  #ifdef SEVERBOSE
348  printf ("COINT out2 finished\n");
349  #endif
350  } else {
351  #ifdef SEVERBOSE
352  printf ("COINT out3\n");
353  #endif
354 
355  /* have to go through and find the key before */
356  #ifdef SEVERBOSE
357  printf ("indx=0, kin %d frac %f\n",kin,px->set_fraction);
358  #endif
359 
360  myKey=find_key(kin,(float)(px->set_fraction),px->key.p);
361  #ifdef SEVERBOSE
362  printf ("working on key %d\n",myKey);
363  #endif
364 
365  /* find the fraction between the 2 values */
366  interval = (px->set_fraction - px->key.p[myKey-1]) /
367  (px->key.p[myKey] - px->key.p[myKey-1]);
368 
369  for (indx = 0; indx < kpkv; indx++) {
370  thisone = myKey * kpkv + indx;
371  prevone = (myKey-1) * kpkv + indx;
372 
373  #ifdef SEVERBOSE
374  if (thisone >= kvin) {
375  printf ("CoordinateInterpolator error: thisone %d prevone %d indx %d kpkv %d kin %d kvin %d\n",thisone,prevone,
376  indx,kpkv,kin,kvin);
377  }
378  #endif
379 
380  for (tmp=0; tmp<3; tmp++) {
381  valchanged[indx].c[tmp] = kVs[prevone].c[tmp] +
382  interval * (kVs[thisone].c[tmp] -
383  kVs[prevone].c[tmp]);
384  }
385  #ifdef SEVERBOSE
386  printf (" 1 %d interval %f prev %f this %f final %f\n",1,interval,kVs[prevone].c[1],kVs[thisone].c[1],valchanged[indx].c[1]);
387  #endif
388  }
389  #ifdef SEVERBOSE
390  printf ("COINT out3 finished\n");
391  #endif
392 
393  }
394 
395  /* if this is a NormalInterpolator... */
396  for (indx = 0; indx < kpkv; indx++) {
397  normalval.x = valchanged[indx].c[0];
398  normalval.y = valchanged[indx].c[1];
399  normalval.z = valchanged[indx].c[2];
400  normalize_vector(&normalval);
401  valchanged[indx].c[0] = (float) normalval.x;
402  valchanged[indx].c[1] = (float) normalval.y;
403  valchanged[indx].c[2] = (float) normalval.z;
404  }
405  #ifdef SEVERBOSE
406  printf ("Done CoordinateInterpolator\n");
407  #endif
408 }
409 
410 
411 void do_OintCoord(void *node) {
412  struct X3D_CoordinateInterpolator *px;
413  int kin, kvin/* , counter */;
414  struct SFVec3f *kVs;
415  struct SFVec3f *valchanged;
416 
417  int thisone, prevone; /* which keyValues we are interpolating between */
418  int tmp;
419  float interval; /* where we are between 2 values */
420  int kpkv; /* keys per key value */
421  int indx;
422  int myKey;
423 
424  if (!node) return;
425  px = (struct X3D_CoordinateInterpolator *) node;
426 
427 #ifdef SEVERBOSE
428  printf ("do_OintCoord, frac %f toGPU %d toCPU %d\n",px->set_fraction,px->_GPU_Routes_out, px->_CPU_Routes_out);
429  printf ("debugging OintCoord keys %d kv %d vc %d\n",px->keyValue.n, px->key.n,px->value_changed.n);
430  #endif
431 
432  MARK_EVENT (node, offsetof (struct X3D_CoordinateInterpolator, value_changed));
433 
434  // create the VBOs if required, for running on the GPU
435  if (px->_GPU_Routes_out > 0) {
436  if (px->_keyVBO==0) {
437  glGenBuffers(1,(GLuint *)&px->_keyValueVBO);
438  glGenBuffers(1,(GLuint *)&px->_keyVBO);
439  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,px->_keyValueVBO);
440  printf ("genning buffer data for %d keyValues, total floats %d\n",px->keyValue.n, px->keyValue.n*3);
441  glBufferData(GL_ARRAY_BUFFER,px->keyValue.n *sizeof(float)*3,px->keyValue.p, GL_STATIC_DRAW);
442 
443  FW_GL_BINDBUFFER(GL_ARRAY_BUFFER,px->_keyVBO);
444  glBufferData(GL_ARRAY_BUFFER,px->key.n *sizeof(float),px->key.p, GL_STATIC_DRAW);
445  printf ("created VBOs for the CoordinateInterpolator, they are %d and %d\n",
446  px->_keyValueVBO, px->_keyVBO);
447  }
448  }
449 
450 
451 
452  if (px->_CPU_Routes_out == 0) {
453  #ifdef SEVERBOSE
454  printf ("do_OintCoord, no CPU routes out, no need to do this work\n");
455  #endif
456  return;
457  }
458 
459  //MARK_EVENT (node, offsetof (struct X3D_CoordinateInterpolator, value_changed));
460 
461 
462  kin = px->key.n;
463  kvin = px->keyValue.n;
464  kVs = px->keyValue.p;
465  kpkv = kvin/kin;
466 
467  /* do we need to (re)allocate the value changed array? */
468  if (kpkv != px->value_changed.n) {
469  #ifdef SEVERBOSE
470  printf ("refactor valuechanged array. n %d sizeof p %d\n",
471  kpkv,sizeof (struct SFVec3f) * kpkv);
472  #endif
473  if (px->value_changed.n != 0) {
474  FREE_IF_NZ (px->value_changed.p);
475  }
476  px->value_changed.n = kpkv;
477  px->value_changed.p = MALLOC (struct SFVec3f*, sizeof (struct SFVec3f) * kpkv);
478  }
479 
480  /* shortcut valchanged; have to put it here because might be reMALLOC'd */
481  valchanged = px->value_changed.p;
482 
483 
484  /* make sure we have the keys and keyValues */
485  if ((kvin == 0) || (kin == 0)) {
486  #ifdef SEVERBOSE
487  printf ("no keys or keyValues yet\n");
488  #endif
489 
490  for (indx = 0; indx < kpkv; indx++) {
491  valchanged[indx].c[0] = (float) 0.0;
492  valchanged[indx].c[1] = (float) 0.0;
493  valchanged[indx].c[2] = (float) 0.0;
494  }
495  return;
496  }
497  if (kin>kvin) kin=kvin; /* means we don't use whole of keyValue, but... */
498 
499 
500  #ifdef SEVERBOSE
501  printf ("debugging, kpkv %d, px->value_changed.n %d\n", kpkv, px->value_changed.n);
502  printf ("CoordinateInterpolator, kpkv %d\n",kpkv);
503  #endif
504 
505 
506  /* set_fraction less than or greater than keys */
507  if (px->set_fraction <= px->key.p[0]) {
508  #ifdef SEVERBOSE
509  printf ("COINT out1\n");
510  #endif
511 
512  for (indx = 0; indx < kpkv; indx++) {
513  memcpy ((void *)&valchanged[indx],
514  (void *)&kVs[indx], sizeof (struct SFVec3f));
515  /* JAS valchanged[indx].c[0] = kVs[indx].c[0]; */
516  /* JAS valchanged[indx].c[1] = kVs[indx].c[1]; */
517  /* JAS valchanged[indx].c[2] = kVs[indx].c[2]; */
518  }
519  #ifdef SEVERBOSE
520  printf ("COINT out1 copied\n");
521  #endif
522  } else if (px->set_fraction >= px->key.p[kin-1]) {
523  #ifdef SEVERBOSE
524  printf ("COINT out2\n");
525  #endif
526 
527  for (indx = 0; indx < kpkv; indx++) {
528  memcpy ((void *)&valchanged[indx],
529  (void *)&kVs[kvin-kpkv+indx],
530  sizeof (struct SFVec3f));
531  }
532  #ifdef SEVERBOSE
533  printf ("COINT out2 finished\n");
534  #endif
535  } else {
536  #ifdef SEVERBOSE
537  printf ("COINT out3\n");
538  #endif
539 
540  /* have to go through and find the key before */
541  #ifdef SEVERBOSE
542  printf ("indx=0, kin %d frac %f\n",kin,px->set_fraction);
543  #endif
544 
545  myKey=find_key(kin,(float)(px->set_fraction),px->key.p);
546  #ifdef SEVERBOSE
547  printf ("working on key %d\n",myKey);
548  #endif
549 
550  /* find the fraction between the 2 values */
551  interval = (px->set_fraction - px->key.p[myKey-1]) /
552  (px->key.p[myKey] - px->key.p[myKey-1]);
553 
554  for (indx = 0; indx < kpkv; indx++) {
555  thisone = myKey * kpkv + indx;
556  prevone = (myKey-1) * kpkv + indx;
557 
558  #ifdef SEVERBOSE
559  if (thisone >= kvin) {
560  printf ("CoordinateInterpolator error: thisone %d prevone %d indx %d kpkv %d kin %d kvin %d\n",thisone,prevone,
561  indx,kpkv,kin,kvin);
562  }
563  #endif
564 
565  for (tmp=0; tmp<3; tmp++) {
566  valchanged[indx].c[tmp] = kVs[prevone].c[tmp] +
567  interval * (kVs[thisone].c[tmp] -
568  kVs[prevone].c[tmp]);
569  }
570  #ifdef SEVERBOSE
571  printf (" 1 %d interval %f prev %f this %f final %f\n",1,interval,kVs[prevone].c[1],kVs[thisone].c[1],valchanged[indx].c[1]);
572  #endif
573  }
574  #ifdef SEVERBOSE
575  printf ("COINT out3 finished\n");
576  #endif
577 
578  }
579 
580  #ifdef SEVERBOSE
581  printf ("Done CoordinateInterpolator\n");
582  #endif
583 }
584 
585 void do_OintCoord2D(void *node) {
586  struct X3D_CoordinateInterpolator2D *px;
587  int kin, kvin/* , counter */;
588  struct SFVec2f *kVs;
589  struct SFVec2f *valchanged;
590 
591  int thisone, prevone; /* which keyValues we are interpolating between */
592  int tmp;
593  float interval; /* where we are between 2 values */
594  int kpkv; /* keys per key value */
595  int indx;
596  int myKey;
597 
598  if (!node) return;
599  px = (struct X3D_CoordinateInterpolator2D *) node;
600 
601 
602  #ifdef SEVERBOSE
603  printf ("debugging OintCoord keys %d kv %d vc %d\n",px->keyValue.n, px->key.n,px->value_changed.n);
604  #endif
605 
606  MARK_EVENT (node, offsetof (struct X3D_CoordinateInterpolator2D, value_changed));
607 
608  kin = px->key.n;
609  kvin = px->keyValue.n;
610  kVs = px->keyValue.p;
611  kpkv = kvin/kin;
612 
613  /* do we need to (re)allocate the value changed array? */
614  if (kpkv != px->value_changed.n) {
615  #ifdef SEVERBOSE
616  printf ("refactor valuechanged array. n %d sizeof p %d\n",
617  kpkv,sizeof (struct SFVec2f) * kpkv);
618  #endif
619  if (px->value_changed.n != 0) {
620  FREE_IF_NZ (px->value_changed.p);
621  }
622  px->value_changed.n = kpkv;
623  px->value_changed.p = MALLOC (struct SFVec2f*, sizeof (struct SFVec2f) * kpkv);
624  }
625 
626  /* shortcut valchanged; have to put it here because might be reMALLOC'd */
627  valchanged = px->value_changed.p;
628 
629 
630  /* make sure we have the keys and keyValues */
631  if ((kvin == 0) || (kin == 0)) {
632  #ifdef SEVERBOSE
633  printf ("no keys or keyValues yet\n");
634  #endif
635 
636  for (indx = 0; indx < kpkv; indx++) {
637  valchanged[indx].c[0] = (float) 0.0;
638  valchanged[indx].c[1] = (float) 0.0;
639  }
640  return;
641  }
642  if (kin>kvin) kin=kvin; /* means we don't use whole of keyValue, but... */
643 
644 
645  #ifdef SEVERBOSE
646  printf ("debugging, kpkv %d, px->value_changed.n %d\n", kpkv, px->value_changed.n);
647  printf ("CoordinateInterpolator2D, kpkv %d\n",kpkv);
648  #endif
649 
650 
651  /* set_fraction less than or greater than keys */
652  if (px->set_fraction <= px->key.p[0]) {
653  #ifdef SEVERBOSE
654  printf ("COINT out1\n");
655  #endif
656 
657  for (indx = 0; indx < kpkv; indx++) {
658  memcpy ((void *)&valchanged[indx],
659  (void *)&kVs[indx], sizeof (struct SFVec2f));
660  /* JAS valchanged[indx].c[0] = kVs[indx].c[0]; */
661  /* JAS valchanged[indx].c[1] = kVs[indx].c[1]; */
662  }
663  #ifdef SEVERBOSE
664  printf ("COINT out1 copied\n");
665  #endif
666  } else if (px->set_fraction >= px->key.p[kin-1]) {
667  #ifdef SEVERBOSE
668  printf ("COINT out2\n");
669  #endif
670 
671  for (indx = 0; indx < kpkv; indx++) {
672  memcpy ((void *)&valchanged[indx],
673  (void *)&kVs[kvin-kpkv+indx],
674  sizeof (struct SFVec2f));
675  }
676  #ifdef SEVERBOSE
677  printf ("COINT out2 finished\n");
678  #endif
679  } else {
680  #ifdef SEVERBOSE
681  printf ("COINT out3\n");
682  #endif
683 
684  /* have to go through and find the key before */
685  #ifdef SEVERBOSE
686  printf ("indx=0, kin %d frac %f\n",kin,px->set_fraction);
687  #endif
688 
689  myKey=find_key(kin,(float)(px->set_fraction),px->key.p);
690  #ifdef SEVERBOSE
691  printf ("working on key %d\n",myKey);
692  #endif
693 
694  /* find the fraction between the 2 values */
695  interval = (px->set_fraction - px->key.p[myKey-1]) /
696  (px->key.p[myKey] - px->key.p[myKey-1]);
697 
698  for (indx = 0; indx < kpkv; indx++) {
699  thisone = myKey * kpkv + indx;
700  prevone = (myKey-1) * kpkv + indx;
701 
702  #ifdef SEVERBOSE
703  if (thisone >= kvin) {
704  printf ("CoordinateInterpolator2D error: thisone %d prevone %d indx %d kpkv %d kin %d kvin %d\n",thisone,prevone,
705  indx,kpkv,kin,kvin);
706  }
707  #endif
708 
709  for (tmp=0; tmp<2; tmp++) {
710  valchanged[indx].c[tmp] = kVs[prevone].c[tmp] +
711  interval * (kVs[thisone].c[tmp] -
712  kVs[prevone].c[tmp]);
713  }
714  }
715  #ifdef SEVERBOSE
716  printf ("COINT out3 finished\n");
717  #endif
718 
719  }
720 
721  #ifdef SEVERBOSE
722  printf ("Done CoordinateInterpolator2D\n");
723  #endif
724 }
725 
726 void do_OintPos2D(void *node) {
727 /* PositionInterpolator2D */
728 /* Called during the "events_processed" section of the event loop, */
729 /* so this is called ONLY when there is something required to do, thus */
730 /* there is no need to look at whether it is active or not */
731 
732  struct X3D_PositionInterpolator2D *px;
733  int kin, kvin, counter, tmp;
734  struct SFVec2f *kVs;
735 
736  if (!node) return;
737  px = (struct X3D_PositionInterpolator2D *) node;
738 
739  MARK_EVENT (node, offsetof (struct X3D_PositionInterpolator2D, value_changed));
740 
741  kin = px->key.n;
742  kvin = px->keyValue.n;
743  kVs = px->keyValue.p;
744 
745  #ifdef SEVERBOSE
746  printf("do_Oint2: Position interp2D, node %u kin %d kvin %d set_fraction %f\n",
747  node, kin, kvin, px->set_fraction);
748  #endif
749 
750  /* make sure we have the keys and keyValues */
751  if ((kvin == 0) || (kin == 0)) {
752  px->value_changed.c[0] = (float) 0.0;
753  px->value_changed.c[1] = (float) 0.0;
754  return;
755  }
756  if (kin>kvin) kin=kvin; /* means we don't use whole of keyValue, but... */
757 
758 
759  /* set_fraction less than or greater than keys */
760  if (px->set_fraction <= ((px->key).p[0])) {
761  memcpy ((void *)&px->value_changed,
762  (void *)&kVs[0], sizeof (struct SFVec2f));
763  } else if (px->set_fraction >= px->key.p[kin-1]) {
764  memcpy ((void *)&px->value_changed,
765  (void *)&kVs[kvin-1], sizeof (struct SFVec2f));
766  } else {
767  /* have to go through and find the key before */
768  counter = find_key(kin,((float)(px->set_fraction)),px->key.p);
769  for (tmp=0; tmp<2; tmp++) {
770  px->value_changed.c[tmp] =
771  (px->set_fraction - px->key.p[counter-1]) /
772  (px->key.p[counter] - px->key.p[counter-1]) *
773  (kVs[counter].c[tmp] -
774  kVs[counter-1].c[tmp]) +
775  kVs[counter-1].c[tmp];
776  }
777  }
778  #ifdef SEVERBOSE
779  printf ("Pos/Col, new value (%f %f)\n",
780  px->value_changed.c[0],px->value_changed.c[1]);
781  #endif
782 }
783 
784 /* PositionInterpolator, ColorInterpolator, GeoPositionInterpolator */
785 /* Called during the "events_processed" section of the event loop, */
786 /* so this is called ONLY when there is something required to do, thus */
787 /* there is no need to look at whether it is active or not */
788 
789 /* GeoPositionInterpolator in the Component_Geospatial file */
790 
791 /* ColorInterpolator == PositionIterpolator */
792 void do_ColorInterpolator (void *node) {
793  struct X3D_ColorInterpolator *px;
794  int kin, kvin, counter, tmp;
795  struct SFColor *kVs;
796 
797  if (!node) return;
798  px = (struct X3D_ColorInterpolator *) node;
799 
800  kvin = px->keyValue.n;
801  kVs = px->keyValue.p;
802  kin = px->key.n;
803 
804  MARK_EVENT (node, offsetof (struct X3D_ColorInterpolator, value_changed));
805 
806  #ifdef SEVERBOSE
807  printf("do_ColorInt: Position/Color interp, node %u kin %d kvin %d set_fraction %f\n",
808  node, kin, kvin, px->set_fraction);
809  #endif
810 
811  /* make sure we have the keys and keyValues */
812  if ((kvin == 0) || (kin == 0)) {
813  px->value_changed.c[0] = (float) 0.0;
814  px->value_changed.c[1] = (float) 0.0;
815  px->value_changed.c[2] = (float) 0.0;
816  return;
817  }
818 
819  if (kin>kvin) kin=kvin; /* means we don't use whole of keyValue, but... */
820 
821  /* set_fraction less than or greater than keys */
822  if (px->set_fraction <= ((px->key).p[0])) {
823  memcpy ((void *)&px->value_changed, (void *)&kVs[0], sizeof (struct SFColor));
824  } else if (px->set_fraction >= px->key.p[kin-1]) {
825  memcpy ((void *)&px->value_changed, (void *)&kVs[kvin-1], sizeof (struct SFColor));
826  } else {
827  /* have to go through and find the key before */
828  counter = find_key(kin,((float)(px->set_fraction)),px->key.p);
829  for (tmp=0; tmp<3; tmp++) {
830  px->value_changed.c[tmp] =
831  (px->set_fraction - px->key.p[counter-1]) /
832  (px->key.p[counter] - px->key.p[counter-1]) *
833  (kVs[counter].c[tmp] - kVs[counter-1].c[tmp]) + kVs[counter-1].c[tmp];
834  }
835  }
836  #ifdef SEVERBOSE
837  printf ("Pos/Col, new value (%f %f %f)\n",
838  px->value_changed.c[0],px->value_changed.c[1],px->value_changed.c[2]);
839  #endif
840 }
841 
842 
843 void do_PositionInterpolator (void *node) {
844  struct X3D_PositionInterpolator *px;
845  int kin, kvin, counter, tmp;
846  struct SFVec3f *kVs;
847 
848  if (!node) return;
849  px = (struct X3D_PositionInterpolator *) node;
850 
851  kvin = px->keyValue.n;
852  kVs = px->keyValue.p;
853  kin = px->key.n;
854 
855  MARK_EVENT (node, offsetof (struct X3D_PositionInterpolator, value_changed));
856 
857  #ifdef SEVERBOSE
858  printf("do_PositionInt: Position/Vec3f interp, node %u kin %d kvin %d set_fraction %f\n",
859  node, kin, kvin, px->set_fraction);
860  #endif
861 
862  /* make sure we have the keys and keyValues */
863  if ((kvin == 0) || (kin == 0)) {
864  px->value_changed.c[0] = (float) 0.0;
865  px->value_changed.c[1] = (float) 0.0;
866  px->value_changed.c[2] = (float) 0.0;
867  return;
868  }
869 
870  if (kin>kvin) kin=kvin; /* means we don't use whole of keyValue, but... */
871 
872  /* set_fraction less than or greater than keys */
873  if (px->set_fraction <= ((px->key).p[0])) {
874  memcpy ((void *)&px->value_changed, (void *)&kVs[0], sizeof (struct SFVec3f));
875  } else if (px->set_fraction >= px->key.p[kin-1]) {
876  memcpy ((void *)&px->value_changed, (void *)&kVs[kvin-1], sizeof (struct SFVec3f));
877  } else {
878  /* have to go through and find the key before */
879  counter = find_key(kin,((float)(px->set_fraction)),px->key.p);
880  for (tmp=0; tmp<3; tmp++) {
881  px->value_changed.c[tmp] =
882  (px->set_fraction - px->key.p[counter-1]) /
883  (px->key.p[counter] - px->key.p[counter-1]) *
884  (kVs[counter].c[tmp] - kVs[counter-1].c[tmp]) + kVs[counter-1].c[tmp];
885  }
886  }
887  #ifdef SEVERBOSE
888  printf ("Pos/Col, new value (%f %f %f)\n",
889  px->value_changed.c[0],px->value_changed.c[1],px->value_changed.c[2]);
890  #endif
891 }
892 
893 /* OrientationInterpolator */
894 /* Called during the "events_processed" section of the event loop, */
895 /* so this is called ONLY when there is something required to do, thus */
896 /* there is no need to look at whether it is active or not */
897 
898 void do_Oint4 (void *node) {
899  struct X3D_OrientationInterpolator *px;
900  int kin, kvin;
901  struct SFRotation *kVs;
902  int counter;
903  float interval; /* where we are between 2 values */
904  // UNUSED?? int stzero;
905  // UNUSED?? int endzero; /* starting and/or ending angles zero? */
906 
907  Quaternion st, fin, final;
908  double x,y,z,a;
909 
910  if (!node) return;
911  px = (struct X3D_OrientationInterpolator *) node;
912  kin = ((px->key).n);
913  kvin = ((px->keyValue).n);
914  kVs = ((px->keyValue).p);
915 
916  #ifdef SEVERBOSE
917  printf ("starting do_Oint4; keyValue count %d and key count %d\n",
918  kvin, kin);
919  #endif
920 
921 
922  MARK_EVENT (node, offsetof (struct X3D_OrientationInterpolator, value_changed));
923 
924  /* make sure we have the keys and keyValues */
925  if ((kvin == 0) || (kin == 0)) {
926  px->value_changed.c[0] = (float) 0.0;
927  px->value_changed.c[1] = (float) 0.0;
928  px->value_changed.c[2] = (float) 0.0;
929  px->value_changed.c[3] = (float) 0.0;
930  return;
931  }
932  if (kin>kvin) kin=kvin; /* means we don't use whole of keyValue, but... */
933 
934 
935  /* set_fraction less than or greater than keys */
936  if (px->set_fraction <= ((px->key).p[0])) {
937  memcpy ((void *)&px->value_changed,
938  (void *)&kVs[0], sizeof (struct SFRotation));
939  } else if (px->set_fraction >= ((px->key).p[kin-1])) {
940  memcpy ((void *)&px->value_changed,
941  (void *)&kVs[kvin-1], sizeof (struct SFRotation));
942  } else {
943  counter = find_key(kin,(float)(px->set_fraction),px->key.p);
944  interval = (px->set_fraction - px->key.p[counter-1]) /
945  (px->key.p[counter] - px->key.p[counter-1]);
946 
947 
948  /* are either the starting or ending angles zero? */
949  // unused? stzero = APPROX(kVs[counter-1].c[3],0.0);
950  // unused? endzero = APPROX(kVs[counter].c[3],0.0);
951  #ifdef SEVERBOSE
952  printf ("counter %d interval %f\n",counter,interval);
953  printf ("angles %f %f %f %f, %f %f %f %f\n",
954  kVs[counter-1].c[0],
955  kVs[counter-1].c[1],
956  kVs[counter-1].c[2],
957  kVs[counter-1].c[3],
958  kVs[counter].c[0],
959  kVs[counter].c[1],
960  kVs[counter].c[2],
961  kVs[counter].c[3]);
962  #endif
963  vrmlrot_to_quaternion (&st, kVs[counter-1].c[0],
964  kVs[counter-1].c[1], kVs[counter-1].c[2], kVs[counter-1].c[3]);
965  vrmlrot_to_quaternion (&fin,kVs[counter].c[0],
966  kVs[counter].c[1], kVs[counter].c[2], kVs[counter].c[3]);
967 
968  quaternion_slerp(&final, &st, &fin, (double)interval);
969  quaternion_to_vrmlrot(&final,&x, &y, &z, &a);
970  px->value_changed.c[0] = (float) x;
971  px->value_changed.c[1] = (float) y;
972  px->value_changed.c[2] = (float) z;
973  px->value_changed.c[3] = (float) a;
974 
975  #ifdef SEVERBOSE
976  printf ("Oint, new angle %f %f %f %f\n",px->value_changed.c[0],
977  px->value_changed.c[1],px->value_changed.c[2], px->value_changed.c[3]);
978  #endif
979  }
980 }
981 
982 /* fired at start of event loop for every Collision */
983 /* void do_CollisionTick(struct X3D_Collision *cx) {*/
984 void do_CollisionTick( void *ptr) {
985  struct X3D_Collision *cx = (struct X3D_Collision *)ptr;
986  if (cx->__hit == 3) {
987  /* printf ("COLLISION at %f\n",TickTime()); */
988  cx->collideTime = TickTime();
989  MARK_EVENT (ptr, offsetof(struct X3D_Collision, collideTime));
990  }
991 }
992 
993 
994 /* Audio AudioClip sensor code */
995 /* void do_AudioTick(struct X3D_AudioClip *node) {*/
996 void do_AudioTick(void *ptr) {
997  struct X3D_AudioClip *node = (struct X3D_AudioClip *)ptr;
998  int oldstatus;
999  double pitch, duration; /* gcc and params - make all doubles to do_active_inactive */
1000 
1001  /* can we possibly have started yet? */
1002  if (!node) return;
1003 
1004  if(node->__inittime == 0.0)
1005  node->__inittime = TickTime();
1006 
1007  if(TickTime() < node->startTime) {
1008  return;
1009  }
1010 
1011  oldstatus = node->isActive;
1012  pitch = node->pitch;
1013 
1014  if(node->__sourceNumber < 0) return;
1016  //if (node->__sourceNumber == -1) {
1017  // locateAudioSource (node);
1018  // /* printf ("do_AudioTick, node %d sn %d\n", node, node->__sourceNumber); */
1019  //}
1020 
1022  // * between 0 and infinity; if it is BADAUDIOSOURCE, bad source.
1023  // * check out locateAudioSource to find out reasons */
1024  //if (node->__sourceNumber == BADAUDIOSOURCE) return;
1025 
1026  /* call common time sensor routine */
1027  //duration = return_Duration(node->__sourceNumber);
1028  duration = return_Duration(node);
1029  do_active_inactive (
1030  &node->isActive, &node->__inittime, &node->startTime,
1031  &node->stopTime,node->loop,duration,
1032  pitch,node->elapsedTime);
1033 
1034  if (oldstatus != node->isActive) {
1035  /* push @e, [$t, "isActive", node->{isActive}]; */
1036  if (node->isActive == 1) {
1037  /* force code below to generate event */
1038  //node->__ctflag = 10.0;
1039  node->__lasttime = TickTime();
1040  node->elapsedTime = 0.0;
1041  }
1042  MARK_EVENT (X3D_NODE(node), offsetof(struct X3D_AudioClip, isActive));
1043  }
1044 
1045  if(node->isActive){
1046  if(node->pauseTime > node->startTime){
1047  if( node->resumeTime < node->pauseTime && !node->isPaused){
1048  node->isPaused = TRUE;
1049  MARK_EVENT (X3D_NODE(node), offsetof(struct X3D_AudioClip, isPaused));
1050  }else if(node->resumeTime > node->pauseTime && node->isPaused){
1051  node->isPaused = FALSE;
1052  node->__lasttime = TickTime();
1053  MARK_EVENT (X3D_NODE(node), offsetof(struct X3D_AudioClip, isPaused));
1054  }
1055  }
1056  }
1057  if(node->isActive == 1 && node->isPaused == FALSE) {
1058  double dtime = TickTime();
1059  node->elapsedTime += dtime - node->__lasttime;
1060  node->__lasttime = dtime;
1061  //double myFrac = node->elapsedTime / duration;
1062  MARK_EVENT (ptr, offsetof(struct X3D_AudioClip, elapsedTime));
1063  }
1064 }
1065 
1066 
1067 
1068 /* Similar to AudioClip, this is the Play, Pause, Stop, Resume code
1069 */
1070 #define LOAD_STABLE 10 //from component_sound.c
1071 unsigned char *movietexture_get_frame_by_fraction(struct X3D_Node* node, float fraction, int *width, int *height, int *nchan);
1072 void do_MovieTextureTick( void *ptr) {
1073  struct X3D_MovieTexture *node = (struct X3D_MovieTexture *)ptr;
1074  //struct X3D_AudioClip *anode;
1075  int oldstatus;
1076  float frac; /* which texture to display */
1077  //int highest,lowest; /* selector variables */
1078  double myFrac;
1079  double speed;
1080  double duration;
1081  int tmpTrunc; /* used for timing for textures */
1082 
1083  //anode = (struct X3D_AudioClip *)node;
1084  //do_AudioTick(ptr); //does play, pause, active, inactive part
1085 
1086  /* can we possibly have started yet? */
1087  if (!node) return;
1088 
1089  if(node->__inittime == 0.0)
1090  node->__inittime = TickTime();
1091 
1092  if(TickTime() < node->startTime) {
1093  return;
1094  }
1095 
1096 // duration = (highest - lowest)/30.0;
1097  //highest = node->__highest;
1098  //lowest = node->__lowest;
1099  duration = node->duration_changed; //return_Duration(node);
1100  speed = node->speed;
1101 
1102  oldstatus = node->isActive;
1103  do_active_inactive (
1104  &node->isActive, &node->__inittime, &node->startTime,
1105  &node->stopTime,node->loop,duration,
1106  speed,node->elapsedTime);
1107 
1108  if (oldstatus != node->isActive) {
1109  if (node->isActive == 1) {
1110  /* force code below to generate event */
1111  //node->__ctflag = 10.0;
1112  node->__lasttime = TickTime();
1113  node->elapsedTime = 0.0;
1114  }
1115  MARK_EVENT (X3D_NODE(node), offsetof(struct X3D_MovieTexture, isActive));
1116  }
1117 
1118  if(node->isActive){
1119  if(node->pauseTime > node->startTime){
1120  if( node->resumeTime < node->pauseTime && !node->isPaused){
1121  node->isPaused = TRUE;
1122  MARK_EVENT (X3D_NODE(node), offsetof(struct X3D_MovieTexture, isPaused));
1123  }else if(node->resumeTime > node->pauseTime && node->isPaused){
1124  node->isPaused = FALSE;
1125  node->__lasttime = TickTime();
1126  MARK_EVENT (X3D_NODE(node), offsetof(struct X3D_MovieTexture, isPaused));
1127  }
1128  }
1129  }
1130  if(node->isActive && node->isPaused == FALSE) {
1131  double dtime = TickTime();
1132  node->elapsedTime += dtime - node->__lasttime;
1133  node->__lasttime = dtime;
1134 
1135  //frac = node->__ctex;
1136 
1138  //if (node->__lowest >= node->__highest) {
1139  // node->__lowest = node->__highest-1;
1140  //}
1141  /* calculate what fraction we should be */
1142  // t = (now - startTime) modulo (duration/speed)
1143  myFrac = node->elapsedTime / duration;
1144  //myTime = (TickTime() - node->startTime) * speed/duration;
1145  tmpTrunc = (int) myFrac;
1146  frac = (float)myFrac - (float)tmpTrunc;
1147  /* negative speed? */
1148  if (speed < 0) {
1149  frac = 1.0f + frac; /* frac will be *negative* */
1150  /* else if (speed == 0) */
1151  } else if (APPROX(speed, 0.0f)) {
1152  frac = 0.0f;
1153  }
1154  node->__frac = frac;
1155  //clamp to last frame when not looping, so at end of show last frame sticks as per specs
1156  if(node->loop == FALSE && tmpTrunc > 0)
1157  node->__frac = 1.0f;
1158  //printf("tmptnk=%d frac=%f ",tmpTrunc,node->__frac);
1159  //node->elapsedTime = TickTime() - node->startTime;
1160  //printf("/ et %lf /",node->elapsedTime);
1161  MARK_EVENT (ptr, offsetof(struct X3D_MovieTexture, elapsedTime));
1162  }
1163  if(node->__loadstatus == LOAD_STABLE){
1164  //Nov 16, 2016 the following works with MPEG_Utils_ffmpeg.c on non-audio mpeg (vts.mpg)
1165  // x not tested with audio
1166  unsigned char* texdata;
1167  int width,height,nchan;
1169  texdata = movietexture_get_frame_by_fraction(X3D_NODE(node), node->__frac, &width, &height, &nchan);
1170  if(texdata){
1171  int thisTexture = node->__textureTableIndex;
1172  tti = getTableIndex(thisTexture);
1173  if(tti){
1174  static int once = 0;
1175  tti->x = width;
1176  tti->y = height;
1177  tti->z = 1;
1178  tti->channels = nchan;
1179  if(!once){
1180  //send it through textures.c once to get things like wrap set
1181  // textures.c likes to free texdata, so we'll deep copy
1182  tti->texdata = malloc(tti->x*tti->y*tti->channels);
1183  memcpy(tti->texdata,texdata,tti->x*tti->y*tti->channels);
1184  tti->status = TEX_NEEDSBINDING;
1185  once = 1;
1186  }else{
1187  tti->status = TEX_LOADED;
1188  glBindTexture(GL_TEXTURE_2D,tti->OpenGLTexture);
1189  //disable the mipmapping done on the once pass through textures.c above
1190  FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1191  FW_GL_TEXPARAMETERI( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1192  //replace the texture data every frame when we are isActive and not paused
1193  //we do this once per frame in startofloopnodeupdates call stack
1194  //(not per render call: we want the same texture to show in left/right or quad display viewports)
1195  if(nchan == 4)
1196  glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,texdata);
1197  if(nchan == 3)
1198  glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,width,height,0,GL_RGB,GL_UNSIGNED_BYTE,texdata);
1199  glBindTexture(GL_TEXTURE_2D,0);
1200  }
1201  }
1202  }
1203 
1204  }
1205 }
1206 
1207 
1208 /****************************************************************************
1209 
1210  Sensitive nodes
1211 
1212 *****************************************************************************/
1213 void do_TouchSensor ( void *ptr, int ev, int but1, int over) {
1214 
1215  struct X3D_TouchSensor *node = (struct X3D_TouchSensor *)ptr;
1216  struct point_XYZ normalval; /* different structures for normalization calls */
1217  ttglobal tg;
1218  #ifdef SENSVERBOSE
1219  printf ("%lf: TS ",TickTime());
1220  if (ev==ButtonPress) printf ("ButtonPress ");
1221  else if (ev==ButtonRelease) printf ("ButtonRelease ");
1222  else if (ev==KeyPress) printf ("KeyPress ");
1223  else if (ev==KeyRelease) printf ("KeyRelease ");
1224  else if (ev==MotionNotify) printf ("%lf MotionNotify ");
1225  else printf ("ev %d ",ev);
1226 
1227  if (but1) printf ("but1 TRUE "); else printf ("but1 FALSE ");
1228  if (over) printf ("over TRUE "); else printf ("over FALSE ");
1229  printf ("\n");
1230  #endif
1231 
1232 
1233  /* if not enabled, do nothing */
1234  if (!node) return;
1235  if (node->__oldEnabled != node->enabled) {
1236  node->__oldEnabled = node->enabled;
1237  MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_TouchSensor, enabled));
1238  }
1239  if (!node->enabled) return;
1240  tg = gglobal();
1241  /* isOver state */
1242  if ((ev == overMark) && (over != node->isOver)) {
1243  #ifdef SENSVERBOSE
1244  printf ("TS %u, isOver changed %d\n",node, over);
1245  #endif
1246  node->isOver = over;
1247  MARK_EVENT (ptr, offsetof (struct X3D_TouchSensor, isOver));
1248  }
1249 
1250  /* active */
1251  /* button presses */
1252  if (ev == ButtonPress) {
1253  node->isActive=TRUE;
1254  MARK_EVENT (ptr, offsetof (struct X3D_TouchSensor, isActive));
1255  #ifdef SENSVERBOSE
1256  printf ("touchSens %u, butPress\n",node);
1257  #endif
1258 
1259  node->touchTime = TickTime();
1260  MARK_EVENT(ptr, offsetof (struct X3D_TouchSensor, touchTime));
1261 
1262  } else if (ev == ButtonRelease) {
1263  #ifdef SENSVERBOSE
1264  printf ("touchSens %u, butRelease\n",node);
1265  #endif
1266  node->isActive=FALSE;
1267  MARK_EVENT (ptr, offsetof (struct X3D_TouchSensor, isActive));
1268  }
1269 
1270  /* hitPoint and hitNormal */
1271  /* save the current hitPoint for determining if this changes between runs */
1272  memcpy ((void *) &node->_oldhitPoint, (void *) &tg->RenderFuncs.ray_save_posn,sizeof(struct SFColor));
1273 
1274  /* did the hitPoint change between runs? */
1275  if ((APPROX(node->_oldhitPoint.c[0],node->hitPoint_changed.c[0])!= TRUE) ||
1276  (APPROX(node->_oldhitPoint.c[1],node->hitPoint_changed.c[1])!= TRUE) ||
1277  (APPROX(node->_oldhitPoint.c[2],node->hitPoint_changed.c[2])!= TRUE)) {
1278 
1279  memcpy ((void *) &node->hitPoint_changed, (void *) &node->_oldhitPoint, sizeof(struct SFColor));
1280  MARK_EVENT(ptr, offsetof (struct X3D_TouchSensor, hitPoint_changed));
1281  }
1282 
1283  /* have to normalize normal; change it from SFColor to struct point_XYZ. */
1284  normalval.x = tg->RenderFuncs.hyp_save_norm[0];
1285  normalval.y = tg->RenderFuncs.hyp_save_norm[1];
1286  normalval.z = tg->RenderFuncs.hyp_save_norm[2];
1287  normalize_vector(&normalval);
1288  node->_oldhitNormal.c[0] = (float) normalval.x;
1289  node->_oldhitNormal.c[1] = (float) normalval.y;
1290  node->_oldhitNormal.c[2] = (float) normalval.z;
1291 
1292  /* did the hitNormal change between runs? */
1293  if ((APPROX(node->_oldhitNormal.c[0],node->hitNormal_changed.c[0])!= TRUE) ||
1294  (APPROX(node->_oldhitNormal.c[1],node->hitNormal_changed.c[1])!= TRUE) ||
1295  (APPROX(node->_oldhitNormal.c[2],node->hitNormal_changed.c[2])!= TRUE)) {
1296 
1297  memcpy ((void *) &node->hitNormal_changed, (void *) &node->_oldhitNormal, sizeof(struct SFColor));
1298  MARK_EVENT(ptr, offsetof (struct X3D_TouchSensor, hitNormal_changed));
1299  }
1300 }
1301 
1302 
1303 void do_LineSensor(void *ptr, int ev, int but1, int over) {
1304  /* There is no LineSensor node in the specs in April 2014. X3Dom guru Max Limper complained
1305  on X3DPublic about how PlaneSensor fails as an axis mover in the degenerate case of
1306  looking edge-on at the planeSensor. The solution we (dug9) came up with was LineSensor,
1307  which also has a degenerate case (when looking end-on at the Line), but that degerate
1308  case is more normal for users - more intuitive.
1309  LineSensor is the same as PlaneSensor, except minPosition and maxPosition are floats,
1310  and LineSensor uses a SFVec3f .direction field to say which way the Line is oriented
1311  in local-sensor coordinates. In April 2014, Paulo added LineSensor to the perl generator,
1312  and dug9 implemented it here.
1313  */
1314  struct X3D_LineSensor *node;
1315  float trackpoint[3], translation[3], xxx;
1316  //struct SFColor tr;
1317  //int tmp;
1318  ttglobal tg;
1319  UNUSED(over);
1320  node = (struct X3D_LineSensor *)ptr;
1321 #ifdef SENSVERBOSE
1322  printf("%lf: TS ", TickTime());
1323  if (ev == ButtonPress) printf("ButtonPress ");
1324  else if (ev == ButtonRelease) printf("ButtonRelease ");
1325  else if (ev == KeyPress) printf("KeyPress ");
1326  else if (ev == KeyRelease) printf("KeyRelease ");
1327  else if (ev == MotionNotify) printf("%lf MotionNotify ");
1328  else printf("ev %d ", ev);
1329 
1330  if (but1) printf("but1 TRUE "); else printf("but1 FALSE ");
1331  if (over) printf("over TRUE "); else printf("over FALSE ");
1332  printf("\n");
1333 #endif
1334 
1335  /* if not enabled, do nothing */
1336  if (!node) return;
1337 
1338  if (node->__oldEnabled != node->enabled) {
1339  node->__oldEnabled = node->enabled;
1340  MARK_EVENT(X3D_NODE(node), offsetof(struct X3D_LineSensor, enabled));
1341  }
1342  if (!node->enabled) return;
1343  tg = gglobal();
1344 
1345  /* only do something when button pressed */
1346  /* if (!but1) return; */
1347  if (but1){
1348  //pre-calculate for Press and Move
1349  /* hyperhit saved in render_hypersensitive phase */
1350  // bearing in sensor-local coordinates: (A=posn,B=norm)
1351  // B/norm is a point, so to get a direction vector: v = B - A
1352  float tt;
1353  float origin [] = { 0.0f, 0.0f, 0.0f };
1354  float footpoint2[3], footpoint1[3], v1[3]; //, temp[3], temp2[3];
1355  vecdif3f(v1, tg->RenderFuncs.hyp_save_norm, tg->RenderFuncs.hyp_save_posn);
1356  vecnormalize3f(v1, v1);
1357  if (!line_intersect_line_3f(tg->RenderFuncs.hyp_save_posn, v1,
1358  origin, node->direction.c, NULL, &tt, footpoint1, footpoint2))
1359  return; //no intersection, lines are parallel
1360  //footpoint1 - closest point of intersection on the A'B' bearing
1361  //footpoint2 - closest point of intersection on the Line (0,0,0)(LineSensor.direction)
1362  //tt is scale of unit vector from origin to footpoint2
1363  xxx = tt;
1364  veccopy3f(trackpoint,footpoint2); //unclamped intersection with Sensor geometry, for trackpoint
1365  }
1366  if ((ev == ButtonPress) && but1) {
1367  /* record the current position from the saved position */
1368 #define LINESENSOR_FLOAT_OFFSET 1
1369 #ifndef LINESENSOR_FLOAT_OFFSET
1370  struct SFColor op;
1371  veccopy3f(op.c, trackpoint);
1372  memcpy((void *)&node->_origPoint, (void *)&op,sizeof(struct SFColor));
1373  // (void *)&tg->RenderFuncs.ray_save_posn, sizeof(struct SFColor));
1374 #else
1375  node->_origPoint.c[0] = xxx;
1376  //in case we go from mousedown to mouseup without mousemove:
1377  if (node->autoOffset)
1378  node->_origPoint.c[1] = node->offset;
1379  else
1380  node->_origPoint.c[1] = 0.0f;
1381 #endif
1382  /* set isActive true */
1383  node->isActive = TRUE;
1384  MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, isActive));
1385 
1386  }
1387  else if ((ev == MotionNotify) && (node->isActive) && but1) {
1388  float xxxoffset, xxxorigin;
1389  //float diroffset[3], nondiroffset[3];
1390  /* trackpoint changed */
1391  node->_oldtrackPoint.c[0] = trackpoint[0];
1392  node->_oldtrackPoint.c[1] = trackpoint[1];
1393  node->_oldtrackPoint.c[2] = trackpoint[2];
1394 
1395  if ((APPROX(node->_oldtrackPoint.c[0], node->trackPoint_changed.c[0]) != TRUE) ||
1396  (APPROX(node->_oldtrackPoint.c[1], node->trackPoint_changed.c[1]) != TRUE) ||
1397  (APPROX(node->_oldtrackPoint.c[2], node->trackPoint_changed.c[2]) != TRUE)) {
1398 
1399  memcpy((void *)&node->trackPoint_changed, (void *)&node->_oldtrackPoint, sizeof(struct SFColor));
1400  MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, trackPoint_changed));
1401 
1402  }
1403 
1404  //clamp to min,max
1405 #ifdef LINESENSOR_FLOAT_OFFSET
1406  xxxoffset = node->offset;
1407  xxxorigin = node->_origPoint.c[0];
1408 #else
1409  //in theory the user can set a non-autoOffset sfvec3f offset that's not along .direction
1410  //- we accomodate that below^, so here we just use the part going along .direction
1411  xxxoffset = vecdot3f(node->direction.c,node->offset.c); //xxxoffset - like web3d specs offset, except just along direction vector
1412  xxxorigin = vecdot3f(node->direction.c,node->_origPoint.c); //mouse-down origin
1413 #endif
1414  //xxx before: unclamped position from line origin
1415  xxx -= xxxorigin; //xxx after: net drag/delta along line since mouse-down
1416  xxx += xxxoffset; //xxx after: cumulative position along line (from line 0) after any/all mousedown/drag sequences
1417  if (node->maxPosition >= node->minPosition) {
1418  if (xxx < node->minPosition) {
1419  xxx = node->minPosition;
1420  }
1421  else if (xxx > node->maxPosition) {
1422  xxx = node->maxPosition;
1423  }
1424  }
1425  //translation clamped to LineSensor.minPosition/.maxPosition
1426  vecscale3f(translation, node->direction.c, xxx);
1427 
1428 #ifndef LINESENSOR_FLOAT_OFFSET
1429  //^add on any non-autoOffset non-.direction offset
1430  //a) part of offset going along direction
1431  vecscale3f(diroffset, node->direction.c, xxxoffset);
1432  //b) part of offset not going along direction
1433  vecdif3f(nondiroffset, node->offset.c, diroffset);
1434  //add non-direction part of offset
1435  vecadd3f(translation, translation, nondiroffset);
1436 #endif
1437 
1438  node->_oldtranslation.c[0] = translation[0];
1439  node->_oldtranslation.c[1] = translation[1];
1440  node->_oldtranslation.c[2] = translation[2];
1441 
1442  if ((APPROX(node->_oldtranslation.c[0], node->translation_changed.c[0]) != TRUE) ||
1443  (APPROX(node->_oldtranslation.c[1], node->translation_changed.c[1]) != TRUE) ||
1444  (APPROX(node->_oldtranslation.c[2], node->translation_changed.c[2]) != TRUE)) {
1445 
1446  memcpy((void *)&node->translation_changed, (void *)&node->_oldtranslation, sizeof(struct SFColor));
1447  MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, translation_changed));
1448  }
1449  //save current for use in mouse-up auto-offset
1450  node->_origPoint.c[1] = xxx;
1451  }
1452  else if (ev == ButtonRelease) {
1453  /* set isActive false */
1454  node->isActive = FALSE;
1455  MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, isActive));
1456 
1457  /* autoOffset? */
1458  if (node->autoOffset) {
1459 #ifdef LINESENSOR_FLOAT_OFFSET
1460  node->offset = node->_origPoint.c[1];
1461 #else
1462  node->offset.c[0] = node->translation_changed.c[0];
1463  node->offset.c[1] = node->translation_changed.c[1];
1464  node->offset.c[2] = node->translation_changed.c[2];
1465 #endif
1466  MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, offset));
1467  }
1468  }
1469 
1470 }
1471 
1472 /* void do_PlaneSensor (struct X3D_PlaneSensor *node, int ev, int over) {*/
1473 void do_PlaneSensor ( void *ptr, int ev, int but1, int over) {
1474  struct X3D_PlaneSensor *node;
1475  float mult, nx, ny, trackpoint[3], *posn;
1476  struct SFColor tr;
1477  int tmp, imethod;
1478  ttglobal tg;
1479  UNUSED(over);
1480  node = (struct X3D_PlaneSensor *)ptr;
1481 #ifdef SENSVERBOSE
1482  ConsoleMessage("%lf: TS ",TickTime());
1483  if (ev==ButtonPress) ConsoleMessage("ButtonPress ");
1484  else if (ev==ButtonRelease) ConsoleMessage("ButtonRelease ");
1485  else if (ev==KeyPress) ConsoleMessage("KeyPress ");
1486  else if (ev==KeyRelease) ConsoleMessage("KeyRelease ");
1487  else if (ev==MotionNotify) ConsoleMessage("MotionNotify ");
1488  else ConsoleMessage("ev %d ",ev);
1489 
1490  if (but1) ConsoleMessage("but1 TRUE "); else ConsoleMessage("but1 FALSE ");
1491  if (over) ConsoleMessage("over TRUE "); else ConsoleMessage("over FALSE ");
1492  ConsoleMessage ("\n");
1493 #endif
1494 
1495  /* if not enabled, do nothing */
1496  if (!node) return;
1497 
1498  if (node->__oldEnabled != node->enabled) {
1499  node->__oldEnabled = node->enabled;
1500  MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_PlaneSensor, enabled));
1501  }
1502  if (!node->enabled) return;
1503  tg = gglobal();
1504 
1505  imethod = 1; //0 = old pre-April-2014, 1=April 2014
1506  /* only do something when button pressed */
1507  /* if (!but1) return; */
1508  if (but1){
1509  float v[3], t1[3];
1510  float N[3] = { 0.0f, 0.0f, 1.0f }; //plane normal, in plane-local
1511  float NS[3]; //plane normal, in sensor-local after axisRotation
1512  //bearing (A,B) in sensor-local
1513  // A=posn, B=norm - norm is a point. To get a direction vector v = (B - A)
1514  //ConsoleMessage("hsp = %f %f %f \n", tg->RenderFuncs.hyp_save_posn[0], tg->RenderFuncs.hyp_save_posn[1], tg->RenderFuncs.hyp_save_posn[2]);
1515  vecnormalize3f(v, vecdif3f(t1, tg->RenderFuncs.hyp_save_norm, tg->RenderFuncs.hyp_save_posn));
1516  //rotate plane normal N, in plane-local to plane normal NS in sensor-local using axisRotation
1517  axisangle_rotate3f(NS,N, node->axisRotation.c);
1518  //a plane P dot N = d = const, for any point P on plane. Our plane is in plane-local coords,
1519  // so we could use P={0,0,0} and P dot N = d = 0
1520  posn = tg->RenderFuncs.hyp_save_posn;
1521  if (!line_intersect_planed_3f(posn, v, NS, 0.0f, trackpoint, NULL))
1522  return; //looking at plane edge-on / parallel, no intersection
1523  axisangle_rotate3f(trackpoint, trackpoint, node->axisRotation.c);
1524  }
1525 
1526  if ((ev==ButtonPress) && but1) {
1527  /* record the current position from the saved position */
1528  struct SFColor op;
1529  float *posn;
1530  posn = tg->RenderFuncs.hyp_save_posn;
1531 
1532  veccopy3f(op.c, trackpoint);
1533  if (imethod==1)
1534  memcpy((void *)&node->_origPoint, (void *)&op,sizeof(struct SFColor));
1535  if (imethod==0)
1536  memcpy ((void *) &node->_origPoint,
1537  (void *) posn,sizeof(struct SFColor));
1538 
1539  /* set isActive true */
1540  node->isActive=TRUE;
1541  MARK_EVENT (ptr, offsetof (struct X3D_PlaneSensor, isActive));
1542 
1543  } else if ((ev==MotionNotify) && (node->isActive) && but1) {
1544  /* hyperhit saved in render_hypersensitive phase */
1545  if (imethod==0){
1546  //this is ray intersect plane code, for plane Z=0
1547  mult = (node->_origPoint.c[2] - tg->RenderFuncs.hyp_save_posn[2]) /
1548  (tg->RenderFuncs.hyp_save_norm[2] - tg->RenderFuncs.hyp_save_posn[2]);
1549  nx = tg->RenderFuncs.hyp_save_posn[0] + mult * (tg->RenderFuncs.hyp_save_norm[0] - tg->RenderFuncs.hyp_save_posn[0]);
1550  ny = tg->RenderFuncs.hyp_save_posn[1] + mult * (tg->RenderFuncs.hyp_save_norm[1] - tg->RenderFuncs.hyp_save_posn[1]);
1551  }
1552  if (imethod==1){
1553  nx = trackpoint[0]; ny = trackpoint[1];
1554  }
1555  #ifdef SEVERBOSE
1556  ConsoleMessage ("now, mult %f nx %f ny %f op %f %f %f\n",mult,nx,ny,
1557  node->_origPoint.c[0],node->_origPoint.c[1],
1558  node->_origPoint.c[2]);
1559  #endif
1560 
1561  /* trackpoint changed */
1562  if (imethod == 0){
1563  node->_oldtrackPoint.c[0] = nx;
1564  node->_oldtrackPoint.c[1] = ny;
1565  node->_oldtrackPoint.c[2] = node->_origPoint.c[2];
1566  }
1567  if (imethod == 1){
1568  veccopy3f(node->_oldtrackPoint.c, trackpoint);
1569  }
1570  /*printf(">%f %f %f\n",nx,ny,node->_oldtrackPoint.c[2]); */
1571  if ((APPROX(node->_oldtrackPoint.c[0],node->trackPoint_changed.c[0])!= TRUE) ||
1572  (APPROX(node->_oldtrackPoint.c[1],node->trackPoint_changed.c[1])!= TRUE) ||
1573  (APPROX(node->_oldtrackPoint.c[2],node->trackPoint_changed.c[2])!= TRUE)) {
1574 
1575  memcpy ((void *) &node->trackPoint_changed, (void *) &node->_oldtrackPoint, sizeof(struct SFColor));
1576  MARK_EVENT(ptr, offsetof (struct X3D_PlaneSensor, trackPoint_changed));
1577 
1578  }
1579 
1580  /* clamp translation to max/min position */
1581  tr.c[0] = nx - node->_origPoint.c[0] + node->offset.c[0];
1582  tr.c[1] = ny - node->_origPoint.c[1] + node->offset.c[1];
1583  tr.c[2] = node->offset.c[2];
1584 
1585  for (tmp=0; tmp<2; tmp++) {
1586  if (node->maxPosition.c[tmp] >= node->minPosition.c[tmp]) {
1587  if (tr.c[tmp] < node->minPosition.c[tmp]) {
1588  tr.c[tmp] = node->minPosition.c[tmp];
1589  } else if (tr.c[tmp] > node->maxPosition.c[tmp]) {
1590  tr.c[tmp] = node->maxPosition.c[tmp];
1591  }
1592  }
1593  }
1594 
1595  node->_oldtranslation.c[0] = tr.c[0];
1596  node->_oldtranslation.c[1] = tr.c[1];
1597  node->_oldtranslation.c[2] = tr.c[2];
1598 
1599  if ((APPROX(node->_oldtranslation.c[0],node->translation_changed.c[0])!= TRUE) ||
1600  (APPROX(node->_oldtranslation.c[1],node->translation_changed.c[1])!= TRUE) ||
1601  (APPROX(node->_oldtranslation.c[2],node->translation_changed.c[2])!= TRUE)) {
1602 
1603  memcpy ((void *) &node->translation_changed, (void *) &node->_oldtranslation, sizeof(struct SFColor));
1604  MARK_EVENT(ptr, offsetof (struct X3D_PlaneSensor, translation_changed));
1605  }
1606 
1607  } else if (ev==ButtonRelease) {
1608  /* set isActive false */
1609  node->isActive=FALSE;
1610  MARK_EVENT (ptr, offsetof (struct X3D_PlaneSensor, isActive));
1611 
1612  /* autoOffset? */
1613  if (node->autoOffset) {
1614  node->offset.c[0] = node->translation_changed.c[0];
1615  node->offset.c[1] = node->translation_changed.c[1];
1616  node->offset.c[2] = node->translation_changed.c[2];
1617 
1618  MARK_EVENT (ptr, offsetof (struct X3D_PlaneSensor, offset));
1619  }
1620  }
1621 
1622 }
1623 
1624 
1625 /* void do_Anchor (struct X3D_Anchor *node, int ev, int over) {*/
1626 void do_Anchor ( void *ptr, int ev, int but1, int over) {
1627  struct X3D_Anchor *node = (struct X3D_Anchor *)ptr;
1628  UNUSED(over);
1629  UNUSED(but1);
1630 
1631  if (!node) return;
1632  /* try button release, so that we dont get worlds flashing past if
1633  the user keeps the finger down. :-) if (ev==ButtonPress) { */
1634  if (ev==ButtonRelease) {
1635  ttglobal tg = gglobal();
1636  /* no parameters in url field? */
1637  if (node->url.n < 1) return;
1638  setAnchorsAnchor( node );
1639  #ifdef OLDCODE
1640  OLDCODE FREE_IF_NZ(tg->RenderFuncs.OSX_replace_world_from_console);
1641  #endif // OLDCODE
1642 
1643  tg->RenderFuncs.BrowserAction = TRUE;
1644  }
1645 }
1646 
1647 
1648 void do_CylinderSensor ( void *ptr, int ev, int but1, int over) {
1649  struct X3D_CylinderSensor *node = (struct X3D_CylinderSensor *)ptr;
1650  double rot, radius, ang, length;
1651  double det, pos, neg, temp;
1652  double acute_angle, disk_angle, height;
1653  float Y[3] = { 0.0f, 1.0f, 0.0f }, ZERO[3] = { 0.0f, 0.0f, 0.0f };
1654  float as[3], bs[3], v[3], rps[3];
1655 
1656  int imethod;
1657  Quaternion bv, dir1, dir2, tempV;
1658  GLDOUBLE modelMatrix[16];
1659  ttglobal tg;
1660 
1661  UNUSED(over);
1662 
1663  /* if not enabled, do nothing */
1664  if (!node) return;
1665  if (node->__oldEnabled != node->enabled) {
1666  node->__oldEnabled = node->enabled;
1667  MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_CylinderSensor, enabled));
1668  }
1669  if (!node->enabled) return;
1670 
1671  /* only do something if the button is pressed */
1672  if (!but1) return;
1673  tg = gglobal();
1674  imethod = 1;
1675  if (imethod == 1){
1676  /*precompute some values for mouse-down, mouse-move*/
1677  //convert all almost-sensor-local points into sensor-local
1678  //(the axisRotation never gets applied in the modelview transform stack - if that changes in the future, then don't need these)
1679  axisangle_rotate3f(as, tg->RenderFuncs.hyp_save_posn, node->axisRotation.c);
1680  axisangle_rotate3f(bs, tg->RenderFuncs.hyp_save_norm, node->axisRotation.c);
1681  vecnormalize3f(v, vecdif3f(v, bs, as));
1682  axisangle_rotate3f(rps,tg->RenderFuncs.ray_save_posn, node->axisRotation.c);
1683 
1684  }
1685  if (ev==ButtonPress) {
1686  /* record the current position from the saved position */
1687  if (imethod == 0){
1688  memcpy((void *)&node->_origPoint,
1689  (void *)&tg->RenderFuncs.ray_save_posn, sizeof(struct SFColor));
1690  }else{
1691  /* on mouse-down we have to decide which sensor geometry to use: disk or cylinder, as per specs
1692  http://www.web3d.org/files/specifications/19775-1/V3.3/Part01/components/pointingsensor.html#CylinderSensor
1693  and that's determined by the angle between the bearing and the sensor Y axis, in sensor-local coords
1694  The bearing (A,B) where A=hyp_posn, B=hyp_norm and both are points in sensor-local coordinates
1695  To get a direction vector v = B - A
1696  */
1697  struct SFColor origPoint;
1698  /*ray_save_posn is the intersection with scene geometry, in sensor-local coordinates, for cylinder*/
1699  float dot, rs[3];
1700  dot = vecdot3f(v, Y);
1701  acute_angle = acos(dot);
1702  ang = min(acute_angle,PI - acute_angle);
1703  veccopy3f(rs, rps); //rps: ray_posn (intersection with scene geometry) in sensor-local
1704  height = rs[1];
1705  rs[1] = 0.0f;
1706  radius = veclength3f(rs); //radius of ray_posn from cylinder axis, for scaling the 'feel' of the rotations to what the user clicked
1707  vecnormalize3f(rs, rs);
1708  if (ang < node->diskAngle){
1709  //use end cap disks
1710  disk_angle = -atan2(rs[2], rs[0]);
1711  }else{
1712  //use cylinder wall
1713  float travelled, cylpoint[3], axispoint[3], dif[3];
1714  line_intersect_line_3f(as, v, ZERO, Y, NULL, NULL, cylpoint, axispoint);
1715  travelled = veclength3f(vecdif3f(dif, cylpoint, axispoint)); //travelled: closest distance of our bearing from cylinder axis
1716  if (det3f(v, dif, Y) > 0.0f) travelled = -travelled; //which side of cylinder axis is our bearing on? v x dif will point a different direction (up or down) depending on which side, so dot with Y to get a sign
1717  disk_angle = travelled / (2.0f * PI * radius) * (2.0f * PI); //don't need the 2PI except to show how we converted to radians: travelled is a fraction of circumference, and circumference is 2PI
1718  }
1719  node->_radius = (float)radius; //store for later use on mouse-moves
1720  //origPoint - we get to store whatever we need later mouse-moves.
1721  origPoint.c[0] = (float)disk_angle;
1722  origPoint.c[1] = (float)-height; //Q. why -height? don't know but it works
1723  memcpy((void *)&node->_origPoint,(void *)&origPoint, sizeof(struct SFColor));
1724  }
1725  /* set isActive true */
1726  node->isActive=TRUE;
1727  MARK_EVENT (ptr, offsetof (struct X3D_CylinderSensor, isActive));
1728 
1729  /* record the current Radius */
1730  if (imethod == 0)
1731  {
1732  node->_radius = tg->RenderFuncs.ray_save_posn[0] * tg->RenderFuncs.ray_save_posn[0] +
1733  tg->RenderFuncs.ray_save_posn[1] * tg->RenderFuncs.ray_save_posn[1] +
1734  tg->RenderFuncs.ray_save_posn[2] * tg->RenderFuncs.ray_save_posn[2];
1735 
1736  FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
1737  /*
1738  printf ("Cur Matrix: \n\t%f %f %f %f\n\t%f %f %f %f\n\t%f %f %f %f\n\t%f %f %f %f\n",
1739  modelMatrix[0], modelMatrix[4], modelMatrix[ 8], modelMatrix[12],
1740  modelMatrix[1], modelMatrix[5], modelMatrix[ 9], modelMatrix[13],
1741  modelMatrix[2], modelMatrix[6], modelMatrix[10], modelMatrix[14],
1742  modelMatrix[3], modelMatrix[7], modelMatrix[11], modelMatrix[15]);
1743  */
1744 
1745  /* find the bearing vector in the local coordinate system */
1746  pos = neg = 0.0;
1747  temp = modelMatrix[1] * modelMatrix[6] * modelMatrix[8];
1748  if (temp >= 0.0) pos += temp; else neg += temp;
1749  temp = -modelMatrix[2] * modelMatrix[5] * modelMatrix[8];
1750  if (temp >= 0.0) pos += temp; else neg += temp;
1751  temp = -modelMatrix[0] * modelMatrix[6] * modelMatrix[9];
1752  if (temp >= 0.0) pos += temp; else neg += temp;
1753  temp = modelMatrix[2] * modelMatrix[4] * modelMatrix[9];
1754  if (temp >= 0.0) pos += temp; else neg += temp;
1755  temp = modelMatrix[0] * modelMatrix[5] * modelMatrix[10];
1756  if (temp >= 0.0) pos += temp; else neg += temp;
1757  temp = -modelMatrix[1] * modelMatrix[4] * modelMatrix[10];
1758  if (temp >= 0.0) pos += temp; else neg += temp;
1759  det = pos + neg;
1760  det = 1.0 / det;
1761 
1762  bv.w = 0;/* set to 0 to ensure vector is normalised correctly */
1763  bv.x = (modelMatrix[4] * modelMatrix[9] - modelMatrix[5] * modelMatrix[8]) * det;
1764  bv.y = -(modelMatrix[0] * modelMatrix[9] - modelMatrix[1] * modelMatrix[8]) * det;
1765  bv.z = (modelMatrix[0] * modelMatrix[5] - modelMatrix[1] * modelMatrix[4]) * det;
1766 
1767  quaternion_normalize(&bv);
1768  ang = acos(bv.y);
1769  if (ang > (M_PI / 2)) { ang = M_PI - ang; }
1770  }
1771  if (ang < node->diskAngle) {
1772  node->_dlchange=TRUE; //use disk sensor geometry
1773  } else {
1774  node->_dlchange=FALSE; //use cylinder sensor geometry
1775  }
1776 
1777 
1778  }else
1779  if ((ev == MotionNotify) && (node->isActive)) {
1780 
1781  if (imethod==0)
1782  memcpy((void *)&node->_oldtrackPoint, (void *)&tg->RenderFuncs.ray_save_posn, sizeof(struct SFColor));
1783  if (imethod == 1)
1784  veccopy3f(node->_oldtrackPoint.c, rps); //I'm using ray_posn, which is intersection with sensitized scene geometry. Should I be using the bearing intersect sensor_geometry?
1785  if ((APPROX(node->_oldtrackPoint.c[0], node->trackPoint_changed.c[0]) != TRUE) ||
1786  (APPROX(node->_oldtrackPoint.c[1], node->trackPoint_changed.c[1]) != TRUE) ||
1787  (APPROX(node->_oldtrackPoint.c[2], node->trackPoint_changed.c[2]) != TRUE)) {
1788 
1789  memcpy((void *)&node->trackPoint_changed, (void *)&node->_oldtrackPoint, sizeof(struct SFColor));
1790  MARK_EVENT(ptr, offsetof(struct X3D_CylinderSensor, trackPoint_changed));
1791  }
1792 
1793  if (imethod==0)
1794  {
1795  dir1.w = 0;
1796  dir1.x = tg->RenderFuncs.ray_save_posn[0];
1797  dir1.y = 0;
1798  dir1.z = tg->RenderFuncs.ray_save_posn[2];
1799 
1800  if (node->_dlchange) {
1801  radius = 1.0; //disk
1802  }
1803  else {
1804  /* get the radius */
1805  radius = (dir1.x * dir1.x + dir1.y * dir1.y + dir1.z * dir1.z); //2D cylinder radius**2
1806  }
1807 
1808  quaternion_normalize(&dir1);
1809  dir2.w = 0;
1810  dir2.x = node->_origPoint.c[0];
1811  dir2.y = 0;
1812  dir2.z = node->_origPoint.c[2];
1813 
1814  quaternion_normalize(&dir2);
1815 
1816  tempV.w = 0;
1817  tempV.x = dir2.y * dir1.z - dir2.z * dir1.y;
1818  tempV.y = dir2.z * dir1.x - dir2.x * dir1.z;
1819  tempV.z = dir2.x * dir1.y - dir2.y * dir1.x;
1820  quaternion_normalize(&tempV);
1821 
1822  length = tempV.x * tempV.x + tempV.y * tempV.y + tempV.z * tempV.z;
1823  if (APPROX(length, 0.0)) { return; }
1824 
1825  /* Find the angle of the dot product */
1826  rot = radius * acos((dir1.x*dir2.x + dir1.y*dir2.y + dir1.z*dir2.z));
1827 
1828  if (APPROX(tempV.y, -1.0)) rot = -rot;
1829  }
1830  if (imethod == 1)
1831  {
1832  //compute delta rotation from drag
1833  //a plane P dot N = d = const, for any point P on plane. Our plane is in plane-local coords,
1834  // so we could use P={0,0,0} and P dot N = d = 0
1835  float diskpoint[3], orig_diskangle, height;
1836  height = node->_origPoint.c[1];
1837  radius = node->_radius;
1838  orig_diskangle = node->_origPoint.c[0];
1839  if (node->_dlchange == TRUE) {
1840  //disk
1841  line_intersect_planed_3f(as, v, Y, height, diskpoint, NULL);
1842  vecnormalize3f(diskpoint, diskpoint);
1843  //for cylinder compute angle from intersection on cylinder of radius
1844  disk_angle = -atan2(diskpoint[2], diskpoint[0]);
1845  //printf("D");
1846  }else {
1847  float cylpoint[3]; //pi1[3],
1848  //cylinder wall
1849  //ray-intersect-cylinder is too hard for us, a quadratic (but is done in rendray_Cylinder)
1850  //if (line_intersect_cylinder_3f(as, v, radius, cylpoint)){ //didn't work - wrong sol1,sol2 or ???
1851  // //on the cylinder
1852  // disk_angle = -atan2(cylpoint[2], cylpoint[0]);
1853  // printf("C");
1854  //
1855  //off the cylinder (and well this works as good as the line_interesect_cylinder
1856  //we want a drag off the cylinder to keep working even when mouse isn't over cylinder
1857  //on the cylinder
1858  //basically we try and do a linear drag perpendicular to both our bearing and the cylinder
1859  //axis, and convert that linear distance from cylinder axis from distance into rotations
1860  float travelled, axispoint[3], dif[3];
1861  radius = 1.0f;
1862  line_intersect_line_3f(as, v, ZERO, Y, NULL, NULL, cylpoint, axispoint);
1863  //cylpoint - closest point of approach of our bearing, on the bearing
1864  //axispoint - ditto, on the cyl axis
1865  //dif = cylpoint - axispoint //vector perpendicular to axis - our 'travel' from the axis
1866  travelled = veclength3f(vecdif3f(dif, cylpoint, axispoint));
1867  if (det3f(v, dif, Y) > 0.0f) travelled = -travelled; // v x dif will be up or down the cyl axis, depending on which side of the axis we are on
1868  disk_angle = travelled / (2.0f * PI * radius) * (2.0f * PI); //convert from distance to radians using ratio of circumference
1869  //printf("V");
1870  }
1871  rot = disk_angle - orig_diskangle;
1872  }
1873 
1874  if (node->autoOffset) {
1875  rot = node->offset + rot;
1876  }
1877  if (node->minAngle < node->maxAngle) {
1878  if (rot < node->minAngle) {
1879  rot = node->minAngle;
1880  } else if (rot > node->maxAngle) {
1881  rot = node->maxAngle;
1882  }
1883  }
1884 
1885  node->_oldrotation.c[0] = (float) 0;
1886  node->_oldrotation.c[1] = (float) 1;
1887  node->_oldrotation.c[2] = (float) 0;
1888  node->_oldrotation.c[3] = (float) rot;
1889 
1890  if ((APPROX(node->_oldrotation.c[0],node->rotation_changed.c[0])!= TRUE) ||
1891  (APPROX(node->_oldrotation.c[1],node->rotation_changed.c[1])!= TRUE) ||
1892  (APPROX(node->_oldrotation.c[2],node->rotation_changed.c[2])!= TRUE) ||
1893  (APPROX(node->_oldrotation.c[3],node->rotation_changed.c[3])!= TRUE)) {
1894 
1895  memcpy ((void *) &node->rotation_changed, (void *) &node->_oldrotation, sizeof(struct SFRotation));
1896  MARK_EVENT(ptr, offsetof (struct X3D_CylinderSensor, rotation_changed));
1897  }
1898 
1899 
1900  } else if (ev==ButtonRelease) {
1901  /* set isActive false */
1902  node->isActive=FALSE;
1903  MARK_EVENT (ptr, offsetof (struct X3D_CylinderSensor, isActive));
1904  /* save auto offset of rotation */
1905  if (node->autoOffset) {
1906  memcpy ((void *) &node->offset,
1907  (void *) &node->rotation_changed.c[3],
1908  sizeof (float));
1909 
1910  MARK_EVENT (ptr, offsetof (struct X3D_CylinderSensor, rotation_changed));
1911  }
1912  }
1913 }
1914 
1915 
1916 
1917 #define ORIG_X node->_origPoint.c[0]
1918 #define ORIG_Y node->_origPoint.c[1]
1919 #define ORIG_Z node->_origPoint.c[2]
1920 #define NORM_ORIG_X node->_origNormalizedPoint.c[0]
1921 #define NORM_ORIG_Y node->_origNormalizedPoint.c[1]
1922 #define NORM_ORIG_Z node->_origNormalizedPoint.c[2]
1923 #define CUR_X tg->RenderFuncs.ray_save_posn[0]
1924 #define CUR_Y tg->RenderFuncs.ray_save_posn[1]
1925 #define CUR_Z tg->RenderFuncs.ray_save_posn[2]
1926 #define NORM_CUR_X normalizedCurrentPoint.c[0]
1927 #define NORM_CUR_Y normalizedCurrentPoint.c[1]
1928 #define NORM_CUR_Z normalizedCurrentPoint.c[2]
1929 #define RADIUS node->_radius
1930 
1931 /********************************************************************************/
1932 /* */
1933 /* do the guts of a SphereSensor.... this has been changed considerably in Apr */
1934 /* 2009 because the original, fast methods created by Tuomas Lukka failed in */
1935 /* a boundary area (HUD, small transform scale, close to viewer) and I could */
1936 /* not understand what *exactly* Tuomas' code did - I guess I don't have a */
1937 /* doctorate in math like he does! I went to the old linear algebra text and */
1938 /* created a simple but inelegant solution from that. J.A. Stewart. */
1939 /* */
1940 /********************************************************************************/
1941 void do_SphereSensor ( void *ptr, int ev, int but1, int over) {
1942  struct X3D_SphereSensor *node = (struct X3D_SphereSensor *)ptr;
1943 /*
1944  int tmp;
1945  float tr1sq, tr2sq, tr1tr2;
1946  struct SFColor dee, arr, cp, dot;
1947  float deelen, aay, bee, cee, und, sol, cl, an;
1948  Quaternion q, q2, q_r;
1949  double s1,s2,s3,s4;
1950 */
1951  ttglobal tg;
1952  UNUSED(over);
1953 
1954  /* if not enabled, do nothing */
1955  if (!node)
1956  return;
1957  if (node->__oldEnabled != node->enabled) {
1958  node->__oldEnabled = node->enabled;
1959  MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_SphereSensor, enabled));
1960  }
1961  if (!node->enabled)
1962  return;
1963 
1964  /* only do something if button1 is pressed */
1965  if (!but1) return;
1966  tg = gglobal();
1967  if (ev==ButtonPress) {
1968  /* record the current position from the saved position */
1969  ORIG_X = CUR_X;
1970  ORIG_Y = CUR_Y;
1971  ORIG_Z = CUR_Z;
1972 
1973  /* record the current Radius */
1974  RADIUS = (float) sqrt(CUR_X * CUR_X + CUR_Y * CUR_Y + CUR_Z * CUR_Z);
1975 
1976  if (APPROX(RADIUS,0.0)) {
1977  printf ("warning, RADIUS %lf == 0, can not compute\n",RADIUS);
1978  return;
1979  }
1980 
1981  /* save the initial norm here */
1982  NORM_ORIG_X = CUR_X / RADIUS;
1983  NORM_ORIG_Y = CUR_Y / RADIUS;
1984  NORM_ORIG_Z = CUR_Z / RADIUS;
1985 
1986  /* norm(offset) ideally this would be done once during parsing
1987  of crazy SFRotation ie '1 1 -5 .6' in 10.wrl/10.x3d
1988  I might be getting rounding errors from repeated normalization */
1989  vrmlrot_normalize(node->offset.c);
1990 
1991  /* set isActive true */
1992  node->isActive=TRUE;
1993  MARK_EVENT (ptr, offsetof (struct X3D_SphereSensor, isActive));
1994 
1995  } else if (ev==ButtonRelease) {
1996  /* set isActive false */
1997  node->isActive=FALSE;
1998  MARK_EVENT (ptr, offsetof (struct X3D_SphereSensor, isActive));
1999 
2000  if (node->autoOffset) {
2001  memcpy ((void *) &node->offset,
2002  (void *) &node->rotation_changed,
2003  sizeof (struct SFRotation));
2004  }
2005  } else if ((ev==MotionNotify) && (node->isActive)) {
2006 
2007  double dotProd;
2008  double newRad;
2009  struct SFColor normalizedCurrentPoint;
2010  struct point_XYZ newA;
2011 
2012  /* record the current Radius */
2013  newRad = sqrt(CUR_X * CUR_X + CUR_Y * CUR_Y + CUR_Z * CUR_Z);
2014 
2015  /* bounds check... */
2016  if (APPROX(newRad,0.0)) {
2017  printf ("warning, newRad %lf == 0, can not compute\n",newRad);
2018  return;
2019  }
2020  RADIUS = (float) newRad;
2021 
2022  /* save the current norm here */
2023  NORM_CUR_X = CUR_X / RADIUS;
2024  NORM_CUR_Y = CUR_Y / RADIUS;
2025  NORM_CUR_Z = CUR_Z / RADIUS;
2026 
2027  /* find the cross-product between the initial and current points */
2028  newA.x = ORIG_Y * CUR_Z - ORIG_Z * CUR_Y;
2029  newA.y = ORIG_Z * CUR_X - ORIG_X * CUR_Z;
2030  newA.z = ORIG_X * CUR_Y - ORIG_Y * CUR_X;
2031  normalize_vector(&newA);
2032 
2033  /* clamp the angle to |a| < 1.0 */
2034  /* remember A dot B = |A|*|B|*cos(theta_between) or theta_between = acos(A dot B/|A|*|B| ) */
2035  dotProd = NORM_ORIG_X * NORM_CUR_X + NORM_ORIG_Y * NORM_CUR_Y + NORM_ORIG_Z * NORM_CUR_Z;
2036  if (dotProd > 1.0)
2037  dotProd = 1.0;
2038  if (dotProd < -1.0)
2039  dotProd = -1.0;
2040  dotProd = acos(dotProd);
2041 
2042  /* have axis-angle now */
2043  /*
2044  printf ("newRotation a %lf - rot -- %lf %lf %lf %lf\n",
2045  dotProd, newA.x,newA.y,newA.z,dotProd);
2046  */
2047  if(node->autoOffset)
2048  {
2049 /*
2050  if(0)
2051  {
2052  //Aug 1, 2010 experimental code - stale date: Sept 1
2053  struct SFRotation temp, temp2;
2054  temp.c[0] = newA.x;
2055  temp.c[1] = newA.y;
2056  temp.c[2] = newA.z;
2057  temp.c[3] = dotProd;
2058  vrmlrot_multiply(temp2.c, node->offset.c, temp.c);
2059  newA.x = temp2.c[0];
2060  newA.y = temp2.c[1];
2061  newA.z = temp2.c[2];
2062  dotProd = temp2.c[3];
2063  }
2064  if(1)
2065  {
2066 */
2067  /* copied from the javascript SFRotationMultiply */
2068  Quaternion q1, q2, qret;
2069  /* convert both rotations into quaternions */
2070  vrmlrot_to_quaternion(&q1, (double) newA.x,
2071  (double) newA.y, (double) newA.z, (double) dotProd);
2072  vrmlrot_to_quaternion(&q2, (double) node->offset.c[0],
2073  (double) node->offset.c[1], (double) node->offset.c[2], (double) node->offset.c[3]);
2074  /* multiply them */
2075  quaternion_multiply(&qret,&q1,&q2);
2076  /* and return the resultant, as a vrml rotation */
2077  quaternion_to_vrmlrot(&qret, &newA.x, &newA.y, &newA.z, &dotProd);
2078  /*}*/
2079  }
2080 
2081 
2082  node->rotation_changed.c[0] = (float) newA.x;
2083  node->rotation_changed.c[1] = (float) newA.y;
2084  node->rotation_changed.c[2] = (float) newA.z;
2085  node->rotation_changed.c[3] = (float) dotProd; //acos(dotProd); done above
2086  MARK_EVENT (ptr, offsetof (struct X3D_SphereSensor, rotation_changed));
2087 
2088  node->trackPoint_changed.c[0] = NORM_CUR_X;
2089  node->trackPoint_changed.c[1] = NORM_CUR_Y;
2090  node->trackPoint_changed.c[2] = NORM_CUR_Z;
2091  MARK_EVENT (ptr, offsetof (struct X3D_SphereSensor, trackPoint_changed));
2092  }
2093 }