void SpaceballTracker::update() { Matrix4 temp; if(!alive()) { moveto(0,0,0); orient->identity(); return; } if (uselocal) { float tx, ty, tz, rx, ry, rz; tx=ty=tz=rx=ry=rz=0.0f; int buttons; buttons=0; // query VMDApp spaceball for events if (app != NULL) { app->spaceball_get_tracker_status(tx, ty, tz, rx, ry, rz, buttons); } // Z-axis rotation/trans have to be negated in order to convert to the // VMD coordinate system temp.identity(); temp.rot(rx, 'x'); temp.rot(ry, 'y'); temp.rot(rz, 'z'); temp.multmatrix(*orient); orient->loadmatrix(temp); pos[0] += tx; pos[1] += ty; pos[2] += tz; } else { int tx, ty, tz, rx, ry, rz, buttons; tx=ty=tz=rx=ry=rz=buttons=0; #if defined(VMDLIBSBALL) if (sball != NULL ) { if (!sball_getstatus(sball, &tx, &ty, &tz, &rx, &ry, &rz, &buttons)) return; } #endif // Z-axis rotation/trans have to be negated in order to convert to the // VMD coordinate system temp.identity(); temp.rot( ((float)rx)*rotInc, 'x' ); temp.rot( ((float)ry)*rotInc, 'y' ); temp.rot(-((float)rz)*rotInc, 'z' ); temp.multmatrix(*orient); orient->loadmatrix(temp); pos[0] += tx * transInc; pos[1] += ty * transInc; pos[2] +=-tz * transInc; } }
// check for an event, and queue it if found. Return TRUE if an event // was generated. int Spaceball::check_event(void) { int tx, ty, tz, rx, ry, rz, buttons; int buttonchanged; int win_event=FALSE; int direct_event=FALSE; // for use in UserKeyEvent() calls DisplayDevice::EventCodes keydev=DisplayDevice::WIN_KBD; // explicitly initialize event state variables rx=ry=rz=tx=ty=tz=buttons=0; #if defined(VMDTDCONNEXION) && defined(__APPLE__) if (tdx_getstatus(tx, ty, tz, rx, ry, rz, buttons)) win_event = TRUE; #else if (app->display->spaceball(&rx, &ry, &rz, &tx, &ty, &tz, &buttons)) win_event = TRUE; #endif #if defined(VMDLIBSBALL) // combine direct spaceball events together with window-system events if (sball != NULL) { int rx2, ry2, rz2, tx2, ty2, tz2, buttons2; if (sball_getstatus(sball, &tx2, &ty2, &tz2, &rx2, &ry2, &rz2, &buttons2)) { direct_event = TRUE; rx += rx2; ry += ry2; rz += rz2; tx += tx2; ty += ty2; tz += tz2; buttons |= buttons2; } } #endif if (!win_event && !direct_event) return FALSE; // no events to report // find which buttons changed state buttonchanged = buttons ^ buttonDown; // if the user presses button 1, reset the view, a very very very // important feature to have implemented early on... ;-) #if defined(VMDLIBSBALL) && !defined(VMDSPACEWARE) if (((buttonchanged & SBALL_BUTTON_1) && (buttons & SBALL_BUTTON_1)) || ((buttonchanged & SBALL_BUTTON_LEFT) && (buttons & SBALL_BUTTON_LEFT))){ #else // #elif!defined(VMDLIBSBALL) && defined(VMDSPACEWARE) if ((buttonchanged & 2) && (buttons & 2)) { #endif app->scene_resetview(); msgInfo << "Spaceball reset view orientation" << sendmsg; } // Toggle between the different modes #if defined(VMDLIBSBALL) && !defined(VMDSPACEWARE) if (((buttonchanged & SBALL_BUTTON_2) && (buttons & SBALL_BUTTON_2)) || ((buttonchanged & SBALL_BUTTON_RIGHT) && (buttons & SBALL_BUTTON_RIGHT))) { #else //#elif !defined(VMDLIBSBALL) && defined(VMDSPACEWARE) if ((buttonchanged & 4) && (buttons & 4)) { #endif switch (moveMode) { case NORMAL: move_mode(MAXAXIS); msgInfo << "Spaceball set to dominant axis rotation/translation mode" << sendmsg; break; case MAXAXIS: move_mode(SCALING); msgInfo << "Spaceball set to scaling mode" << sendmsg; break; case SCALING: move_mode(ANIMATE); msgInfo << "Spaceball set to animate mode" << sendmsg; break; case ANIMATE: move_mode(TRACKER); msgInfo << "Spaceball set to tracker mode" << sendmsg; break; case TRACKER: move_mode(USER); msgInfo << "Spaceball set to user mode" << sendmsg; break; default: move_mode(NORMAL); msgInfo << "Spaceball set to rotation/translation mode" << sendmsg; break; } } // if the user presses button 3 through N, run a User command #if defined(VMDLIBSBALL) && !defined(VMDSPACEWARE) if ((buttonchanged & SBALL_BUTTON_3) && (buttons & SBALL_BUTTON_3)) { runcommand(new UserKeyEvent(keydev, '3', (int) DisplayDevice::AUX)); } if ((buttonchanged & SBALL_BUTTON_4) && (buttons & SBALL_BUTTON_4)) { runcommand(new UserKeyEvent(keydev, '4', (int) DisplayDevice::AUX)); } if ((buttonchanged & SBALL_BUTTON_5) && (buttons & SBALL_BUTTON_5)) { runcommand(new UserKeyEvent(keydev, '5', (int) DisplayDevice::AUX)); } if ((buttonchanged & SBALL_BUTTON_6) && (buttons & SBALL_BUTTON_6)) { runcommand(new UserKeyEvent(keydev, '6', (int) DisplayDevice::AUX)); } if ((buttonchanged & SBALL_BUTTON_7) && (buttons & SBALL_BUTTON_7)) { runcommand(new UserKeyEvent(keydev, '7', (int) DisplayDevice::AUX)); } if ((buttonchanged & SBALL_BUTTON_8) && (buttons & SBALL_BUTTON_8)) { runcommand(new UserKeyEvent(keydev, '8', (int) DisplayDevice::AUX)); } //#elif !defined(VMDLIBSBALL) && defined(VMDSPACEWARE) #else if ((buttonchanged & 8) && (buttons & 8)) { runcommand(new UserKeyEvent(keydev, '3', (int) DisplayDevice::AUX)); } if ((buttonchanged & 16) && (buttons & 16)) { runcommand(new UserKeyEvent(keydev, '4', (int) DisplayDevice::AUX)); } if ((buttonchanged & 32) && (buttons & 32)) { runcommand(new UserKeyEvent(keydev, '5', (int) DisplayDevice::AUX)); } if ((buttonchanged & 64) && (buttons & 64)) { runcommand(new UserKeyEvent(keydev, '6', (int) DisplayDevice::AUX)); } if ((buttonchanged & 128) && (buttons & 128)) { runcommand(new UserKeyEvent(keydev, '7', (int) DisplayDevice::AUX)); } if ((buttonchanged & 256) && (buttons & 256)) { runcommand(new UserKeyEvent(keydev, '8', (int) DisplayDevice::AUX)); } #endif // get absolute values of axis forces for use in // null region processing and min/max comparison tests int atx, aty, atz, arx, ary, arz; atx = abs(tx); aty = abs(ty); atz = abs(tz); arx = abs(rx); ary = abs(ry); arz = abs(rz); // perform null region processing if (atx > null_region) { tx = ((tx > 0) ? (tx - null_region) : (tx + null_region)); } else { tx = 0; } if (aty > null_region) { ty = ((ty > 0) ? (ty - null_region) : (ty + null_region)); } else { ty = 0; } if (atz > null_region) { tz = ((tz > 0) ? (tz - null_region) : (tz + null_region)); } else { tz = 0; } if (arx > null_region) { rx = ((rx > 0) ? (rx - null_region) : (rx + null_region)); } else { rx = 0; } if (ary > null_region) { ry = ((ry > 0) ? (ry - null_region) : (ry + null_region)); } else { ry = 0; } if (arz > null_region) { rz = ((rz > 0) ? (rz - null_region) : (rz + null_region)); } else { rz = 0; } // Ignore null motion events since some versions of the Windows // Spaceball driver emit a constant stream of null motion event // packets which would otherwise cause continuous redraws, pegging the // CPU and GPU at maximum load. if ((arx+ary+arz+atx+aty+atz) > 0) { float ftx = tx * sensitivity; float fty = ty * sensitivity; float ftz = tz * sensitivity; float frx = rx * sensitivity; float fry = ry * sensitivity; float frz = rz * sensitivity; char rmaxaxis = 'x'; float rmaxval = 0.0f; float tmaxval = 0.0f; float tmaxvec[3] = { 0.0f, 0.0f, 0.0f }; tmaxvec[0] = tmaxvec[1] = tmaxvec[2] = 0.0f; switch(moveMode) { case NORMAL: // Z-axis rotation/trans have to be negated in order to please VMD... app->scene_rotate_by(frx * rotInc, 'x'); app->scene_rotate_by(fry * rotInc, 'y'); app->scene_rotate_by(-frz * rotInc, 'z'); if (app->display_projection_is_perspective()) { app->scene_translate_by(ftx * transInc, fty * transInc, -ftz * transInc); } else { app->scene_scale_by((1.0f + scaleInc * -ftz > 0.0f) ? 1.0f + scaleInc * -ftz : 0.0f); app->scene_translate_by(ftx * transInc, fty * transInc, 0); } break; case MAXAXIS: // Z-axis rotation/trans have to be negated in order to please VMD... // find dominant rotation axis if (arx > ary) { if (arx > arz) { rmaxaxis = 'x'; rmaxval = frx; } else { rmaxaxis = 'z'; rmaxval = -frz; } } else { if (ary > arz) { rmaxaxis = 'y'; rmaxval = fry; } else { rmaxaxis = 'z'; rmaxval = -frz; } } // find dominant translation axis if (atx > aty) { if (atx > atz) { tmaxval = ftx; tmaxvec[0] = ftx; } else { tmaxval = ftz; tmaxvec[2] = ftz; } } else { if (aty > atz) { tmaxval = fty; tmaxvec[1] = fty; } else { tmaxval = ftz; tmaxvec[2] = ftz; } } // determine whether to rotate or translate if (fabs(rmaxval) > fabs(tmaxval)) { app->scene_rotate_by(rmaxval * rotInc, rmaxaxis); } else { app->scene_translate_by(tmaxvec[0] * transInc, tmaxvec[1] * transInc, -tmaxvec[2] * transInc); } break; case SCALING: app->scene_scale_by((1.0f + scaleInc * ftz > 0.0f) ? 1.0f + scaleInc * ftz : 0.0f); break; case ANIMATE: // if we got a non-zero input, update the VMD animation state if (abs(ry) > 0) { #if 1 // exponential input scaling float speed = fabsf(expf(fabsf((fabsf(fry) * animInc) / 1.7f))) - 1.0f; #else // linear input scaling float speed = fabsf(fry) * animInc; #endif if (speed > 0) { if (speed < 1.0) app->animation_set_speed(speed); else app->animation_set_speed(1.0f); int stride = 1; if (fabs(speed - 1.0) > (double) maxstride) stride = maxstride; else stride = 1 + (int) fabs(speed-1.0); if (stride < 1) stride = 1; app->animation_set_stride(stride); // -ry is turned to the right, like a typical shuttle/jog control if (fry < 0) app->animation_set_dir(Animation::ANIM_FORWARD1); else app->animation_set_dir(Animation::ANIM_REVERSE1); } else { app->animation_set_dir(Animation::ANIM_PAUSE); app->animation_set_speed(1.0f); } } else { app->animation_set_dir(Animation::ANIM_PAUSE); app->animation_set_speed(1.0f); } break; case TRACKER: trtx = ftx; trty = fty; trtz = ftz; trrx = frx; trry = fry; trrz = frz; trbuttons = buttons; break; case USER: // inform TCL app->commandQueue->runcommand(new SpaceballEvent(ftx, fty, ftz, frx, fry, frz, buttons)); break; } } // update button status for next time through buttonDown = buttons; return TRUE; } ///////////// public routines for use by text commands etc const char* Spaceball::get_mode_str(MoveMode mm) { const char* modestr; switch (mm) { default: case NORMAL: modestr = "rotate"; break; case MAXAXIS: modestr = "maxaxis"; break; case SCALING: modestr = "scale"; break; case ANIMATE: modestr = "animate"; break; case TRACKER: modestr = "tracker"; break; case USER: modestr = "user"; break; } return modestr; } void Spaceball::get_tracker_status(float &tx, float &ty, float &tz, float &rx, float &ry, float &rz, int &buttons) { tx = trtx * transInc; ty = trty * transInc; tz = -trtz * transInc; rx = trrx * rotInc; ry = trry * rotInc; rz = -trrz * rotInc; buttons = trbuttons; } // set the Spaceball move mode to the given state; return success int Spaceball::move_mode(MoveMode mm) { // change the mode now moveMode = mm; /// clear out any remaining tracker event data if we're not in that mode if (moveMode != TRACKER) { trtx=trty=trtz=trrx=trry=trrz=0.0f; trbuttons=0; } return TRUE; // report success }
int tachyon_spaceball_update(sbHandle * bh, SceneHandle scene) { int tx, ty, tz, rx, ry, rz, buttons; float qq[4]; float xx[3]={1.0, 0.0, 0.0}; float yy[3]={0.0, 1.0, 0.0}; float zz[3]={0.0, 0.0, 1.0}; float m[4][4]; float t[3]; static float transdivisor = 5000.0; static float angdivisor = 20000.0; if (bh->sball == NULL) return -1; if (sball_getstatus(bh->sball, &tx, &ty, &tz, &rx, &ry, &rz, &buttons)) { /* negate rotations given by spaceball */ rx = -rx; ry = -ry; rz = -rz; if (buttons) { if (buttons & SBALL_BUTTON_PICK) { bh->curtrans[0] = 0.0; bh->curtrans[1] = 0.0; bh->curtrans[2] = 0.0; trackball(bh->curquat, 0.0, 0.0, 0.0, 0.0); transdivisor = 5000.0; angdivisor = 20000.0; bh->camviewvec = bh->orig_camviewvec; bh->camupvec = bh->orig_camupvec; bh->camcent = bh->orig_camcent; } if (buttons & SBALL_BUTTON_1) { transdivisor /= 1.2; angdivisor /= 1.2; } else if (buttons & SBALL_BUTTON_2) { transdivisor *= 1.2; angdivisor *= 1.2; } if (buttons & SBALL_BUTTON_3) transdivisor /= 1.2; else if (buttons & SBALL_BUTTON_4) transdivisor *= 1.2; if (buttons & SBALL_BUTTON_5) angdivisor *= 1.2; else if (buttons & SBALL_BUTTON_6) angdivisor /= 1.2; if (buttons & SBALL_BUTTON_7) { return 1; /* quit the fly through */ } } /* end of button handling */ t[0] = tx / transdivisor; t[1] = ty / transdivisor; t[2] = tz / transdivisor; /* * convert rotations and translations from the * spaceball's coordinate frame into the camera's frame. */ bh->newtrans[0] = t[0] * bh->orig_camrightvec.x + t[1] * bh->orig_camupvec.x + t[2] * bh->orig_camviewvec.x; bh->newtrans[1] = t[0] * bh->orig_camrightvec.y + t[1] * bh->orig_camupvec.y + t[2] * bh->orig_camviewvec.y; bh->newtrans[2] = t[0] * bh->orig_camrightvec.z + t[1] * bh->orig_camupvec.z + t[2] * bh->orig_camviewvec.z; /* * rotate around camera's coordinate frame */ xx[0] = bh->orig_camrightvec.x; xx[1] = bh->orig_camrightvec.y; xx[2] = bh->orig_camrightvec.z; yy[0] = bh->orig_camupvec.x; yy[1] = bh->orig_camupvec.y; yy[2] = bh->orig_camupvec.z; zz[0] = bh->orig_camviewvec.x; zz[1] = bh->orig_camviewvec.y; zz[2] = bh->orig_camviewvec.z; /* do rotations */ axis_to_quat(xx, rx / angdivisor, bh->lastquat); axis_to_quat(yy, ry / angdivisor, qq); add_quats(qq, bh->lastquat, bh->lastquat); axis_to_quat(zz, rz / angdivisor, qq); add_quats(qq, bh->lastquat, bh->lastquat); add_quats(bh->lastquat, bh->curquat, bh->curquat); } else { usleep(5); /* if no movement then sleep for a tiny bit.. */ } build_rotmatrix(m, bh->curquat); /* * translate along the new axes */ t[0] = m[0][0] * bh->newtrans[0] + m[0][1] * bh->newtrans[1] + m[0][2] * bh->newtrans[2]; t[1] = m[1][0] * bh->newtrans[0] + m[1][1] * bh->newtrans[1] + m[1][2] * bh->newtrans[2]; t[2] = m[2][0] * bh->newtrans[0] + m[2][1] * bh->newtrans[1] + m[2][2] * bh->newtrans[2]; bh->camcent.x += t[0]; bh->camcent.y += t[1]; bh->camcent.z += t[2]; /* * rotate view system with spaceball */ bh->camviewvec.x = m[0][0] * bh->orig_camviewvec.x + m[0][1] * bh->orig_camviewvec.y + m[0][2] * bh->orig_camviewvec.z; bh->camviewvec.y = m[1][0] * bh->orig_camviewvec.x + m[1][1] * bh->orig_camviewvec.y + m[1][2] * bh->orig_camviewvec.z; bh->camviewvec.z = m[2][0] * bh->orig_camviewvec.x + m[2][1] * bh->orig_camviewvec.y + m[2][2] * bh->orig_camviewvec.z; bh->camupvec.x = m[0][0] * bh->orig_camupvec.x + m[0][1] * bh->orig_camupvec.y + m[0][2] * bh->orig_camupvec.z; bh->camupvec.y = m[1][0] * bh->orig_camupvec.x + m[1][1] * bh->orig_camupvec.y + m[1][2] * bh->orig_camupvec.z; bh->camupvec.z = m[2][0] * bh->orig_camupvec.x + m[2][1] * bh->orig_camupvec.y + m[2][2] * bh->orig_camupvec.z; /* * update camera parameters before we render again */ rt_camera_position(scene, bh->camcent, bh->camviewvec, bh->camupvec); return 0; }