FreeWRL / FreeX3D 4.3.0
SensInterps.c
1/*
2
3
4Do Sensors and Interpolators in C, not in perl.
5
6Interps 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;
64typedef struct pSensInterps{
65 int stub;
67void *SensInterps_constructor(){
68 void *v = MALLOCV(sizeof(struct pSensInterps));
69 memset(v,0,sizeof(struct pSensInterps));
70 return v;
71}
72void 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 */
88void 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 */
200int 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 */
213void 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
256void 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
411void do_OintCoord(void *node) {
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
585void do_OintCoord2D(void *node) {
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
726void 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
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 */
792void 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
843void 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
898void do_Oint4 (void *node) {
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) {*/
984void 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) {*/
996void 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
1071unsigned char *movietexture_get_frame_by_fraction(struct X3D_Node* node, float fraction, int *width, int *height, int *nchan);
1072void 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*****************************************************************************/
1214
1215float fclamp(float fval, float fstart, float fend) {
1216 float fret = fval;
1217 fret = fval > fend? fend : fval; //min(fval,fend)
1218 fret = fret < fstart ? fstart : fret; //max(fval,fstart)
1219 return fret;
1220}
1221float *vecclamp2f(float *fval, float *fstart, float *fend){
1222 int i;
1223 for(i=0;i<2;i++){
1224 if(fstart[i] <= fend[i])
1225 fval[i] = fclamp(fval[i],fstart[i],fend[i]);
1226 }
1227 return fval; //so you can chain
1228}
1229float *vecclamp3f(float *fval, float *fstart, float *fend){
1230 int i;
1231 for(i=0;i<3;i++){
1232 if(fstart[i] <= fend[i])
1233 fval[i] = fclamp(fval[i],fstart[i],fend[i]);
1234 }
1235 return fval; //so you can chain
1236}
1237// #define APPROX(a,b) (fabs((a)-(b))<0.00000001)
1238int approx3f(float *a, float *b){
1239 float tol = 0.00000001;
1240 int i, iret = TRUE;
1241 for(i=0;i<3;i++){
1242 iret = iret && (fabs(a[i] - b[i]) < tol) ? iret : FALSE;
1243 }
1244 return iret;
1245}
1246int approx4f(float *a, float *b){
1247 float tol = 0.00000001;
1248 int i, iret = TRUE;
1249 for(i=0;i<4;i++){
1250 iret = iret && (fabs(a[i] - b[i]) < tol) ? iret : FALSE;
1251 }
1252 return iret;
1253}
1254void do_TouchSensor ( void *ptr, int ev, int but1, int over) {
1255
1256 struct X3D_TouchSensor *node = (struct X3D_TouchSensor *)ptr;
1257 float normalval[3];
1258 ttglobal tg;
1259 #ifdef SENSVERBOSE
1260 printf ("%lf: TS ",TickTime());
1261 if (ev==ButtonPress) printf ("ButtonPress ");
1262 else if (ev==ButtonRelease) printf ("ButtonRelease ");
1263 else if (ev==KeyPress) printf ("KeyPress ");
1264 else if (ev==KeyRelease) printf ("KeyRelease ");
1265 else if (ev==MotionNotify) printf ("%lf MotionNotify ");
1266 else printf ("ev %d ",ev);
1267
1268 if (but1) printf ("but1 TRUE "); else printf ("but1 FALSE ");
1269 if (over) printf ("over TRUE "); else printf ("over FALSE ");
1270 printf ("\n");
1271 #endif
1272
1273
1274 /* if not enabled, do nothing */
1275 if (!node) return;
1276 if (node->__oldEnabled != node->enabled) {
1277 node->__oldEnabled = node->enabled;
1278 MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_TouchSensor, enabled));
1279 }
1280 if (!node->enabled) return;
1281 tg = gglobal();
1282 /* isOver state */
1283 if ((ev == overMark) && (over != node->isOver)) {
1284 #ifdef SENSVERBOSE
1285 printf ("TS %u, isOver changed %d\n",node, over);
1286 #endif
1287 node->isOver = over;
1288 MARK_EVENT (ptr, offsetof (struct X3D_TouchSensor, isOver));
1289 }
1290
1291 /* active */
1292 /* button presses */
1293 if (ev == ButtonPress) {
1294 node->isActive=TRUE;
1295 MARK_EVENT (ptr, offsetof (struct X3D_TouchSensor, isActive));
1296 #ifdef SENSVERBOSE
1297 printf ("touchSens %u, butPress\n",node);
1298 #endif
1299
1300 node->touchTime = TickTime();
1301 MARK_EVENT(ptr, offsetof (struct X3D_TouchSensor, touchTime));
1302
1303 } else if (ev == ButtonRelease) {
1304 #ifdef SENSVERBOSE
1305 printf ("touchSens %u, butRelease\n",node);
1306 #endif
1307 node->isActive=FALSE;
1308 MARK_EVENT (ptr, offsetof (struct X3D_TouchSensor, isActive));
1309 }
1310
1311 /* hitPoint and hitNormal */
1312 /* save the current hitPoint for determining if this changes between runs */
1313 veccopy3f(node->_oldhitPoint.c,tg->RenderFuncs.ray_save_posn);
1314
1315 /* did the hitPoint change between runs? */
1316 if(!approx3f(node->_oldhitPoint.c,node->hitPoint_changed.c)){
1317 veccopy3f(node->hitPoint_changed.c,node->_oldhitPoint.c);
1318 MARK_EVENT(ptr, offsetof (struct X3D_TouchSensor, hitPoint_changed));
1319 }
1320
1321 /* have to normalize normal; change it from SFColor to struct point_XYZ. */
1322 veccopy3f(normalval,tg->RenderFuncs.hyp_save_norm);
1323 vecnormalize3f(normalval,normalval);
1324 veccopy3f(node->_oldhitNormal.c,normalval);
1325
1326 /* did the hitNormal change between runs? */
1327 if(!approx3f(node->_oldhitNormal.c,node->hitNormal_changed.c)) {
1328 //memcpy ((void *) &node->hitNormal_changed, (void *) &node->_oldhitNormal, sizeof(struct SFColor));
1329 veccopy3f(node->hitNormal_changed.c,node->_oldhitNormal.c);
1330 MARK_EVENT(ptr, offsetof (struct X3D_TouchSensor, hitNormal_changed));
1331 }
1332}
1333// see Mainloop.c get_hyperhit() for more explanation:
1334// in sensor-node-local coordinates (not quite sensor-local if sensor node has axisRotation):
1335// ray_save_posn - intersection point of pickray/bearing with sensitized geometry
1336// hyp_save_posn - point on camera/viewpoint nearplane on pickray/bearing, transformed to sensor-node-local
1337// hyp_save_norm - point on carmera/viewpoint farplane on pickray/bearing, transformed to sensor-node-local
1338
1339void do_LineSensor(void *ptr, int ev, int but1, int over) {
1340 /* There is no LineSensor node in the specs in April 2014. X3Dom guru Max Limper complained
1341 on X3DPublic about how PlaneSensor fails as an axis mover in the degenerate case of
1342 looking edge-on at the planeSensor. The solution we (dug9) came up with was LineSensor,
1343 which also has a degenerate case (when looking end-on at the Line), but that degerate
1344 case is more normal for users - more intuitive.
1345 LineSensor is the same as PlaneSensor, except minPosition and maxPosition are floats,
1346 and LineSensor uses a SFVec3f .direction field to say which way the Line is oriented
1347 in local-sensor coordinates. In April 2014, Paulo added LineSensor to the perl generator,
1348 and dug9 implemented it here.
1349 */
1350 struct X3D_LineSensor *node;
1351 float trackpoint[3], translation[3], xxx;
1352 //struct SFColor tr;
1353 //int tmp;
1354 ttglobal tg;
1355 UNUSED(over);
1356 node = (struct X3D_LineSensor *)ptr;
1357#ifdef SENSVERBOSE
1358 printf("%lf: TS ", TickTime());
1359 if (ev == ButtonPress) printf("ButtonPress ");
1360 else if (ev == ButtonRelease) printf("ButtonRelease ");
1361 else if (ev == KeyPress) printf("KeyPress ");
1362 else if (ev == KeyRelease) printf("KeyRelease ");
1363 else if (ev == MotionNotify) printf("%lf MotionNotify ");
1364 else printf("ev %d ", ev);
1365
1366 if (but1) printf("but1 TRUE "); else printf("but1 FALSE ");
1367 if (over) printf("over TRUE "); else printf("over FALSE ");
1368 printf("\n");
1369#endif
1370
1371 /* if not enabled, do nothing */
1372 if (!node) return;
1373
1374 if (node->__oldEnabled != node->enabled) {
1375 node->__oldEnabled = node->enabled;
1376 MARK_EVENT(X3D_NODE(node), offsetof(struct X3D_LineSensor, enabled));
1377 }
1378 if (!node->enabled) return;
1379 tg = gglobal();
1380
1381 /* only do something when button pressed */
1382 /* if (!but1) return; */
1383 if (but1){
1384 //pre-calculate for Press and Move
1385 /* hyperhit saved in render_hypersensitive phase */
1386 // bearing in sensor-local coordinates: (A=posn,B=norm)
1387 // B/norm is a point, so to get a direction vector: v = B - A
1388 float tt;
1389 float origin [] = { 0.0f, 0.0f, 0.0f };
1390 float footpoint2[3], footpoint1[3], v1[3]; //, temp[3], temp2[3];
1391 vecdif3f(v1, tg->RenderFuncs.hyp_save_norm, tg->RenderFuncs.hyp_save_posn);
1392 vecnormalize3f(v1, v1);
1393 if (!line_intersect_line_3f(tg->RenderFuncs.hyp_save_posn, v1,
1394 origin, node->direction.c, NULL, &tt, footpoint1, footpoint2))
1395 return; //no intersection, lines are parallel
1396 //footpoint1 - closest point of intersection on the A'B' bearing
1397 //footpoint2 - closest point of intersection on the Line (0,0,0)(LineSensor.direction)
1398 //tt is scale of unit vector from origin to footpoint2
1399 xxx = tt;
1400 veccopy3f(trackpoint,footpoint2); //unclamped intersection with Sensor geometry, for trackpoint
1401 }
1402 if ((ev == ButtonPress) && but1) {
1403 /* record the current position from the saved position */
1404#define LINESENSOR_FLOAT_OFFSET 1
1405#ifndef LINESENSOR_FLOAT_OFFSET
1406 struct SFColor op;
1407 veccopy3f(op.c, trackpoint);
1408 memcpy((void *)&node->_origPoint, (void *)&op,sizeof(struct SFColor));
1409 // (void *)&tg->RenderFuncs.ray_save_posn, sizeof(struct SFColor));
1410#else
1411 node->_origPoint.c[0] = xxx;
1412 //in case we go from mousedown to mouseup without mousemove:
1413 if (node->autoOffset)
1414 node->_origPoint.c[1] = node->offset;
1415 else
1416 node->_origPoint.c[1] = 0.0f;
1417#endif
1418 /* set isActive true */
1419 node->isActive = TRUE;
1420 MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, isActive));
1421
1422 }
1423 else if ((ev == MotionNotify) && (node->isActive) && but1) {
1424 float xxxoffset, xxxorigin;
1425 //float diroffset[3], nondiroffset[3];
1426 /* trackpoint changed */
1427 veccopy3f(node->_oldtrackPoint.c,trackpoint);
1428
1429 if(!approx3f(node->_oldtrackPoint.c, node->trackPoint_changed.c)) {
1430 veccopy3f(node->trackPoint_changed.c, node->_oldtrackPoint.c);
1431 MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, trackPoint_changed));
1432
1433 }
1434
1435 //clamp to min,max
1436#ifdef LINESENSOR_FLOAT_OFFSET
1437 xxxoffset = node->offset;
1438 xxxorigin = node->_origPoint.c[0];
1439#else
1440 //in theory the user can set a non-autoOffset sfvec3f offset that's not along .direction
1441 //- we accomodate that below^, so here we just use the part going along .direction
1442 xxxoffset = vecdot3f(node->direction.c,node->offset.c); //xxxoffset - like web3d specs offset, except just along direction vector
1443 xxxorigin = vecdot3f(node->direction.c,node->_origPoint.c); //mouse-down origin
1444#endif
1445 //xxx before: unclamped position from line origin
1446 xxx -= xxxorigin; //xxx after: net drag/delta along line since mouse-down
1447 xxx += xxxoffset; //xxx after: cumulative position along line (from line 0) after any/all mousedown/drag sequences
1448 if (node->maxPosition >= node->minPosition) {
1449 if (xxx < node->minPosition) {
1450 xxx = node->minPosition;
1451 }
1452 else if (xxx > node->maxPosition) {
1453 xxx = node->maxPosition;
1454 }
1455 }
1456 //translation clamped to LineSensor.minPosition/.maxPosition
1457 vecscale3f(translation, node->direction.c, xxx);
1458
1459#ifndef LINESENSOR_FLOAT_OFFSET
1460 //^add on any non-autoOffset non-.direction offset
1461 //a) part of offset going along direction
1462 vecscale3f(diroffset, node->direction.c, xxxoffset);
1463 //b) part of offset not going along direction
1464 vecdif3f(nondiroffset, node->offset.c, diroffset);
1465 //add non-direction part of offset
1466 vecadd3f(translation, translation, nondiroffset);
1467#endif
1468
1469 veccopy3f(node->_oldtranslation.c,translation);
1470
1471 if(!approx3f(node->_oldtranslation.c, node->translation_changed.c)) {
1472 veccopy3f(node->translation_changed.c, node->_oldtranslation.c);
1473 MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, translation_changed));
1474 }
1475 //save current for use in mouse-up auto-offset
1476 node->_origPoint.c[1] = xxx;
1477 }
1478 else if (ev == ButtonRelease) {
1479 /* set isActive false */
1480 node->isActive = FALSE;
1481 MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, isActive));
1482
1483 /* autoOffset? */
1484 if (node->autoOffset) {
1485#ifdef LINESENSOR_FLOAT_OFFSET
1486 node->offset = node->_origPoint.c[1];
1487#else
1488 veccopy3f(node->offset.c,node->translation_changed.c);
1489#endif
1490 MARK_EVENT(ptr, offsetof(struct X3D_LineSensor, offset));
1491 }
1492 }
1493
1494}
1495
1496
1497void do_PointSensor(void *ptr, int ev, int but1, int over) {
1498 /* Experimental node There is no PointSensor node in the specs in Dec 2017.
1499 Concept: you should be able to grab and drag something perpendicular to your ray.
1500 then if you move your viewpoint (ie with examine) you should be able to drag
1501 perpendicular to your new ray direction
1502 So the direction isn't in a field
1503 - its computed internally based on pickray/bearing direction
1504 - (in theory it could be an outputOnly)
1505 Trackpoint would start at ray/bearing distance from viewpoint
1506 */
1507 struct X3D_PointSensor *node;
1508 float trackpoint[3], translation[3], *posn, *rposn, *norm;
1509 ttglobal tg;
1510 UNUSED(over);
1511 node = (struct X3D_PointSensor *)ptr;
1512#ifdef SENSVERBOSE
1513 printf("%lf: TS ", TickTime());
1514 if (ev == ButtonPress) printf("ButtonPress ");
1515 else if (ev == ButtonRelease) printf("ButtonRelease ");
1516 else if (ev == KeyPress) printf("KeyPress ");
1517 else if (ev == KeyRelease) printf("KeyRelease ");
1518 else if (ev == MotionNotify) printf("%lf MotionNotify ");
1519 else printf("ev %d ", ev);
1520
1521 if (but1) printf("but1 TRUE "); else printf("but1 FALSE ");
1522 if (over) printf("over TRUE "); else printf("over FALSE ");
1523 printf("\n");
1524#endif
1525
1526 /* if not enabled, do nothing */
1527 if (!node) return;
1528
1529 if (node->__oldEnabled != node->enabled) {
1530 node->__oldEnabled = node->enabled;
1531 MARK_EVENT(X3D_NODE(node), offsetof(struct X3D_PointSensor, enabled));
1532 }
1533 if (!node->enabled) return;
1534 tg = gglobal();
1535
1536 /* only do something when button pressed */
1537 if (!but1) return;
1538 norm = tg->RenderFuncs.hyp_save_norm;
1539 posn = tg->RenderFuncs.hyp_save_posn;
1540 rposn = tg->RenderFuncs.ray_save_posn;
1541
1542 if ((ev == ButtonPress) && but1) {
1543 /* record the current position from the saved position */
1544 float tt[3];
1545 float distance = veclength3f(vecdif3f(tt,rposn,norm));
1546 //printf("dist0 = %f\n",distance);
1547 veccopy3f(trackpoint,rposn);
1548 veccopy3f(node->_origPoint.c,trackpoint);
1549
1550 /* set isActive true */
1551 node->isActive = TRUE;
1552 MARK_EVENT(ptr, offsetof(struct X3D_PointSensor, isActive));
1553
1554 }
1555 else if ((ev == MotionNotify) && (node->isActive) && but1) {
1556 /* trackpoint changed */
1557 float t1[3];
1558
1559 //pre-calculate for Press and Move
1560 /* hyperhit saved in render_hypersensitive phase */
1561 // bearing in sensor-local coordinates: (A=posn,B=norm)
1562 // B/norm is a point, so to get a direction vector: v = B - A
1563 float tt[3];
1564 //float N [] = { 0.0f, 0.0f, 1.0f };
1565 float v1[3];
1566
1567 veccopy3f(trackpoint,rposn);
1568
1569 veccopy3f(node->_oldtrackPoint.c,trackpoint);
1570 if(!approx3f(node->_oldtrackPoint.c, node->trackPoint_changed.c)) {
1571 veccopy3f(node->trackPoint_changed.c, node->_oldtrackPoint.c);
1572 MARK_EVENT(ptr, offsetof(struct X3D_PointSensor, trackPoint_changed));
1573 }
1574
1575 vecdif3f(v1, norm, posn);
1576 vecnormalize3f(v1, v1);
1577
1578 //IDEA intersect the pickray with a plane at distance to the mouse-down point
1579 // and drag in a plane perpendicular to the camera axis
1580 // ie plane = (mouse-down ray_posn, viewpoint axis)
1581 if (!line_intersect_plane_3f(posn,v1,tg->RenderFuncs.camera_axis,node->_origPoint.c,translation,NULL))
1582 return;
1583
1584 if (node->autoOffset){
1585 vecadd3f(translation,translation,node->offset.c);
1586 }
1587
1588
1589 //clamp to min,max
1590 vecclamp3f(translation,node->minPosition.c,node->maxPosition.c);
1591
1592 veccopy3f(node->_oldtranslation.c,translation);
1593
1594 if(!approx3f(node->_oldtranslation.c, node->translation_changed.c)) {
1595 veccopy3f(node->translation_changed.c, node->_oldtranslation.c);
1596 MARK_EVENT(ptr, offsetof(struct X3D_PointSensor, translation_changed));
1597 }
1598 }
1599 else if (ev == ButtonRelease) {
1600 /* set isActive false */
1601 node->isActive = FALSE;
1602 MARK_EVENT(ptr, offsetof(struct X3D_PointSensor, isActive));
1603 /* autoOffset? */
1604 if (node->autoOffset) {
1605 veccopy3f(node->offset.c,node->translation_changed.c);
1606 MARK_EVENT(ptr, offsetof(struct X3D_PointSensor, offset));
1607 }
1608 }
1609
1610}
1611
1612/* void do_PlaneSensor (struct X3D_PlaneSensor *node, int ev, int over) {*/
1613void do_PlaneSensor ( void *ptr, int ev, int but1, int over) {
1614 struct X3D_PlaneSensor *node;
1615 float mult, nx, ny, trackpoint[3], inverserotation[4], *posn;
1616 float tr[3];
1617 int tmp, imethod;
1618
1619 ttglobal tg;
1620 UNUSED(over);
1621 node = (struct X3D_PlaneSensor *)ptr;
1622#ifdef SENSVERBOSE
1623 ConsoleMessage("%lf: TS ",TickTime());
1624 if (ev==ButtonPress) ConsoleMessage("ButtonPress ");
1625 else if (ev==ButtonRelease) ConsoleMessage("ButtonRelease ");
1626 else if (ev==KeyPress) ConsoleMessage("KeyPress ");
1627 else if (ev==KeyRelease) ConsoleMessage("KeyRelease ");
1628 else if (ev==MotionNotify) ConsoleMessage("MotionNotify ");
1629 else ConsoleMessage("ev %d ",ev);
1630
1631 if (but1) ConsoleMessage("but1 TRUE "); else ConsoleMessage("but1 FALSE ");
1632 if (over) ConsoleMessage("over TRUE "); else ConsoleMessage("over FALSE ");
1633 ConsoleMessage ("\n");
1634#endif
1635
1636 /* if not enabled, do nothing */
1637 if (!node) return;
1638
1639 if (node->__oldEnabled != node->enabled) {
1640 node->__oldEnabled = node->enabled;
1641 MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_PlaneSensor, enabled));
1642 }
1643 if (!node->enabled) return;
1644 tg = gglobal();
1645
1646 /* only do something when button pressed */
1647 /* if (!but1) return; */
1648 if (but1){
1649 float v[3], t1[3];
1650 float N[3] = { 0.0f, 0.0f, 1.0f }; //plane normal, in plane-local
1651 float NS[3]; //plane normal, in sensor-local after axisRotation
1652 //bearing (A,B) in sensor-local
1653 // A=posn, B=norm - norm is a point. To get a direction vector v = (B - A)
1654 //ConsoleMessage("hsp = %f %f %f \n", tg->RenderFuncs.hyp_save_posn[0], tg->RenderFuncs.hyp_save_posn[1], tg->RenderFuncs.hyp_save_posn[2]);
1655 vecnormalize3f(v, vecdif3f(t1, tg->RenderFuncs.hyp_save_norm, tg->RenderFuncs.hyp_save_posn));
1656 //rotate plane normal N, in plane-local to plane normal NS in sensor-local using axisRotation
1657 axisangle_rotate3f(NS,N, node->axisRotation.c);
1658 //a plane P dot N = d = const, for any point P on plane. Our plane is in plane-local coords,
1659 // so we could use P={0,0,0} and P dot N = d = 0
1660 posn = tg->RenderFuncs.hyp_save_posn;
1661 if (!line_intersect_planed_3f(posn, v, NS, 0.0f, trackpoint, NULL))
1662 return; //looking at plane edge-on / parallel, no intersection
1663 //is rotating the trackpoint/translation_changed opposite sense to rotating the virtual geometry?
1664 //-- we harmonize with x3dom and view3dscene
1665 veccopy4f(inverserotation,node->axisRotation.c);
1666 inverserotation[3] = -inverserotation[3];
1667 //axisangle_rotate3f(trackpoint, trackpoint, inverserotation);
1668 }
1669
1670 if ((ev==ButtonPress) && but1) {
1671 /* record the current position from the saved position */
1672 struct SFColor op;
1673 float *posn;
1674 posn = tg->RenderFuncs.hyp_save_posn;
1675
1676 veccopy3f(op.c, trackpoint);
1677 memcpy((void *)&node->_origPoint, (void *)&op,sizeof(struct SFColor));
1678 veccopy3f(node->_origPoint.c,op.c);
1679
1680 /* set isActive true */
1681 node->isActive=TRUE;
1682 MARK_EVENT (ptr, offsetof (struct X3D_PlaneSensor, isActive));
1683
1684 } else if ((ev==MotionNotify) && (node->isActive) && but1) {
1685 /* hyperhit saved in render_hypersensitive phase */
1686 nx = trackpoint[0]; ny = trackpoint[1];
1687 #ifdef SEVERBOSE
1688 ConsoleMessage ("now, mult %f nx %f ny %f op %f %f %f\n",mult,nx,ny,
1689 node->_origPoint.c[0],node->_origPoint.c[1],
1690 node->_origPoint.c[2]);
1691 #endif
1692
1693 /* trackpoint changed */
1694 if(!node->sensorLocalOutput){
1695 axisangle_rotate3f(trackpoint,trackpoint, inverserotation);
1696 }
1697
1698 veccopy3f(node->_oldtrackPoint.c, trackpoint);
1699 /*printf(">%f %f %f\n",nx,ny,node->_oldtrackPoint.c[2]); */
1700 if(!approx3f(node->_oldtrackPoint.c,node->trackPoint_changed.c)) {
1701 veccopy3f(node->trackPoint_changed.c, node->_oldtrackPoint.c);
1702 MARK_EVENT(ptr, offsetof (struct X3D_PlaneSensor, trackPoint_changed));
1703
1704 }
1705
1706 /* clamp translation to max/min position */
1707 tr[0] = nx - node->_origPoint.c[0] + node->offset.c[0];
1708 tr[1] = ny - node->_origPoint.c[1] + node->offset.c[1];
1709 tr[2] = node->offset.c[2];
1710
1711 vecclamp2f(tr,node->minPosition.c,node->maxPosition.c);
1712 if(!node->sensorLocalOutput){
1713 axisangle_rotate3f(tr,tr, node->axisRotation.c);
1714 }
1715 veccopy3f(node->_oldtranslation.c,tr);
1716
1717 if(!approx3f(node->_oldtranslation.c,node->translation_changed.c)) {
1718 veccopy3f(node->translation_changed.c, (void *) node->_oldtranslation.c);
1719 MARK_EVENT(ptr, offsetof (struct X3D_PlaneSensor, translation_changed));
1720 }
1721
1722 } else if (ev==ButtonRelease) {
1723 /* set isActive false */
1724 node->isActive=FALSE;
1725 MARK_EVENT (ptr, offsetof (struct X3D_PlaneSensor, isActive));
1726
1727 /* autoOffset? */
1728 if (node->autoOffset) {
1729 veccopy3f(node->offset.c,node->translation_changed.c);
1730
1731 MARK_EVENT (ptr, offsetof (struct X3D_PlaneSensor, offset));
1732 }
1733 }
1734
1735}
1736
1737
1738/* void do_Anchor (struct X3D_Anchor *node, int ev, int over) {*/
1739void do_Anchor ( void *ptr, int ev, int but1, int over) {
1740 struct X3D_Anchor *node = (struct X3D_Anchor *)ptr;
1741 UNUSED(over);
1742 UNUSED(but1);
1743
1744 if (!node) return;
1745 /* try button release, so that we dont get worlds flashing past if
1746 the user keeps the finger down. :-) if (ev==ButtonPress) { */
1747 if (ev==ButtonRelease) {
1748 ttglobal tg = gglobal();
1749 /* no parameters in url field? */
1750 if (node->url.n < 1) return;
1751 setAnchorsAnchor( node );
1752 #ifdef OLDCODE
1753 OLDCODE FREE_IF_NZ(tg->RenderFuncs.OSX_replace_world_from_console);
1754 #endif // OLDCODE
1755
1756 tg->RenderFuncs.BrowserAction = TRUE;
1757 }
1758}
1759
1760//double angleAcuteDifferenced(double angle1, double angle2){
1761// //sometimes we cross over the -PI or PI barrier and get a jump
1762// //when really we want the small incremental difference
1763// double angledif = angle2 - angle1;
1764// if(angledif > PI) angledif -= 2*PI;
1765// if(angledif < -PI) angledif += 2*PI;
1766// return angledif;
1767//}
1768//double angleNormalized(double angle){
1769// return atan2(sin(angle),cos(angle));
1770//}
1771
1772void do_CylinderSensor ( void *ptr, int ev, int but1, int over) {
1773 //troubled
1774 struct X3D_CylinderSensor *node = (struct X3D_CylinderSensor *)ptr;
1775 double rot, radius, ang, length;
1776 double det, pos, neg, temp;
1777 double acute_angle, disk_angle, height;
1778 float Y[3] = { 0.0f, 1.0f, 0.0f }, ZERO[3] = { 0.0f, 0.0f, 0.0f };
1779 float aBearing[3], bBearing[3], dirBearing[3], posn[3], axisRotation[4];
1780 Quaternion bv, dir1, dir2, tempV;
1781 GLDOUBLE modelMatrix[16];
1782 ttglobal tg;
1783
1784 UNUSED(over);
1785
1786 /* if not enabled, do nothing */
1787 if (!node) return;
1788 if (node->__oldEnabled != node->enabled) {
1789 node->__oldEnabled = node->enabled;
1790 MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_CylinderSensor, enabled));
1791 }
1792 if (!node->enabled) return;
1793
1794 /* only do something if the button is pressed */
1795 if (!but1) return;
1796 tg = gglobal();
1797
1798 /*precompute some values for mouse-down, mouse-move*/
1799 //convert all almost-sensor-local points into sensor-local
1800 //(the axisRotation never gets applied in the modelview transform stack - if that changes in the future, then don't need these)
1801 veccopy4f(axisRotation,node->axisRotation.c);
1802 axisRotation[3] = -axisRotation[3]; //harmonize rotation with view3dscene
1803 //Dec 2017 view3dscene only other browser that shares our interp of specs on axisRotation for CylinderSensor
1804 //- x3dom and view3dscene share our interpretation of axisRotation for Planesensor
1805 axisangle_rotate3f(aBearing, tg->RenderFuncs.hyp_save_posn, axisRotation);
1806 axisangle_rotate3f(bBearing, tg->RenderFuncs.hyp_save_norm, axisRotation);
1807 vecnormalize3f(dirBearing, vecdif3f(dirBearing, bBearing, aBearing));
1808 axisangle_rotate3f(posn,tg->RenderFuncs.ray_save_posn, axisRotation);
1809
1810 if (ev==ButtonPress) {
1811 /* record the current position from the saved position */
1812 /* on mouse-down we have to decide which sensor geometry to use: disk or cylinder, as per specs
1813 http://www.web3d.org/files/specifications/19775-1/V3.3/Part01/components/pointingsensor.html#CylinderSensor
1814 and that's determined by the angle between the bearing and the sensor Y axis, in sensor-local coords
1815 The bearing (A,B) where A=hyp_posn, B=hyp_norm and both are points in sensor-local coordinates
1816 To get a direction vector v = B - A
1817 */
1818 struct SFColor origPoint;
1819 /*ray_save_posn is the intersection with scene geometry, in sensor-local coordinates, for cylinder*/
1820 float dot, rs[3];
1821
1822 dot = vecdot3f(dirBearing, Y);
1823 dot = fclamp(dot,-1.0f,1.0f);
1824 acute_angle = acos(dot);
1825 ang = min(acute_angle,PI - acute_angle);
1826 //printf("ang= %f\n",(float)ang);
1827 veccopy3f(rs, posn); //posn: ray_posn (intersection with scene geometry) in sensor-local
1828 height = rs[1];
1829 rs[1] = 0.0f;
1830 //radius of ray_posn from cylinder axis,
1831 //for scaling the 'feel' of the rotations to what the user clicked
1832 radius = veclength3f(rs);
1833 vecnormalize3f(rs, rs);
1834 if (ang < node->diskAngle){
1835 //use end cap disks
1836 node->_usingDisk = TRUE;
1837 disk_angle = -atan2(rs[2], rs[0]);
1838 printf("using disk\n");
1839 }else{
1840 //use cylinder wall
1841 node->_usingDisk = FALSE;
1842 //printf("using cylinder\n");
1843 float travelled, cylpoint[3], axispoint[3], dif[3];
1844 line_intersect_line_3f(aBearing, dirBearing, ZERO, Y, NULL, NULL, cylpoint, axispoint);
1845 //travelled: closest distance of our bearing from cylinder axis
1846 travelled = veclength3f(vecdif3f(dif, cylpoint, axispoint));
1847 //which side of cylinder axis is our bearing on?
1848 //v x dif will point a different direction (up or down)
1849 //depending on which side, so dot with Y to get a sign
1850 if (det3f(dirBearing, dif, Y) > 0.0f) travelled = -travelled;
1851 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
1852 }
1853 node->_radius = (float)radius; //store for later use on mouse-moves
1854 //printf("radius= %f\n",node->_radius);
1855 //origPoint - we get to store whatever we need later mouse-moves.
1856 //GOAL: be able to crank the disk, and keep going around in circles, accumulating angle, like s screw
1857 //printf("disk_angle=%f\n",(float)disk_angle);
1858 node->_origPoint.c[0] = disk_angle;
1859 node->_origPoint.c[1] = -height; //Q. why -height? don't know but it works
1860 //printf("rsp = %f %f %f\n",tg->RenderFuncs.ray_save_posn[0],tg->RenderFuncs.ray_save_posn[1],tg->RenderFuncs.ray_save_posn[2]);
1861 //printf("eqv = %f %f %f\n",cos(-disk_angle)*radius,height,sin(-disk_angle)*radius);
1862 /* set isActive true */
1863 node->isActive=TRUE;
1864 MARK_EVENT (ptr, offsetof (struct X3D_CylinderSensor, isActive));
1865
1866 }else if ((ev == MotionNotify) && (node->isActive)) {
1867 float trackpoint[3], rotation4f[4];
1868 //specs > cylsensor: "trackPoint_changed events represent the unclamped intersection points
1869 // on the surface of the invisible cylinder or disk"
1870 // Q. in sensor-local or sensor?
1871 veccopy3f(trackpoint,node->_oldtrackPoint.c); //a default, some non-junk value
1872
1873
1874 //compute delta rotation from drag
1875 //a plane P dot N = d = const, for any point P on plane. Our plane is in plane-local coords,
1876 // so we could use P={0,0,0} and P dot N = d = 0
1877 float diskpoint[3], orig_diskangle, height;
1878 height = node->_origPoint.c[1];
1879 radius = node->_radius;
1880 orig_diskangle = node->_origPoint.c[0];
1881 if (node->_usingDisk == TRUE) {
1882 //disk
1883 line_intersect_planed_3f(aBearing, dirBearing, Y, height, diskpoint, NULL);
1884 veccopy3f(trackpoint,diskpoint);
1885 vecnormalize3f(diskpoint, diskpoint);
1886 //for cylinder compute angle from intersection on cylinder of radius
1887 disk_angle = -atan2(diskpoint[2], diskpoint[0]);
1888 //printf("D1 %lf ",disk_angle);
1889 }else {
1890 float cylpoint[3]; //pi1[3],
1891 //cylinder wall
1892 //we want a drag off the cylinder to keep working even when mouse isn't over cylinder
1893 //on the cylinder
1894 //basically we try and do a linear drag perpendicular to both our bearing and the cylinder
1895 //axis, and convert that linear distance from cylinder axis from distance into rotations
1896 float travelled, axispoint[3], dif[3];
1897 line_intersect_line_3f(aBearing, dirBearing, ZERO, Y, NULL, NULL, cylpoint, axispoint);
1898 //cylpoint - closest point of approach of our bearing, on the bearing
1899 //axispoint - ditto, on the cyl axis
1900 //dif = cylpoint - axispoint //vector perpendicular to axis - our perpendicular 'travel' from the axis
1901 travelled = veclength3f(vecdif3f(dif, cylpoint, axispoint));
1902 if (det3f(dirBearing, 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
1903 //convert from linear travel to rotation, using travel/circumference * 2PI
1904 disk_angle = travelled / (2.0f * PI * radius) * (2.0f * PI); //convert from distance to radians using ratio of circumference
1905 if(!line_intersect_cylinder_3f(aBearing,dirBearing,node->_radius,trackpoint))
1906 veccopy3f(trackpoint,cylpoint);
1907
1908 }
1909 rot = disk_angle - orig_diskangle;
1910 //printf(" D2 %lf ",rot);
1911 if (node->autoOffset) {
1912 //printf(" O %f ",node->offset);
1913 rot = node->offset + rot;
1914 }
1915 //printf(" D3 %lf ",rot);
1916 //printf(" N %lf ",rot);
1917 if (node->minAngle < node->maxAngle) {
1918 rot = fclamp(rot,node->minAngle,node->maxAngle);
1919 }
1920 //printf(" D4 %lf \n",rot);
1921
1922 vecset4f(rotation4f,0.0f,1.0f,0.0f,(float)rot);
1923
1924 if(!node->sensorLocalOutput){
1925 //this matches the octaga/instant/h3d technique
1926 axisangle_rotate3f(rotation4f,rotation4f,node->axisRotation.c); //rotate axis only
1927 }
1928 veccopy4f(node->_oldrotation.c,rotation4f);
1929 if(!approx4f(node->_oldrotation.c,node->rotation_changed.c)) {
1930 veccopy4f(node->rotation_changed.c, node->_oldrotation.c);
1931 MARK_EVENT(ptr, offsetof (struct X3D_CylinderSensor, rotation_changed));
1932 }
1933
1934 //the specs don't explicitly say if the trackpoint is in sensor-local (with axisRotation applied)
1935 // or node-local. But it seems easier to understand if in node-local
1936 if(!node->sensorLocalOutput)
1937 axisangle_rotate3f(trackpoint, trackpoint, node->axisRotation.c);
1938 veccopy3f(node->_oldtrackPoint.c,trackpoint);
1939 if(!approx3f(node->_oldtrackPoint.c, node->trackPoint_changed.c)) {
1940 veccopy3f(node->trackPoint_changed.c, node->_oldtrackPoint.c);
1941 MARK_EVENT(ptr, offsetof(struct X3D_CylinderSensor, trackPoint_changed));
1942 }
1943
1944 } else if (ev==ButtonRelease) {
1945 /* set isActive false */
1946 node->isActive=FALSE;
1947 MARK_EVENT (ptr, offsetof (struct X3D_CylinderSensor, isActive));
1948 /* save auto offset of rotation */
1949 if (node->autoOffset) {
1950 node->offset = node->rotation_changed.c[3];
1951 }
1952 }
1953}
1954// see Mainloop.c get_hyperhit() for more explanation:
1955// in sensor-node-local coordinates (not quite sensor-local if sensor node has axisRotation):
1956// ray_save_posn - intersection point of pickray/bearing with sensitized geometry
1957// hyp_save_posn - point on camera/viewpoint nearplane on pickray/bearing, transformed to sensor-node-local
1958// hyp_save_norm - point on carmera/viewpoint farplane on pickray/bearing, transformed to sensor-node-local
1959
1960float fwfdsign(float x){ return x >= 0.0f ? 1.0f : -1.0f; }
1961
1962void do_CylinderSensor_simple ( void *ptr, int ev, int but1, int over) {
1963 //simplest cylinder case, no axisRotation, no disk, derived from SphereSensor
1964 //not used except for understanding
1965 struct X3D_CylinderSensor *node = (struct X3D_CylinderSensor *)ptr;
1966
1967 float *cur, *orig, onorm[3];
1968 ttglobal tg;
1969 UNUSED(over);
1970
1971 /* if not enabled, do nothing */
1972 if (!node)
1973 return;
1974 if (node->__oldEnabled != node->enabled) {
1975 node->__oldEnabled = node->enabled;
1976 MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_CylinderSensor, enabled));
1977 }
1978 if (!node->enabled)
1979 return;
1980
1981 /* only do something if button1 is pressed */
1982 if (!but1) return;
1983 tg = gglobal();
1984
1985 cur = tg->RenderFuncs.ray_save_posn;
1986 orig = node->_origPoint.c;
1987 veccopy3f(onorm,orig);
1988 onorm[1] = 0.0f;
1989 vecnormalize3f(onorm,onorm);
1990 if (ev==ButtonPress) {
1991 /* record the current position from the saved position */
1992 float pcur[3], height;
1993 veccopy3f(orig,cur);
1994
1995 /* record the current Radius */
1996 veccopy3f(pcur,cur);
1997 height = pcur[1];
1998 pcur[1] = 0.0f;
1999 node->_radius = veclength3f(pcur);
2000 if (APPROX(node->_radius,0.0)) {
2001 printf ("warning, RADIUS %lf == 0, can not compute\n",node->_radius);
2002 return;
2003 }
2004
2005 /* save the initial norm here */
2006 //vecscale3f(onorm,cur,1.0f / node->_radius);
2007
2008 /* set isActive true */
2009 node->isActive=TRUE;
2010 MARK_EVENT (ptr, offsetof (struct X3D_CylinderSensor, isActive));
2011 } else if (ev==ButtonRelease) {
2012 /* set isActive false */
2013 node->isActive=FALSE;
2014 MARK_EVENT (ptr, offsetof (struct X3D_CylinderSensor, isActive));
2015
2016 if (node->autoOffset) {
2017 node->offset = node->rotation_changed.c[3];
2018 }
2019 } else if ((ev==MotionNotify) && (node->isActive)) {
2020
2021 float dotProd, sine, angle;
2022 float newRad;
2023 float cnorm[3];
2024 float newAxis[3];
2025 float pcur[3], height;
2026
2027 /* record the current Radius */
2028 height = cur[1];
2029 veccopy3f(pcur,cur);
2030 pcur[1] = 0.0f;
2031 newRad = veclength3f(pcur);
2032 /* bounds check... */
2033 if (APPROX(newRad,0.0)) {
2034 printf ("warning, newRad %lf == 0, can not compute\n",newRad);
2035 return;
2036 }
2037
2038 /* save the current norm here */
2039 //vecscale3f(cnorm,cur,1.0f/newRad);
2040 vecnormalize3f(cnorm,pcur);
2041
2042 /* find the cross-product between the initial and current points */
2043 veccross3f(newAxis,onorm,cnorm);
2044 sine = veclength3f(newAxis);
2045
2046 /* clamp the angle to |a| < 1.0 */
2047 /* remember A dot B = |A|*|B|*cos(theta_between) or theta_between = acos(A dot B/|A|*|B| ) */
2048 //dotProd = NORM_ORIG_X * NORM_CUR_X + NORM_ORIG_Y * NORM_CUR_Y + NORM_ORIG_Z * NORM_CUR_Z;
2049 dotProd = vecdot3f(onorm,cnorm);
2050 dotProd = fclamp(dotProd,-1.0f,1.0f);
2051 angle = acos(dotProd) * fwfdsign(newAxis[1]);
2052
2053 /* have axis-angle now */
2054 /*
2055 printf ("newRotation a %lf - rot -- %lf %lf %lf %lf\n",
2056 dotProd, newA.x,newA.y,newA.z,dotProd);
2057 */
2058 if(node->autoOffset)
2059 {
2060 angle += node->offset;
2061 angle = atan2(sin(angle),cos(angle));
2062 }
2063
2064
2065 //veccopy3f(node->rotation_changed.c,newAxis);
2066 vecset3f(node->rotation_changed.c,0.0f,1.0f,0.0f);
2067 node->rotation_changed.c[3] = angle;
2068 MARK_EVENT (ptr, offsetof (struct X3D_CylinderSensor, rotation_changed));
2069
2070 vecscale3f(node->trackPoint_changed.c,cnorm, node->_radius);
2071 node->trackPoint_changed.c[1] = height;
2072 MARK_EVENT (ptr, offsetof (struct X3D_CylinderSensor, trackPoint_changed));
2073 }
2074}
2075
2076
2077/********************************************************************************/
2078/* */
2079/* do the guts of a SphereSensor.... this has been changed considerably in Apr */
2080/* 2009 because the original, fast methods created by Tuomas Lukka failed in */
2081/* a boundary area (HUD, small transform scale, close to viewer) and I could */
2082/* not understand what *exactly* Tuomas' code did - I guess I don't have a */
2083/* doctorate in math like he does! I went to the old linear algebra text and */
2084/* created a simple but inelegant solution from that. J.A. Stewart. */
2085/* */
2086/********************************************************************************/
2087
2088void do_SphereSensor ( void *ptr, int ev, int but1, int over) {
2089 struct X3D_SphereSensor *node = (struct X3D_SphereSensor *)ptr;
2090
2091 float *cur, *orig, *onorm;
2092 ttglobal tg;
2093 UNUSED(over);
2094
2095 /* if not enabled, do nothing */
2096 if (!node)
2097 return;
2098 if (node->__oldEnabled != node->enabled) {
2099 node->__oldEnabled = node->enabled;
2100 MARK_EVENT(X3D_NODE(node),offsetof (struct X3D_SphereSensor, enabled));
2101 }
2102 if (!node->enabled)
2103 return;
2104
2105 /* only do something if button1 is pressed */
2106 if (!but1) return;
2107 tg = gglobal();
2108
2109 cur = tg->RenderFuncs.ray_save_posn;
2110 orig = node->_origPoint.c;
2111 onorm = node->_origNormalizedPoint.c;
2112 if (ev==ButtonPress) {
2113 /* record the current position from the saved position */
2114 veccopy3f(orig,cur);
2115
2116 /* record the current Radius */
2117 //RADIUS = (float) sqrt(CUR_X * CUR_X + CUR_Y * CUR_Y + CUR_Z * CUR_Z);
2118 node->_radius = veclength3f(cur);
2119 if (APPROX(node->_radius,0.0)) {
2120 printf ("warning, RADIUS %lf == 0, can not compute\n",node->_radius);
2121 return;
2122 }
2123
2124 /* save the initial norm here */
2125 vecscale3f(onorm,cur,1.0f / node->_radius);
2126
2127 /* norm(offset) ideally this would be done once during parsing
2128 of crazy SFRotation ie '1 1 -5 .6' in 10.wrl/10.x3d
2129 I might be getting rounding errors from repeated normalization */
2130 vrmlrot_normalize(node->offset.c);
2131
2132 /* set isActive true */
2133 node->isActive=TRUE;
2134 MARK_EVENT (ptr, offsetof (struct X3D_SphereSensor, isActive));
2135 } else if (ev==ButtonRelease) {
2136 /* set isActive false */
2137 node->isActive=FALSE;
2138 MARK_EVENT (ptr, offsetof (struct X3D_SphereSensor, isActive));
2139
2140 if (node->autoOffset) {
2141 veccopy4f(node->offset.c,node->rotation_changed.c);
2142 }
2143 } else if ((ev==MotionNotify) && (node->isActive)) {
2144
2145 float dotProd;
2146 float newRad;
2147 float cnorm[3];
2148 float newA[4];
2149
2150 /* record the current Radius */
2151 newRad = veclength3f(cur);
2152 /* bounds check... */
2153 if (APPROX(newRad,0.0)) {
2154 printf ("warning, newRad %lf == 0, can not compute\n",newRad);
2155 return;
2156 }
2157
2158 /* save the current norm here */
2159 vecscale3f(cnorm,cur,1.0f/newRad);
2160
2161 /* find the cross-product between the initial and current points */
2162 veccross3f(newA,orig,cur);
2163 vecnormalize3f(newA,newA);
2164
2165 /* clamp the angle to |a| < 1.0 */
2166 /* remember A dot B = |A|*|B|*cos(theta_between) or theta_between = acos(A dot B/|A|*|B| ) */
2167 //dotProd = NORM_ORIG_X * NORM_CUR_X + NORM_ORIG_Y * NORM_CUR_Y + NORM_ORIG_Z * NORM_CUR_Z;
2168 dotProd = vecdot3f(onorm,cnorm);
2169 if (dotProd > 1.0)
2170 dotProd = 1.0;
2171 if (dotProd < -1.0)
2172 dotProd = -1.0;
2173 dotProd = acos(dotProd);
2174 newA[3] = dotProd;
2175
2176 /* have axis-angle now */
2177 /*
2178 printf ("newRotation a %lf - rot -- %lf %lf %lf %lf\n",
2179 dotProd, newA.x,newA.y,newA.z,dotProd);
2180 */
2181 if(node->autoOffset)
2182 {
2183
2184 /* copied from the javascript SFRotationMultiply */
2185 Quaternion q1, q2, qret;
2186 double newD[4];
2187 /* convert both rotations into quaternions */
2188 vrmlrot_to_quaternion(&q1, (double) newA[0],
2189 (double) newA[1], (double) newA[2], (double) dotProd);
2190 vrmlrot_to_quaternion(&q2, (double) node->offset.c[0],
2191 (double) node->offset.c[1], (double) node->offset.c[2], (double) node->offset.c[3]);
2192 /* multiply them */
2193 quaternion_multiply(&qret,&q1,&q2);
2194 /* and return the resultant, as a vrml rotation */
2195 quaternion_to_vrmlrot(&qret, &newD[0], &newD[1], &newD[2], &newD[3]);
2196 newA[0] = newD[0]; newA[1] = newD[1], newA[2] = newD[2], newA[3] = newD[3];
2197 dotProd = newD[3];
2198 /*}*/
2199 }
2200
2201
2202 veccopy4f(node->rotation_changed.c,newA);
2203 MARK_EVENT (ptr, offsetof (struct X3D_SphereSensor, rotation_changed));
2204
2205 vecscale3f(node->trackPoint_changed.c,cnorm, node->_radius);
2206 MARK_EVENT (ptr, offsetof (struct X3D_SphereSensor, trackPoint_changed));
2207 }
2208}