34 #include <libFreeWRL.h>
36 #include "../vrml_parser/Structs.h"
37 #include "../opengl/OpenGL_Utils.h"
38 #include "../main/headers.h"
40 #include "LinearAlgebra.h"
41 #include "quaternion.h"
43 #include "../x3d_parser/Bindable.h"
44 #include "ui/common.h"
54 static void init_stereodefaults(
X3D_Viewer *Viewer)
57 Viewer->shutterGlasses = 0;
59 Viewer->sidebyside = 0;
62 Viewer->eyedist = 0.065;
68 Viewer->screendist = 0.375;
69 Viewer->stereoParameter = 0.01;
70 Viewer->dominantEye = 1;
71 Viewer->eitherDominantEye = 1;
74 Viewer->haveQuadbuffer = 0;
81 int viewer_initialized;
90 int StereoInitializedOnce;
91 GLboolean acMask[3][3];
94 double viewpoint2rootnode[16];
95 double viewpointnew2rootnode[16];
106 void *Viewer_constructor(){
107 void *v = MALLOCV(
sizeof(
struct pViewer));
108 memset(v,0,
sizeof(
struct pViewer));
111 void Viewer_init(
struct tViewer *t){
115 t->prv = Viewer_constructor();
119 p->examineCounter = 5;
121 p->viewer_initialized = FALSE;
127 p->StereoInitializedOnce = 0;
128 p->acMask[0][0] = (GLboolean)1;
130 p->acMask[1][1] = (GLboolean)1;
131 p->acMask[1][2] = (GLboolean)1;
134 loadIdentityMatrix(p->viewpoint2rootnode);
135 p->vp2rnSaved = FALSE;
136 loadIdentityMatrix(p->old2new);
137 loadIdentityMatrix(p->identity);
140 p->StereoInitializedOnce = 1;
141 p->keychord = CHORD_XY;
142 p->dragchord = CHORD_YAWZ;
150 static void handle_tick_fly(
void);
151 static void handle_tick_exfly(
void);
152 static void handle_tick_fly2(
double dtime);
156 void getCurrentSpeed() {
162 tg->Mainloop.BrowserSpeed = tg->Mainloop.BrowserFPS * (fabs(viewer->VPvelocity.x) + fabs(viewer->VPvelocity.y) + fabs(viewer->VPvelocity.z));
169 viewer->fieldofview = 45.0;
170 viewer->fovZoom = 1.0;
172 viewer->VPvelocity.x = 0.0; viewer->VPvelocity.y = 0.0; viewer->VPvelocity.z = 0.0;
173 viewer->Pos.x = 0; viewer->Pos.y = 0; viewer->Pos.z = 10;
174 viewer->currentPosInModel.x = 0; viewer->currentPosInModel.y = 0; viewer->currentPosInModel.z = 10;
175 viewer->AntiPos.x = 0; viewer->AntiPos.y = 0; viewer->AntiPos.z = 0;
177 vrmlrot_to_quaternion (&viewer->Quat,1.0,0.0,0.0,0.0);
178 vrmlrot_to_quaternion (&viewer->bindTimeQuat,1.0,0.0,0.0,0.0);
179 vrmlrot_to_quaternion (&viewer->prepVPQuat,0.0,1.0,0.0,3.14);
180 vrmlrot_to_quaternion (&q_i,1.0,0.0,0.0,0.0);
181 quaternion_inverse(&(viewer->AntiQuat),&q_i);
183 viewer->headlight = TRUE;
193 if(vpnodetype == NODE_OrthoViewpoint){
195 fwl_set_viewer_type0(viewer,VIEWER_NONE);
196 viewer->orthoField[0] = -1.0;
197 viewer->orthoField[1] = -1.0;
198 viewer->orthoField[2] = 1.0;
199 viewer->orthoField[3] = 1.0;
200 viewer->nearPlane = 0.1;
201 viewer->farPlane = 210000.0;
202 viewer->ortho = TRUE;
205 fwl_set_viewer_type0(viewer,VIEWER_EXAMINE);
207 viewer->LookatMode = 0;
212 viewer->GeoSpatialNode = NULL;
226 bstack = getBindableStacksByLayer(tg,layerid);
231 vpnodetype = bstack->nodetype == NODE_LayoutLayer ? NODE_OrthoViewpoint : NODE_Viewpoint;
232 viewer_default0(viewer,vpnodetype);
233 init_stereodefaults(viewer);
234 bstack->viewer = viewer;
236 return bstack->viewer;
242 return ViewerByLayerId(tg->Bindable.activeLayer);
245 void viewer_default() {
248 viewer_default0(viewer,NODE_Viewpoint);
253 void viewer_init (
X3D_Viewer *viewer,
int type) {
258 if (!p->viewer_initialized) {
259 p->viewer_initialized = TRUE;
264 viewer->Pos.x = 0; viewer->Pos.y = 0; viewer->Pos.z = 10;
265 viewer->currentPosInModel.x = 0; viewer->currentPosInModel.y = 0; viewer->currentPosInModel.z = 10;
266 viewer->AntiPos.x = 0; viewer->AntiPos.y = 0; viewer->AntiPos.z = 0;
269 vrmlrot_to_quaternion (&viewer->Quat,1.0,0.0,0.0,0.0);
270 vrmlrot_to_quaternion (&viewer->bindTimeQuat,1.0,0.0,0.0,0.0);
271 vrmlrot_to_quaternion (&viewer->prepVPQuat,1.0,0.0,0.0,0.0);
272 vrmlrot_to_quaternion (&q_i,1.0,0.0,0.0,0.0);
273 quaternion_inverse(&(viewer->AntiQuat),&q_i);
275 viewer->headlight = TRUE;
276 viewer->collision = FALSE;
289 viewer->SLERPing = FALSE;
290 viewer->startSLERPtime = 0.0;
291 viewer->transitionType = 1;
292 viewer->transitionTime = 1.0;
295 viewer->ortho = FALSE;
297 viewer->doExamineModeDistanceCalculations = FALSE;
300 viewer->screenOrientation = 0;
302 viewer->nearPlane=DEFAULT_NEARPLANE;
303 viewer->farPlane=DEFAULT_FARPLANE;
304 viewer->backgroundPlane = DEFAULT_BACKGROUNDPLANE;
305 viewer->fieldofview=45.0;
306 viewer->fovZoom = 1.0;
308 viewer->wasBound = FALSE;
311 resolve_pos20(viewer);
316 int getCRouteCount();
317 void printStatsRoutes()
319 ConsoleMessage(
"%25s %d\n",
"Routes count", getCRouteCount());
322 void printStatsBindingStacks();
323 void printStatsResources();
324 void printStatsEvents();
325 void printStatsNodes();
329 printStatsResources();
333 printStatsBindingStacks();
345 quaternion_to_vrmlrot(&(viewer->Quat), &(ori.x),&(ori.y),&(ori.z), &(ori.a));
346 ConsoleMessage(
"Viewpoint local{\n");
347 ConsoleMessage(
"\tPosition[%.4f, %.4f, %.4f]\n", (viewer->Pos).x, (viewer->Pos).y, (viewer->Pos).z);
348 ConsoleMessage(
"\tQuaternion[%.4f, %.4f, %.4f, %.4f]\n", (viewer->Quat).w, (viewer->Quat).x, (viewer->Quat).y, (viewer->Quat).z);
349 ConsoleMessage(
"\tOrientation[%.4f, %.4f, %.4f, %.4f]\n", ori.x, ori.y, ori.z, ori.a);
350 ConsoleMessage(
"}\n");
351 getCurrentPosInModel(FALSE);
352 ConsoleMessage(
"World Coordinates of Avatar [%.4f, %.4f %.4f]\n",viewer->currentPosInModel.x,viewer->currentPosInModel.y,viewer->currentPosInModel.z);
356 int fwl_get_headlight() {
357 return(Viewer()->headlight);
360 void fwl_toggle_headlight() {
365 if (viewer->headlight == TRUE) {
366 viewer->headlight = FALSE;
368 viewer->headlight = TRUE;
376 void setNoCollision() {
380 viewer->collision = 0;
384 int get_collision() {
385 return fwl_getCollision();
387 void toggle_collision() {
391 viewer->collision = 1 - viewer->collision;
397 int fwl_getCollision(){
401 return viewer->collision;
403 void fwl_setCollision(
int state) {
407 viewer->collision = state;
410 void fwl_init_StereoDefaults()
415 if(!p->StereoInitializedOnce)
416 init_stereodefaults(viewer);
417 p->StereoInitializedOnce = 1;
421 void set_eyehalf(
const double eyehalf,
const double eyehalfangle) {
426 viewer->eyehalf = eyehalf;
427 viewer->eyehalfangle = eyehalfangle;
431 void fwl_set_viewer_type0(
X3D_Viewer *viewer,
const int type) {
435 if(viewer->type != type){
436 tg->Mainloop.CTRL = FALSE;
437 switch(viewer->type){
440 viewer->LookatMode = 0;
449 resolve_pos20(viewer);
457 case VIEWER_TURNTABLE:
462 case VIEWER_SPHERICAL:
464 if(viewer->type == type){
466 if(tg->Mainloop.CTRL){
467 tg->Mainloop.CTRL = FALSE;
469 tg->Mainloop.CTRL = TRUE;
479 if(viewer->type == type){
481 if(tg->Mainloop.CTRL){
482 tg->Mainloop.CTRL = FALSE;
483 viewer->LookatMode = 0;
485 tg->Mainloop.CTRL = TRUE;
486 viewer->LookatMode = 1;
495 if(viewer->type == type){
497 viewer->type = viewer->lastType;
498 viewer->LookatMode = 0;
501 viewer->lastType = viewer->type;
502 viewer->LookatMode = 1;
507 ConsoleMessage (
"Viewer type %d is not supported. See Viewer.h.\n", type);
508 viewer->type = VIEWER_NONE;
513 viewer->VPvelocity.x=0.0; viewer->VPvelocity.y=0.0; viewer->VPvelocity.z=0.0;
517 if (vectorSize(getActiveBindableStacks(tg)->navigation) >0)
518 if (viewer->oktypes[type]==FALSE) {
523 if(1) viewer_init(viewer,type);
529 void fwl_set_viewer_type(
const int type) {
533 fwl_set_viewer_type0(viewer, type);
539 #define VIEWER_STRING(type) ( \
540 type == VIEWER_NONE ? "NONE" : ( \
541 type == VIEWER_EXAMINE ? "EXAMINE" : ( \
542 type == VIEWER_WALK ? "WALK" : ( \
543 type == VIEWER_EXFLY ? "EXFLY" : ( \
544 type == VIEWER_SPHERICAL ? "SPHERICAL" : (\
545 type == VIEWER_TURNTABLE ? "TURNTABLE" : (\
546 type == VIEWER_FLY ? "FLY" : "UNKNOWN"))))))
550 #define strcasecmp _stricmp
557 {
"NONE",VIEWER_NONE},
558 {
"WALK",VIEWER_WALK},
560 {
"EXAMINE",VIEWER_EXAMINE},
561 {
"SPHERICAL",VIEWER_SPHERICAL},
562 {
"TURNTABLE",VIEWER_TURNTABLE},
563 {
"EXPLORE",VIEWER_EXPLORE},
564 {
"LOOKAT",VIEWER_LOOKAT},
565 {
"YAWZ",VIEWER_YAWZ},
567 {
"YAWPITCH",VIEWER_YAWPITCH},
568 {
"ROLL",VIEWER_ROLL},
569 {
"DIST",VIEWER_DIST},
572 char * lookup_navmodestring(
int navmode){
580 if(nm->type == navmode){
585 }
while(navmodes[i].
key);
586 if(!retval) retval =
"NONE";
589 int lookup_navmode(
char *cmode){
597 if(!strcasecmp(nm->key,cmode)){
602 }
while(navmodes[i].key);
605 char* fwl_getNavModeStr()
611 return lookup_navmodestring(viewer->type);
652 int fwl_setNavMode(
char *mode){
653 int imode = lookup_navmode(mode);
654 fwl_set_viewer_type(imode);
670 struct point_XYZ rot, z_axis = { 0, 0, 1 };
680 quaternion_inverse(&q_inv, &(viewer->Quat));
681 quaternion_rotation(&rot, &q_inv, &z_axis);
690 (examine->Origin).x = (viewer->Pos).x - viewer->Dist * rot.x;
691 (examine->Origin).y = (viewer->Pos).y - viewer->Dist * rot.y;
692 (examine->Origin).z = (viewer->Pos).z - viewer->Dist * rot.z;
698 void resolve_pos2() {
701 resolve_pos20(viewer);
708 double cosine, sine, ulen, vlen, scale, dot, angle;
712 ulen = sqrt(vecdot(V1,V1));
713 vlen = sqrt(vecdot(V2,V2));
715 if( APPROX(scale, 0.0) )
717 rotaxis->y = rotaxis->z = 0.0;
723 veccross(&cross,*V1,*V2);
724 sine = sqrt(vecdot(&cross,&cross))/scale;
726 angle = atan2(sine,cosine);
727 vecnormal(rotaxis,&cross);
730 void avatar2BoundViewpointVerticalAvatar(GLDOUBLE *matA2BVVA, GLDOUBLE *matBVVA2A)
737 struct point_XYZ downvec = {0.0,-1.0,0.0};
742 quaternion_rotation(&tilted, &viewer->Quat, &downvec);
744 matrotate2v(matA2BVVA,downvec,tilted);
745 matrotate2v(matBVVA2A,tilted,downvec);
751 void viewer_level_to_bound()
799 struct point_XYZ downvec = {0.0,-1.0,0.0};
805 quaternion_rotation(&tilted, &Quat, &downvec);
807 angle = vecangle2(&downvec,&tilted,&rotaxis);
808 if( APPROX(angle,0.0) )
return;
809 vrmlrot_to_quaternion(&q, rotaxis.x, rotaxis.y, rotaxis.z, -angle );
810 quaternion_normalize(&q);
811 quaternion_multiply(&(viewer->Quat), &q, &Quat);
812 quaternion_normalize(&(viewer->Quat));
818 void viewer_togl(
double fieldofview)
848 if (viewer->isStereo)
849 set_stereo_offset0();
851 if (viewer->SLERPing) {
865 tickFrac = (TickTime() - viewer->startSLERPtime)/viewer->transitionTime;
869 pos.x = viewer->Pos.x * tickFrac + (viewer->startSLERPPos.x * (1.0 - tickFrac));
870 pos.y = viewer->Pos.y * tickFrac + (viewer->startSLERPPos.y * (1.0 - tickFrac));
871 pos.z = viewer->Pos.z * tickFrac + (viewer->startSLERPPos.z * (1.0 - tickFrac));
873 antipos.x = viewer->AntiPos.x * tickFrac + (viewer->startSLERPAntiPos.x * (1.0 - tickFrac));
874 antipos.y = viewer->AntiPos.y * tickFrac + (viewer->startSLERPAntiPos.y * (1.0 - tickFrac));
875 antipos.z = viewer->AntiPos.z * tickFrac + (viewer->startSLERPAntiPos.z * (1.0 - tickFrac));
877 quaternion_slerp (&slerpedDiff,&viewer->startSLERPQuat,&viewer->Quat,tickFrac);
879 quaternion_togl(&slerpedDiff);
880 FW_GL_TRANSLATE_D(-pos.x, -pos.y, -pos.z);
881 FW_GL_TRANSLATE_D(antipos.x, antipos.y, antipos.z);
882 quaternion_slerp (&slerpedDiff,&viewer->startSLERPAntiQuat,&viewer->AntiQuat,tickFrac);
883 quaternion_togl(&slerpedDiff);
886 if (tickFrac >= 1.0) viewer->SLERPing = FALSE;
888 quaternion_togl(&viewer->Quat);
889 FW_GL_TRANSLATE_D(-(viewer->Pos).x, -(viewer->Pos).y, -(viewer->Pos).z);
890 FW_GL_TRANSLATE_D((viewer->AntiPos).x, (viewer->AntiPos).y, (viewer->AntiPos).z);
891 quaternion_togl(&viewer->AntiQuat);
895 getCurrentPosInModel(TRUE);
907 void getCurrentPosInModel (
int addInAntiPos) {
912 GLDOUBLE modelMatrix[16];
913 GLDOUBLE inverseMatrix[16];
930 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, modelMatrix);
941 matinverseAFFINE(inverseMatrix,modelMatrix);
953 tmppt.x = inverseMatrix[12];
954 tmppt.y = inverseMatrix[13];
955 tmppt.z = inverseMatrix[14];
961 quaternion_rotation(&rp, &viewer->bindTimeQuat, &tmppt);
964 viewer->currentPosInModel.x = viewer->AntiPos.x + rp.x;
965 viewer->currentPosInModel.y = viewer->AntiPos.y + rp.y;
966 viewer->currentPosInModel.z = viewer->AntiPos.z + rp.z;
970 if(0) quaternion_rotation(&rp, &viewer->bindTimeQuat, &tmppt);
971 if(1) {rp.x = tmppt.x; rp.y = tmppt.y; rp.z = tmppt.z;}
972 viewer->currentPosInModel.x = rp.x;
973 viewer->currentPosInModel.y = rp.y;
974 viewer->currentPosInModel.z = rp.z;
986 double quadratic(
double x,
double a,
double b,
double c)
989 return x*x*a + x*b + c;
991 double xsign_quadratic(
double x,
double a,
double b,
double c)
996 if(x < 0.0) xSign = -1.0;
else xSign = 1.0;
998 return xSign*quadratic(x,a,b,c);
1000 static void handle_walk(
const int mev,
const unsigned int button,
const float x,
const float y) {
1011 double frameRateAdjustment = 1.0;
1015 walk = &viewer->walk;
1017 if( tg->Mainloop.BrowserFPS > 0)
1018 frameRateAdjustment = 20.0 / tg->Mainloop.BrowserFPS;
1020 frameRateAdjustment = 1.0;
1023 if (mev == ButtonPress ) {
1026 }
else if (mev == MotionNotify) {
1037 walk->ZD = -xsign_quadratic(y - walk->SY,.05,5.0,0.0)*viewer->speed * frameRateAdjustment;
1038 walk->RD = xsign_quadratic(x - walk->SX,0.1,0.5,0.0)*frameRateAdjustment;
1041 }
else if (button == 3) {
1042 walk->XD = xsign_quadratic(x - walk->SX,5.0,10.0,0.0)*viewer->speed * frameRateAdjustment;
1043 walk->YD = xsign_quadratic(y - walk->SY,5.0,10.0,0.0)*viewer->speed * frameRateAdjustment;
1047 }
else if (mev == ButtonRelease) {
1051 }
else if (button == 3) {
1071 void handle_examine(
const int mev,
const unsigned int button,
float x,
float y) {
1080 examine = &viewer->examine;
1083 if (mev == ButtonPress) {
1094 xy2qua(&(examine->SQuat), x, y);
1095 quaternion_set(&(examine->OQuat), &(viewer->Quat));
1104 }
else if (button == 3) {
1106 examine->ODist = max(0.1,viewer->Dist);
1108 }
else if (mev == MotionNotify) {
1110 squat_norm = norm(&(examine->SQuat));
1112 if (APPROX(squat_norm, 0)) {
1113 fprintf(stderr,
"Viewer handle_examine: mouse event DRAG - missed press\n");
1115 xy2qua(&(examine->SQuat), x, y);
1117 quaternion_set(&(examine->OQuat), &(viewer->Quat));
1122 quaternion_inverse(&q_i, &(examine->SQuat));
1123 quaternion_multiply(&arc, &q, &q_i);
1127 quaternion_multiply(&(viewer->Quat), &arc, &(examine->OQuat));
1129 }
else if (button == 3) {
1131 viewer->Dist = examine->ODist * exp(examine->SY - y);
1133 viewer->Dist = (0 != y) ? examine->ODist * examine->SY / y : 0;
1138 quaternion_inverse(&q_i, &(viewer->Quat));
1139 quaternion_rotation(&(viewer->Pos), &q_i, &pp);
1143 viewer->Pos.x += (examine->Origin).x;
1144 viewer->Pos.y += (examine->Origin).y;
1145 viewer->Pos.z += (examine->Origin).z;
1151 double get_viewer_dist(){
1152 return Viewer()->Dist;
1155 void handle_dist(
const int mev,
const unsigned int button,
float x,
float y) {
1168 examine = &viewer->examine;
1174 if (mev == ButtonPress) {
1178 examine->ODist = max(0.1,viewer->Dist);
1180 }
else if (mev == MotionNotify) {
1183 viewer->Dist = examine->ODist * exp(2.0 * (examine->SY - yy));
1185 viewer->Dist = (0 != yy) ? examine->ODist * examine->SY / yy : 0;
1190 quaternion_inverse(&q_i, &(viewer->Quat));
1191 quaternion_rotation(&(viewer->Pos), &q_i, &pp);
1195 viewer->Pos.x += (examine->Origin).x;
1196 viewer->Pos.y += (examine->Origin).y;
1197 viewer->Pos.z += (examine->Origin).z;
1201 double display_screenRatio();
1202 void handle_turntable(
const int mev,
const unsigned int button,
float x,
float y) {
1207 double frameRateAdjustment;
1216 if(APPROX(viewer->Dist,0.0)){
1218 viewer->Dist = 10.0;
1221 if( tg->Mainloop.BrowserFPS > 0)
1222 frameRateAdjustment = 20.0 / tg->Mainloop.BrowserFPS;
1224 frameRateAdjustment = 1.0;
1227 if (mev == ButtonPress) {
1228 if (button == 1 || button == 3) {
1233 else if (mev == MotionNotify)
1236 double dyaw, dpitch;
1242 if (button == 1 || button == 3){
1244 yaxis.x = yaxis.z = 0.0;
1250 dd.x = dd.y = 0.0; dd.z = viewer->Dist;
1251 quat = viewer->Quat;
1252 quaternion_inverse(&quat,&quat);
1253 quaternion_rotation(&ddr, &quat, &dd);
1254 vecdiff(&viewer->examine.Origin,&viewer->Pos,&ddr);
1266 vecnormal(&pp, &pp);
1267 yaw = -atan2(pp.x, pp.z);
1268 pitch = -(acos(vecdot(&pp, &yaxis)) - PI*.5);
1271 dyaw = -(ypz->x - x) * viewer->fieldofview*PI / 180.0*viewer->fovZoom * display_screenRatio();
1272 dpitch = (ypz->y - y) * viewer->fieldofview*PI / 180.0*viewer->fovZoom;
1279 }
else if (button == 3) {
1284 d = (y - ypz->y)*.5;
1286 fac = ((d * 2.0) + (1.0 - d) * 1.0);
1290 fac = ((d * .5) + (1.0 - d) * 1.0);
1293 viewer->Dist *= fac;
1298 ypz->ypz[1] = -xsign_quadratic(y - ypz->y,100.0,10.0,0.0)*viewer->speed * frameRateAdjustment *.15;
1302 if (button == 1 || button == 3)
1304 vrmlrot_to_quaternion(&qyaw, 0.0, 1.0, 0.0, yaw);
1305 vrmlrot_to_quaternion(&qpitch, 1.0, 0.0, 0.0, pitch);
1306 quaternion_multiply(&quat, &qpitch, &qyaw);
1307 quaternion_normalize(&quat);
1309 quaternion_set(&(viewer->Quat), &quat);
1311 quaternion_inverse(&quat, &quat);
1314 pp.z = viewer->Dist;
1315 quaternion_rotation(&(viewer->Pos), &quat, &pp);
1317 vecadd(&viewer->Pos,&viewer->examine.Origin,&viewer->Pos);
1323 }
else if(mev == ButtonRelease) {
1331 void handle_spherical(
const int mev,
const unsigned int button,
float x,
float y) {
1345 if(ibutton == 1 && tg->Mainloop.CTRL) ibutton = 3;
1347 if (mev == ButtonPress) {
1348 if (ibutton == 1 || ibutton == 3) {
1352 }
else if (mev == MotionNotify) {
1359 yaxis.x = yaxis.z = 0.0;
1362 dd.x = dd.y = 0.0; dd.z = 1.0;
1363 quat = viewer->Quat;
1364 quaternion_inverse(&quat,&quat);
1365 quaternion_rotation(&ddr, &quat, &dd);
1366 yaw = -atan2(ddr.x,ddr.z);
1367 pitch = -(acos(vecdot(&ddr, &yaxis)) - PI*.5);
1370 dyaw = (ypz->x - x) * viewer->fieldofview*PI/180.0*viewer->fovZoom * display_screenRatio();
1371 dpitch = -(ypz->y - y) * viewer->fieldofview*PI/180.0*viewer->fovZoom;
1376 vrmlrot_to_quaternion(&qyaw, 0.0, 1.0, 0.0, yaw);
1377 vrmlrot_to_quaternion(&qpitch, 1.0, 0.0, 0.0, pitch);
1378 quaternion_multiply(&quat, &qpitch, &qyaw);
1379 quaternion_normalize(&quat);
1381 quaternion_set(&(viewer->Quat), &quat);
1383 }
else if (ibutton == 3) {
1385 d = -(y - ypz->y)*.5;
1387 viewer->fovZoom = viewer->fovZoom * fac;
1390 if(ibutton == 1 || ibutton == 3){
1407 void handle_fly2(
const int mev,
const unsigned int button,
float x,
float y) {
1418 inplane = &viewer->inplane;
1420 if (mev == ButtonPress) {
1426 }
else if (mev == MotionNotify) {
1429 }
else if (mev == ButtonRelease ) {
1437 void handle_tick_fly2(
double dtime) {
1441 double frameRateAdjustment, xx, yy, zz, rot;
1448 inplane = &viewer->inplane;
1450 if( tg->Mainloop.BrowserFPS > 0)
1451 frameRateAdjustment = 20.0 / tg->Mainloop.BrowserFPS;
1453 frameRateAdjustment = 1.0;
1456 xx = inplane->xx - inplane->x;
1457 yy = inplane->yy - inplane->y;
1458 zz = -xsign_quadratic(yy,.05,5.0,0.0)*viewer->speed * frameRateAdjustment;
1465 rot = xsign_quadratic(xx,0.1,0.5,0.0)*frameRateAdjustment;
1468 vrmlrot_to_quaternion (&nq,0.0,1.0,0.0,0.4*rot);
1469 viewer_lastQ_set(&nq);
1470 quaternion_multiply(&(viewer->Quat), &nq, &q);
1472 increment_pos(&xyz);
1480 void handle_lookat(
const int mev,
const unsigned int button,
float x,
float y) {
1494 viewer->LookatMode = 2;
1504 if(viewer->type == VIEWER_LOOKAT)
1505 fwl_set_viewer_type(VIEWER_LOOKAT);
1506 if(viewer->type == VIEWER_EXPLORE)
1507 fwl_set_viewer_type(VIEWER_EXPLORE);
1508 viewer->LookatMode = 0;
1514 void handle_tick_lookat() {
1522 switch(viewer->LookatMode){
1532 void handle_explore(
const int mev,
const unsigned int button,
float x,
float y) {
1545 ctrl = tg->Mainloop.CTRL;
1550 handle_lookat(mev,button,x,y);
1553 if(APPROX(viewer->Dist,0.0)){
1555 handle_spherical(mev,button,x,y);
1558 handle_turntable(mev, button, x, y);
1561 void handle_tplane(
const int mev,
const unsigned int button,
float x,
float y) {
1575 inplane = &viewer->inplane;
1582 if (mev == ButtonPress) {
1586 }
else if (mev == MotionNotify) {
1589 }
else if(mev == ButtonRelease){
1595 void handle_tick_tplane(
double dtime){
1606 inplane = &viewer->inplane;
1609 pp.x = xsign_quadratic(inplane->xx - inplane->x,300.0,100.0,0.0) *dtime;
1610 pp.y = xsign_quadratic(inplane->yy - inplane->y,300.0,100.0,0.0) *dtime;
1612 pp.x = xsign_quadratic(inplane->xx - inplane->x,3.0,1.0,0.0)*max(1.0,viewer->Dist) * dtime;
1613 pp.y = xsign_quadratic(inplane->yy - inplane->y,3.0,1.0,0.0)*max(1.0,viewer->Dist) * dtime;
1621 void handle_rtplane(
const int mev,
const unsigned int button,
float x,
float y) {
1630 double xx,yy, frameRateAdjustment;
1635 inplane = &viewer->inplane;
1637 if( tg->Mainloop.BrowserFPS > 0)
1638 frameRateAdjustment = 20.0 / tg->Mainloop.BrowserFPS;
1640 frameRateAdjustment = 1.0;
1642 if (mev == ButtonPress) {
1645 }
else if (mev == MotionNotify) {
1648 double drot = atan2(yy,xx) - atan2(inplane->y,inplane->x);
1650 quaternion_set(&q_v, &(viewer->Quat));
1651 vrmlrot_to_quaternion(&nq, 0.0, 0.0, 1.0, drot);
1652 quaternion_multiply(&(viewer->Quat), &nq, &q_v);
1659 inplane->xx = xsign_quadratic(x - inplane->x,0.1,0.5,0.0)*frameRateAdjustment;
1660 inplane->yy = xsign_quadratic(y - inplane->y,0.1,0.5,0.0)*frameRateAdjustment;
1663 }
else if (mev == ButtonRelease) {
1671 void handle_tick_rplane(
double dtime){
1683 inplane = &viewer->inplane;
1685 roll = xsign_quadratic(inplane->xx - inplane->x,2.0,2.0,0.0)*dtime;
1686 vrmlrot_to_quaternion (&quatr,0.0,0.0,1.0,roll);
1687 quaternion_multiply(&(viewer->Quat), &quatr, &(viewer->Quat));
1688 quaternion_normalize(&(viewer->Quat));
1692 void handle_tick_tilt(
double dtime) {
1704 inplane = &viewer->inplane;
1706 yaw = xsign_quadratic(inplane->xx - inplane->x,2.0,2.0,0.0)*dtime;
1707 vrmlrot_to_quaternion (&quatt,0.0,1.0,0.0,yaw);
1708 quaternion_multiply(&(viewer->Quat), &quatt, &(viewer->Quat));
1709 pitch = -xsign_quadratic(inplane->yy - inplane->y,2.0,2.0,0.0)*dtime;
1710 vrmlrot_to_quaternion (&quatt,1.0,0.0,0.0,pitch);
1711 quaternion_multiply(&(viewer->Quat), &quatt, &(viewer->Quat));
1712 quaternion_normalize(&(viewer->Quat));
1719 void handle0(
const int mev,
const unsigned int button,
const float x,
const float yup)
1730 switch(viewer->type) {
1733 case VIEWER_EXAMINE:
1734 handle_examine(mev, button, ((
float) x), ((
float) yup));
1737 handle_walk(mev, button, ((
float) x), ((
float) yup));
1742 handle_fly2(mev, button, ((
float) x), ((
float) yup));
1745 handle_fly2(mev,button,((
float) x),((
float)yup));
1749 handle_rtplane(mev,button,((
float) x),((
float)yup));
1752 handle_tplane(mev,button,((
float) x),((
float)yup));
1754 case VIEWER_SPHERICAL:
1755 handle_spherical(mev,button,((
float) x),((
float)yup));
1757 case VIEWER_TURNTABLE:
1758 handle_turntable(mev, button, ((
float)x), ((
float)yup));
1761 handle_lookat(mev, button, ((
float)x), ((
float)yup));
1763 case VIEWER_EXPLORE:
1764 handle_explore(mev, button, ((
float)x), ((
float)yup));
1767 handle_dist(mev,button,(
float)x,(
float)yup);
1773 #define FLYREMAP {{'a',NUM0},{'z',NUMDEC},{'j',LEFT_KEY},{'l',RIGHT_KEY},{'p',UP_KEY},{';',DOWN_KEY},{'8',NUM8},{'k',NUM2},{'u',NUM4},{'o',NUM6 },{'7',NUM7},{'9',NUM9}}
1779 Key FLYREMAP2 [] = {{
'a',NUM0},{
'z',NUMDEC},{
'j',LEFT_KEY},{
'l',RIGHT_KEY},{
'p',UP_KEY},{
';',DOWN_KEY},{
'8',NUM8},{
'k',NUM2},{
'u',NUM4},{
'o',NUM6 },{
'7',NUM7},{
'9',NUM9}};
1780 int FLYREMAP2SIZE = 12;
1781 Key FLYCHORDREMAP [] = {
1782 {
'j',LEFT_KEY},{
'l',RIGHT_KEY},{
'p',UP_KEY},{
';',DOWN_KEY}
1784 int arrowkeys [] = {LEFT_KEY,RIGHT_KEY,UP_KEY,DOWN_KEY};
1792 int indexArrowkey(
int key){
1796 if(key == arrowkeys[i]) iret = i;
1812 FLY_ROLL_COUNTERCLOCKWISE,
1815 Key fly_normalkeys [] = {
1820 {
'a',FLY_Z_FORWARD},
1821 {
'z',FLY_Z_REVERSE},
1823 {
'8',FLY_PITCH_DOWN},
1825 {
'o',FLY_YAW_RIGHT},
1826 {
'7',FLY_ROLL_COUNTERCLOCKWISE},
1827 {
'9',FLY_ROLL_CLOCKWISE},
1836 char *chordnames [] = {
"YAWZ",
"YAWPITCH",
"ROLL",
"XY"};
1843 {CHORD_YAWZ, {{FLY_YAW_LEFT,LEFT_KEY},{FLY_YAW_RIGHT,RIGHT_KEY},{FLY_Z_FORWARD,UP_KEY},{FLY_Z_REVERSE,DOWN_KEY}}},
1844 {CHORD_YAWPITCH,{{FLY_YAW_LEFT,LEFT_KEY},{FLY_YAW_RIGHT,RIGHT_KEY},{FLY_PITCH_UP,UP_KEY},{FLY_PITCH_DOWN,DOWN_KEY}}},
1845 {CHORD_ROLL, {{FLY_ROLL_COUNTERCLOCKWISE,LEFT_KEY},{FLY_ROLL_CLOCKWISE,RIGHT_KEY},{FLY_ROLL_COUNTERCLOCKWISE,UP_KEY},{FLY_ROLL_CLOCKWISE,DOWN_KEY}}},
1846 {CHORD_XY, {{FLY_X_LEFT,LEFT_KEY},{FLY_X_RIGHT,RIGHT_KEY},{FLY_Y_UP,UP_KEY},{FLY_Y_DOWN,DOWN_KEY}}},
1849 int viewer_getKeyChord(){
1853 void viewer_setKeyChord(
int chord){
1857 if(chord1 > 3) chord1 = 0;
1858 if(chord1 < 0) chord1 = 3;
1859 p->keychord = chord1;
1861 char *fwl_getKeyChord(){
1862 return chordnames[viewer_getKeyChord()];
1865 int fwl_setKeyChord(
char *chordname){
1869 if(!strcasecmp(chordname,chordnames[i])){
1870 viewer_setKeyChord(i);
1877 int viewer_getDragChord(){
1879 return p->dragchord;
1881 void viewer_setDragChord(
int chord){
1883 p->dragchord = chord;
1885 void viewer_setNextDragChord(){
1887 p->dragchord = p->dragchord == CHORD_XY ? CHORD_YAWZ : p->dragchord + 1;
1889 char *fwl_getDragChord(){
1890 return chordnames[viewer_getDragChord()];
1892 int fwl_setDragChord(
char *chordname){
1896 if(!strcasecmp(chordname,chordnames[i])){
1897 viewer_setDragChord(i);
1907 int lookup_fly_arrow(
int key){
1911 int idxarrow, idxnormal;
1913 idxarrow = indexArrowkey(key);
1916 idxnormal = FLYCHORDREMAP2[p->keychord].arrows[idxarrow].key;
1918 iret = fly_normalkeys[idxnormal].key;
1923 char lookup_fly_extended(
int key){
1926 Key ps[KEYS_HANDLED] = FLYREMAP;
1927 for(i=0;i<KEYS_HANDLED;i++){
1935 char lookup_fly_key(
int key){
1938 kp = lookup_fly_arrow(key);
1940 kp = lookup_fly_extended(key);
1943 static struct flykey_lookup_type {
1949 } flykey_lookup [] = {
1950 {
'j', 0, 0, -1, FLY_X_LEFT},
1951 {
'l', 0, 0, 1, FLY_X_RIGHT},
1952 {
';', 0, 1, -1, FLY_Y_DOWN},
1953 {
'p', 0, 1, 1, FLY_Y_UP,},
1954 {
'a', 0, 2, -1, FLY_Z_FORWARD},
1955 {
'z', 0, 2, 1, FLY_Z_REVERSE},
1957 {
'k', 1, 0, -1, FLY_YAW_LEFT},
1958 {
'8', 1, 0, 1, FLY_YAW_RIGHT},
1959 {
'u', 1, 1, -1, FLY_PITCH_UP},
1960 {
'o', 1, 1, 1, FLY_PITCH_DOWN},
1961 {
'7', 1, 2, -1, FLY_ROLL_COUNTERCLOCKWISE},
1962 {
'9', 1, 2, 1, FLY_ROLL_CLOCKWISE}
1966 struct flykey_lookup_type *getFlyIndex(
char key){
1967 struct flykey_lookup_type *flykey;
1970 for(index=0;index<KEYS_HANDLED;index++){
1971 if(key == flykey_lookup[index].key )
break;
1974 flykey = &flykey_lookup[index];
1977 int isFlyKey(
char key){
1979 index = indexArrowkey(key);
1981 for(i=0;i<KEYS_HANDLED;i++)
1982 if(key == flykey_lookup[i].key ){
1986 return index > -1 ? 1 : 0;
1988 void handle_key(
const char key,
double keytime)
1994 struct flykey_lookup_type *flykey;
2002 _key = (char) tolower((
int) key);
2003 if(!isFlyKey(_key)){
2008 flykey = getFlyIndex(_key);
2010 if(flykey->motion > -1 && flykey->motion < 2 && flykey->axis > -1 && flykey->axis < 3){
2011 fly->down[flykey->motion][flykey->axis].direction = flykey->sign;
2012 fly->down[flykey->motion][flykey->axis].epoch = keytime;
2013 fly->down[flykey->motion][flykey->axis].era = keytime;
2014 fly->down[flykey->motion][flykey->axis].once = 1;
2021 void handle_keyrelease(
const char key,
double keytime)
2027 struct flykey_lookup_type *flykey;
2036 _key = (char) tolower((
int) key);
2037 if(!isFlyKey(_key))
return;
2038 flykey = getFlyIndex(_key);
2040 if(flykey->motion > -1 && flykey->motion < 2 && flykey->axis > -1 && flykey->axis < 3){
2041 int *ndown = &fly->ndown[flykey->motion][flykey->axis];
2044 fly->wasDown[flykey->motion][flykey->axis][*ndown].direction = fly->down[flykey->motion][flykey->axis].direction;
2045 fly->wasDown[flykey->motion][flykey->axis][*ndown].epoch = keytime - fly->down[flykey->motion][flykey->axis].epoch;
2046 fly->wasDown[flykey->motion][flykey->axis][*ndown].era = keytime - fly->down[flykey->motion][flykey->axis].era;
2047 fly->wasDown[flykey->motion][flykey->axis][*ndown].once = fly->down[flykey->motion][flykey->axis].once;
2050 fly->down[flykey->motion][flykey->axis].direction = 0;
2063 void viewer_lastP_clear()
2067 p->viewer_lastP.x = p->viewer_lastP.y = p->viewer_lastP.z = 0.0;
2072 quaternion_rotation(&p->viewer_lastP,lastQ,&p->viewer_lastP);
2074 void viewer_lastP_add(
struct point_XYZ *vec)
2079 VECADD(p->viewer_lastP,*vec);
2082 viewer_lastP_clear();
2091 vecscale(&nv,&nv,-1.0);
2112 static void handle_tick_walk()
2120 walk = &viewer->walk;
2123 pp.x = 0.15 * walk->XD;
2124 pp.y = 0.15 * walk->YD;
2125 pp.z = 0.15 * walk->ZD;
2173 q.w = (viewer->Quat).w;
2174 q.x = (viewer->Quat).x;
2175 q.y = (viewer->Quat).y;
2176 q.z = (viewer->Quat).z;
2177 vrmlrot_to_quaternion (&nq,0.0,1.0,0.0,0.4*walk->RD);
2181 viewer_lastQ_set(&nq);
2186 quaternion_multiply(&(viewer->Quat), &q, &nq);
2187 quaternion_normalize(&(viewer->Quat));
2191 struct point_XYZ rotaxis = {0.0, 1.0, 0.0};
2193 struct point_XYZ down = {0.0, -1.0, 0.0};
2196 quaternion_rotation(&tilted,&q,&down);
2197 angle = vecangle2(&down,&tilted, &rotaxis);
2198 vrmlrot_to_quaternion (&qlevel,rotaxis.x,rotaxis.y,rotaxis.z,-angle);
2200 quaternion_multiply(&qplanar,&qlevel,&q);
2213 viewer_lastP_add(&vec);
2217 quaternion_inverse(&q_i, &qplanar);
2218 quaternion_rotation(&nv, &q_i, &vec);
2221 viewer->VPvelocity.x = nv.x; viewer->VPvelocity.y = nv.y; viewer->VPvelocity.z = nv.z;
2223 viewer->Pos.x += nv.x;
2224 viewer->Pos.y += nv.y;
2225 viewer->Pos.z += nv.z;
2242 static int negate_pos = TRUE;
2243 void viewer_setpose(
double *quat4,
double *vec3){
2254 if(negate_pos) vecnegated(vec,vec);
2255 double2pointxyz(&viewer->Pos,vec);
2256 double2quat(&viewer->Quat,quat4);
2258 void viewer_getpose(
double *quat4,
double *vec3){
2268 pointxyz2double(vec3,&viewer->Pos);
2270 vecnegated(vec3,vec3);
2271 quat2double(quat4,&viewer->Quat);
2273 void viewer_getbindpose(
double *quat4,
double *vec3){
2284 pointxyz2double(vec3,&viewer->AntiPos);
2286 vecnegated(vec3,vec3);
2287 quaternion_inverse(&q_i,&viewer->AntiQuat);
2288 quat2double(quat4,&q_i);
2290 void viewer_getview(
double *viewMatrix){
2295 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, viewMatrix);
2300 void viewer_setview(
double *viewMatrix){
2301 FW_GL_SETDOUBLEV(GL_MODELVIEW_MATRIX, viewMatrix);
2332 char string[STRING_SIZE];
2333 float px,py,pz,q1,q2,q3,q4;
2340 memset(
string, 0, STRING_SIZE *
sizeof(
char));
2354 if ((p->exfly_in_file = fopen(IN_FILE,
"r")) == NULL) {
2356 "Viewer handle_tick_exfly: could not open %s for read, returning to EXAMINE mode.\nSee the FreeWRL man page for further details on the usage of Fly - External Sensor input mode.\n",
2360 viewer->type = VIEWER_EXAMINE;
2364 rv = fread(
string,
sizeof(
char), IN_FILE_BYTES, p->exfly_in_file);
2365 if (ferror(p->exfly_in_file)) {
2367 "Viewer handle_tick_exfly: error reading from file %s.",
2369 fclose(p->exfly_in_file);
2372 fclose(p->exfly_in_file);
2375 if ((len = strlen(
string)) > 0) {
2376 if(p->exflyMethod == 0)
2379 len = sscanf (
string,
"%f %f %f %f %f %f %f",&px,&py,&pz,
2383 if (len != 7)
return;
2385 (viewer->Pos).x = px;
2386 (viewer->Pos).y = py;
2387 (viewer->Pos).z = pz;
2389 (viewer->Quat).w = q1;
2390 (viewer->Quat).x = q2;
2391 (viewer->Quat).y = q3;
2392 (viewer->Quat).z = q4;
2393 }
else if(p->exflyMethod == 1){
2395 static int lastbut = 0;
2397 len = sscanf (
string,
"%d %f %f ",&but,&px,&py);
2398 if (len != 3)
return;
2399 mev = ButtonRelease;
2400 if(but) mev = MotionNotify;
2403 mev = (but==1 || but==4)? ButtonPress : ButtonRelease;
2408 handle_walk(mev,but,px,py);
2429 static void handle_tick_fly()
2435 double changed = 0.0, time_diff = -1.0;
2443 if (fly->lasttime < 0) {
2444 fly->lasttime = TickTime();
2447 double dtime = TickTime();
2448 time_diff = dtime - fly->lasttime;
2449 if (APPROX(time_diff, 0)) {
2452 fly->lasttime = dtime;
2453 if(time_diff < 0.0)
return;
2460 for (i = 0; i < 3; i++) {
2462 if(!fly->down[0][i].direction){
2463 double dtime = fly->lasttime - fly->down[0][i].epoch;
2465 fly->Velocity[0][i] *= pow(0.04, time_diff);
2468 if(fabs(fly->Velocity[0][i]) < .001){
2469 fly->Velocity[0][i] = 0.0;
2472 if(fly->down[0][i].direction){
2474 fly->Velocity[0][i] += (fly->ndown[0][i]+fly->down[0][i].once)*fly->down[0][i].direction * viewer->speed * .1 * max(viewer->Dist,1.0);
2475 fly->down[0][i].once = 0;
2476 fly->ndown[0][i] = 0;
2479 changed += fly->Velocity[0][i];
2483 if (viewer->GeoSpatialNode == NULL)
2484 if(0)
for (i = 0; i < 3; i++) {
2485 if (fabs(fly->Velocity[0][i]) >9.0)
2486 fly->Velocity[0][i] /= (fabs(fly->Velocity[0][i]) /9.0);
2499 for (i = 0; i < 3; i++) {
2500 static double radians_per_second = .6;
2501 fly->Velocity[1][i] = 0.0;
2502 if(!fly->down[1][i].direction){
2503 fly->Velocity[1][i] *= pow(0.04, time_diff);
2506 double rps = radians_per_second;
2509 double era = fly->lasttime - fly->down[1][i].era;
2510 fly->Velocity[1][i] += era * fly->down[1][i].direction * rps;
2511 fly->down[1][i].era += era;
2514 if(fly->ndown[1][i]){
2517 double rps = radians_per_second * .33;
2518 for(k=0; k<fly->ndown[1][i]; k++){
2519 double era = fly->wasDown[1][i][k].era;
2520 double pressedEra = fly->wasDown[1][i][k].epoch;
2522 if(pressedEra <= .1)
2525 fly->Velocity[1][i] += era * fly->wasDown[1][i][k].direction * rps;
2527 fly->ndown[1][i] = 0;
2529 if (fabs(fly->Velocity[1][i]) > 0.8) {
2530 fly->Velocity[1][i] /= (fabs(fly->Velocity[1][i]) / 0.8);
2532 changed += fly->Velocity[1][i];
2537 if (APPROX(changed,0.0))
return;
2538 v.x = fly->Velocity[0][0] * time_diff;
2539 v.y = fly->Velocity[0][1] * time_diff;
2540 v.z = fly->Velocity[0][2] * time_diff;
2543 nq.x = fly->Velocity[1][0];
2544 nq.y = fly->Velocity[1][1];
2545 nq.z = fly->Velocity[1][2];
2546 quaternion_normalize(&nq);
2548 quaternion_set(&q_v, &(viewer->Quat));
2549 quaternion_multiply(&(viewer->Quat), &nq, &q_v);
2550 quaternion_normalize(&(viewer->Quat));
2561 double lasttime, dtime, time_diff;
2564 lasttime = viewer->lasttime;
2569 viewer->lasttime = TickTime();
2573 time_diff = dtime - viewer->lasttime;
2574 if (APPROX(time_diff, 0)) {
2577 viewer->lasttime = dtime;
2578 if(time_diff < 0.0)
return;
2581 switch(viewer->type) {
2584 case VIEWER_EXAMINE:
2590 handle_tick_exfly();
2593 switch(p->dragchord){
2594 case CHORD_YAWPITCH:
2595 handle_tick_tilt(time_diff);
2598 handle_tick_rplane(time_diff);
2601 handle_tick_tplane(time_diff);
2605 handle_tick_fly2(time_diff);
2610 handle_tick_fly2(time_diff);
2613 handle_tick_lookat();
2616 handle_tick_tplane(dtime);
2619 handle_tick_rplane(dtime);
2622 handle_tick_tilt(dtime);
2624 case VIEWER_EXPLORE:
2626 case VIEWER_SPHERICAL:
2629 case VIEWER_TURNTABLE:
2636 if(viewer->type != VIEWER_NONE){
2639 if (viewer->doExamineModeDistanceCalculations) {
2643 CALCULATE_EXAMINE_DISTANCE
2645 p->examineCounter --;
2647 if (p->examineCounter < 0) {
2648 viewer->doExamineModeDistanceCalculations = FALSE;
2649 p->examineCounter = 5;
2666 xy2qua(
Quaternion *ret,
const double x,
const double y)
2668 double _x = x - 0.5, _y = y - 0.5, _z, dist;
2672 dist = sqrt((_x * _x) + (_y * _y));
2685 quaternion_normalize(ret);
2691 void setmask(GLboolean *mask,
int r,
int g,
int b)
2693 mask[0] = (GLboolean)r;
2694 mask[1] = (GLboolean)g;
2695 mask[2] = (GLboolean)b;
2697 void Viewer_anaglyph_setSide(
int iside)
2703 glColorMask(p->acMask[iside][0],p->acMask[iside][1],p->acMask[iside][2],t);
2705 void Viewer_anaglyph_clearSides()
2707 glColorMask(1,1,1,1);
2710 static char * RGBACM =
"RGBACM";
2711 static int indexRGBACM(
int a)
2713 return (
int) (strchr(RGBACM,a)-RGBACM);
2715 int getAnaglyphPrimarySide(
int primary,
int iside){
2719 return (
int)p->acMask[iside][primary];
2722 void setAnaglyphPrimarySide(
int primary,
int iside){
2737 p->acMask[i][primary] = (GLboolean)1;
2739 p->acMask[i][primary] = (GLboolean)0;
2741 void setAnaglyphSideColor(
char val,
int iside)
2746 viewer->iprog[iside] = indexRGBACM(val);
2747 if(viewer->iprog[iside] == -1 )
2749 printf (
"warning, command line anaglyph parameter incorrect - was %c need something like RG\n",val);
2750 viewer->iprog[iside] = iside;
2753 switch (viewer->iprog[iside]) {
2755 setmask(p->acMask[iside],1,0,0);
2758 setmask(p->acMask[iside],0,1,0);
2761 setmask(p->acMask[iside],0,0,1);
2764 setmask(p->acMask[iside],1,1,0);
2767 setmask(p->acMask[iside],0,1,1);
2770 setmask(p->acMask[iside],1,0,1);
2774 void fwl_set_AnaglyphParameter(
const char *optArg) {
2779 const char* glasses;
2785 len = (int) strlen(optArg);
2786 if(len !=2 && len != 3)
2788 printf (
"warning, command line anaglyph parameter incorrect - was %s need something like RC or LRN\n",optArg);
2789 glasses =
"RC"; len = 2;
2792 setAnaglyphSideColor(glasses[0],0);
2793 setAnaglyphSideColor(glasses[1],1);
2798 case 'L': iside = 0;
break;
2799 case 'R': iside = 1;
break;
2800 case 'N': iside = 2;
break;
2804 setAnaglyphPrimarySide(i,iside);
2815 viewer->anaglyph = 1;
2816 viewer->shutterGlasses = 0;
2817 viewer->sidebyside = 0;
2819 viewer->isStereo = 1;
2820 setStereoBufferStyle(1);
2824 void fwl_init_Shutter (
void)
2836 tg->display.shutterGlasses = 2;
2837 viewer->shutterGlasses = 2;
2838 setStereoBufferStyle(1);
2839 if(viewer->haveQuadbuffer)
2841 tg->display.shutterGlasses = 1;
2842 viewer->shutterGlasses = 1;
2843 setStereoBufferStyle(0);
2845 viewer->isStereo = 1;
2849 void fwl_init_SideBySide()
2855 setStereoBufferStyle(1);
2856 viewer->isStereo = 1;
2857 viewer->sidebyside = 1;
2858 viewer->screendist = min(viewer->screendist,.375);
2859 viewer->stereoParameter = min(viewer->stereoParameter,.01);
2861 void fwl_init_UpDown()
2867 setStereoBufferStyle(1);
2868 viewer->isStereo = 1;
2870 viewer->screendist = min(viewer->screendist,.375);
2871 viewer->stereoParameter = min(viewer->stereoParameter,.01);
2874 void clear_shader_table();
2882 viewer->anaglyph = 1;
2883 viewer->isStereo = 1;
2884 clear_shader_table();
2885 setStereoBufferStyle(1);
2895 viewer->isStereo = 0;
2896 if(viewer->anaglyph)
2898 glColorMask(1,1,1,1);
2899 clear_shader_table();
2901 viewer->anaglyph = 0;
2902 viewer->sidebyside = 0;
2904 viewer->shutterGlasses = 0;
2905 tg->display.shutterGlasses = 0;
2917 static void setStereo(
int type)
2922 gglobal()->Viewer.stereotype = type;
2926 case VIEWER_STEREO_OFF: {;
break;}
2927 case VIEWER_STEREO_SHUTTERGLASSES: {fwl_init_Shutter();
break;}
2928 case VIEWER_STEREO_SIDEBYSIDE: {fwl_init_SideBySide();
break;}
2929 case VIEWER_STEREO_ANAGLYPH: {setAnaglyph();
break;}
2930 case VIEWER_STEREO_UPDOWN: {fwl_init_UpDown();
break;}
2934 void toggleOrSetStereo(
int type)
2943 shut = viewer->shutterGlasses ? 1 : 0;
2944 curtype = viewer->isStereo*( (shut)*1 + viewer->sidebyside*2 + viewer->anaglyph*3 + viewer->updown*4);
2945 if(type != curtype) {
2949 gglobal()->Viewer.stereotype = 0;
2953 void fwl_setPickraySide(
int ipreferredSide,
int either){
2957 viewer->dominantEye = ipreferredSide;
2958 viewer->eitherDominantEye = either;
2961 void fwl_getPickraySide(
int *ipreferredSide,
int *either){
2965 *ipreferredSide = viewer->dominantEye ;
2966 *either = viewer->eitherDominantEye;
2968 void updateEyehalf()
2973 if( viewer->screendist != 0.0)
2995 set_eyehalf( viewer->eyedist/2.0,atan(viewer->stereoParameter)*180.0/3.1415926);
2999 void viewer_postGLinit_init(
void)
3009 rdr_caps = tg->display.rdr_caps;
3012 viewer->haveQuadbuffer = (rdr_caps->quadBuffer== GL_TRUE);
3018 type = VIEWER_STEREO_OFF;
3019 if( viewer->shutterGlasses ) type = VIEWER_STEREO_SHUTTERGLASSES;
3020 if( viewer->sidebyside ) type = VIEWER_STEREO_SIDEBYSIDE;
3021 if( viewer->updown ) type = VIEWER_STEREO_UPDOWN;
3022 if( viewer->anaglyph ==1 ) type = VIEWER_STEREO_ANAGLYPH;
3024 if(type==VIEWER_STEREO_SHUTTERGLASSES)
3028 if (!viewer->haveQuadbuffer ) {
3029 ConsoleMessage(
"Unable to get quadbuffer stereo visual, switching to flutter mode\n");
3041 void fwl_set_StereoParameter (
const char *optArg) {
3051 i = sscanf(optArg,
"%lf",&viewer->stereoParameter);
3052 if (i==0) printf (
"warning, command line stereo parameter incorrect - was %s\n",optArg);
3053 else updateEyehalf();
3056 void fwl_set_EyeDist (
const char *optArg) {
3064 i= sscanf(optArg,
"%lf",&viewer->eyedist);
3065 if (i==0) printf (
"warning, command line eyedist parameter incorrect - was %s\n",optArg);
3066 else updateEyehalf();
3069 void fwl_set_ScreenDist (
const char *optArg) {
3077 i= sscanf(optArg,
"%lf",&viewer->screendist);
3078 if (i==0) printf (
"warning, command line screendist parameter incorrect - was %s\n",optArg);
3079 else updateEyehalf();
3083 void set_stereo_offset0()
3085 double x = 0.0, angle = 0.0;
3090 if (viewer->iside == 0) {
3092 x = viewer->eyehalf;
3093 angle = viewer->eyehalfangle;
3094 }
else if (viewer->iside == 1) {
3096 x = -viewer->eyehalf;
3097 angle = -viewer->eyehalfangle;
3099 FW_GL_TRANSLATE_D(x, 0.0, 0.0);
3100 FW_GL_ROTATE_D(angle, 0.0, 1.0, 0.0);
3104 void increment_pos(
struct point_XYZ *vec) {
3111 viewer_lastP_add(vec);
3114 quaternion_inverse(&q_i, &(viewer->Quat));
3115 quaternion_rotation(&nv, &q_i, vec);
3118 viewer->VPvelocity.x = nv.x; viewer->VPvelocity.y = nv.y; viewer->VPvelocity.z = nv.z;
3120 viewer->Pos.x += nv.x;
3121 viewer->Pos.y += nv.y;
3122 viewer->Pos.z += nv.z;
3138 viewer = ViewerByLayerId(vp->_layerId);
3142 if (!(vp->isBound))
return;
3153 if (vp->fieldOfView.n == 4) {
3156 viewer->orthoField[0] = (double) vp->fieldOfView.p[0];
3157 viewer->orthoField[1] = (
double) vp->fieldOfView.p[1];
3158 viewer->orthoField[2] = (double) vp->fieldOfView.p[2];
3159 viewer->orthoField[3] = (
double) vp->fieldOfView.p[3];
3161 ERROR_MSG(
"OrthoViewpoint - fieldOfView must have 4 parameters");
3162 viewer->orthoField[0] = -1.0;
3163 viewer->orthoField[1] = -1.0;
3164 viewer->orthoField[2] = 1.0;
3165 viewer->orthoField[3] = 1.0;
3171 viewer->GeoSpatialNode = NULL;
3174 INITIATE_ROTATION_ORIGIN
3214 INITIATE_POSITION_ANTIPOSITION
3218 viewer_lastP_clear();
3220 setMenuStatusVP (vp->description->strptr);
3225 int slerp_viewpoint(
int itype)
3233 if(viewer->SLERPing3 && itype==3){
3237 tickFrac = (TickTime() - viewer->startSLERPtime)/viewer->transitionTime;
3238 tickFrac = min(1.0,tickFrac);
3239 quaternion_slerp(&viewer->Quat,&viewer->startSLERPQuat,&viewer->endSLERPQuat,tickFrac);
3240 point_XYZ_slerp(&viewer->Pos,&viewer->startSLERPPos,&viewer->endSLERPPos,tickFrac);
3241 general_slerp(&viewer->Dist,&viewer->startSLERPDist,&viewer->endSLERPDist,1,tickFrac);
3242 if(tickFrac >= 1.0) {
3243 viewer->SLERPing3 = 0;
3248 }
else if(viewer->SLERPing2 && p->vp2rnSaved && itype==2) {
3250 if(viewer->SLERPing2justStarted)
3255 double vpn2rn[16],rn2vpn[16];
3258 memcpy(vpo2rn,p->viewpoint2rootnode,
sizeof(
double)*16);
3259 if(viewer->LookatMode==3){
3260 memcpy(vpn2rn,p->viewpointnew2rootnode,
sizeof(
double)*16);
3262 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, p->viewpoint2rootnode);
3263 memcpy(vpn2rn,p->viewpoint2rootnode,
sizeof(
double)*16);
3266 matinverseAFFINE(rn2vpn,vpn2rn);
3271 matmultiplyAFFINE(diffrn,vpo2rn,rn2vpn);
3277 matrix_to_quaternion(&p->sq,diffrn);
3278 quaternion_normalize(&p->sq);
3279 p->sp[0] = diffrn[12];
3280 p->sp[1] = diffrn[13];
3281 p->sp[2] = diffrn[14];
3283 viewer->SLERPing2justStarted = FALSE;
3291 double vzero[3], vshift[3];
3293 tickFrac = (TickTime() - viewer->startSLERPtime)/viewer->transitionTime;
3299 tickFrac = DOUBLE_MIN(tickFrac,1.0);
3300 tickFrac = DOUBLE_MAX(tickFrac,0.0);
3303 vzero[0] = vzero[1] = vzero[2] = 0.0;
3304 vrmlrot_to_quaternion(&qzero, 0.0,1.0,0.0,0.0);
3305 quaternion_slerp(&qdif,&p->sq,&qzero,tickFrac);
3306 general_slerp(vshift,p->sp,vzero,3,tickFrac);
3308 FW_GL_TRANSLATE_D(vshift[0],vshift[1],vshift[2]);
3309 quaternion_togl(&qdif);
3313 viewer->SLERPing2 = FALSE;
3321 void setup_viewpoint_slerp(
double* center,
double pivot_radius,
double vp_radius){
3339 double pos[3] = {0.0,0.0,0.0};
3343 veccopyd(pos,center);
3348 vecnormald(pos,pos);
3349 vecscaled(pos,pos,vp_radius);
3352 viewer->SLERPing3 = 1;
3361 viewer->startSLERPPos = viewer->Pos;
3362 viewer->startSLERPQuat = viewer->Quat;
3363 viewer->startSLERPDist = viewer->Dist;
3364 viewer->startSLERPtime = TickTime();
3379 viewer->endSLERPDist = vp_radius;
3383 quaternion_normalize(&viewer->startSLERPQuat);
3384 quaternion_inverse( &q_i,&viewer->startSLERPQuat);
3385 vecdifd(pos,center,pos);
3386 double2pointxyz(&pp,pos);
3387 quaternion_rotation(&qq, &q_i, &pp);
3388 vecadd(&viewer->endSLERPPos,&viewer->startSLERPPos,&qq);
3396 if( APPROX( vecnormald(C,C), 0.0) )
3400 vecscaled(C,C,-1.0);
3401 yaw = -atan2(C[0],C[2]);
3403 vrmlrot_to_quaternion(&qyaw, 0.0,1.0,0.0,yaw);
3404 double2pointxyz(&PC,C);
3405 quaternion_rotation(&PC,&qyaw,&PC);
3407 pitch = atan2(PC.y,PC.z);
3408 vrmlrot_to_quaternion(&qpitch,1.0,0.0,0.0,pitch);
3410 quaternion_multiply(&qtmp,&qyaw,&qpitch);
3411 quaternion_multiply(&viewer->endSLERPQuat,&qtmp,&viewer->startSLERPQuat);
3432 if (!(vp->isBound))
return;
3581 viewer = ViewerByLayerId(vp->_layerId);
3582 if (viewer->transitionType != VIEWER_TRANSITION_TELEPORT && viewer->wasBound) {
3583 viewer->SLERPing = FALSE;
3584 viewer->startSLERPtime = TickTime();
3585 memcpy (&viewer->startSLERPPos, &viewer->Pos, sizeof (
struct point_XYZ));
3586 memcpy (&viewer->startSLERPAntiPos, &viewer->AntiPos, sizeof (
struct point_XYZ));
3587 memcpy (&viewer->startSLERPQuat, &viewer->Quat, sizeof (
Quaternion));
3588 memcpy (&viewer->startSLERPAntiQuat, &viewer->AntiQuat, sizeof (
Quaternion));
3589 memcpy (&viewer->startSLERPbindTimeQuat, &viewer->bindTimeQuat, sizeof (
Quaternion));
3590 memcpy (&viewer->startSLERPprepVPQuat, &viewer->prepVPQuat, sizeof (
Quaternion));
3593 viewer->SLERPing2 = TRUE;
3594 viewer->SLERPing2justStarted = TRUE;
3597 p->vp2rnSaved = TRUE;
3599 FW_GL_GETDOUBLEV(GL_MODELVIEW_MATRIX, p->viewpoint2rootnode);
3603 viewer->SLERPing = FALSE;
3604 viewer->SLERPing2 = FALSE;
3607 viewer->wasBound = TRUE;
3612 viewer->ortho=FALSE;
3617 viewer->GeoSpatialNode = NULL;
3620 INITIATE_ROTATION_ORIGIN
3650 INITIATE_POSITION_ANTIPOSITION
3652 viewer_lastP_clear();
3654 setMenuStatusVP (vp->description->strptr);
3657 int fwl_getAnaglyphSide(
int whichSide) {
3661 if ((whichSide<0) || (whichSide>1)) {
3676 return (p->acMask[whichSide][0] << 2) | (p->acMask[whichSide][1] << 1) | (p->acMask[whichSide][2]);
3683 void Android_reset_viewer_to_defaults() {
3689 p->viewer_initialized = FALSE;
3692 viewer->SLERPing2 = FALSE;
3693 viewer->SLERPing = FALSE;
3697 return Viewer()->iside;