Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

Spaceball.C

Go to the documentation of this file.
00001 /***************************************************************************
00002  *cr                                                                       
00003  *cr            (C) Copyright 1995-2011 The Board of Trustees of the           
00004  *cr                        University of Illinois                       
00005  *cr                         All Rights Reserved                        
00006  *cr                                                                   
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  * RCS INFORMATION:
00011  *
00012  *      $RCSfile: Spaceball.C,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.61 $       $Date: 2011/02/18 20:28:32 $
00015  *
00016  ***************************************************************************
00017  * DESCRIPTION:
00018  *
00019  * The Spaceball UI object, which maintains the current state of the 
00020  * spaceball.  This code uses John Stone's spaceball library when
00021  * VMDLIBSBALL is defined, or the Spaceware library when VMDSPACEWARE 
00022  * is defined.
00023  *
00024  ***************************************************************************
00025  * TODO list:
00026  *   1) Mac code needs to either flush queued events, force-read them all
00027  *      at every screen redraw, or use an independent thread to process them
00028  *      so that the event queue never lags the screen draws.
00029  *   2) The 'animate' mode needs to use the wall-clock time since the last
00030  *      event to normalize the applied force to account for complex 
00031  *      reps slowing down the update rate.  With the exponential speed
00032  *      the animate step size can get out of hand far too easily.  The max
00033  *      step size allowed should be capped, preferably to a user-configurable
00034  *      limit.  A default step size limit of something like 50 would be a 
00035  *      good compromise. (Partially done)
00036  *   3) Orthographic mode confuses beginners because the scene doesn't
00037  *      scale when they pull objects towards the camera.  They expect 
00038  *      behavior more like what one gets with perspective.  We may want to
00039  *      provide a default behavior of scaling when orthographic projection
00040  *      is active and the user pulls towards them. (Partially done)
00041  *   4) The spaceball mode switching is too complex to be handled well
00042  *      by a two button device.  We need to map these functions to 
00043  *      keyboard keys to make it easier to use.  It would be even better if
00044  *      we briefly displayed status messages on the screen for a couple of
00045  *      seconds when modes are changed since one might not be able to see
00046  *      the text console.  This would be useful for any mode changes that
00047  *      affect the VMD control/input state that don't have some other
00048  *      visual/audio cue to observe. (e.g. the mouse pointer changing
00049  *      when mouse modes are altered).
00050  *
00051  ***************************************************************************/
00052 
00053 #include "Spaceball.h"
00054 #include "DisplayDevice.h"
00055 #include "TextEvent.h"
00056 #include "CommandQueue.h"
00057 #include "Inform.h"
00058 #include "PickList.h"
00059 #include "Animation.h"
00060 #include "VMDApp.h"
00061 #include "math.h"
00062 #include "stdlib.h" // for getenv(), abs() etc.
00063 
00064 //
00065 // 3DConnexion MacOS X driver API
00066 //
00067 #if defined(VMDTDCONNEXION) && defined(__APPLE__)
00068 #include <unistd.h>
00069 #include <Carbon/Carbon.h>
00070 #include <stdio.h>
00071 #include <stdlib.h>
00072 
00073 // 3dxware API header
00074 #include "3DconnexionClient/ConnexionClientAPI.h"
00075 
00076 extern "C" {
00077 extern OSErr InstallConnexionHandlers(ConnexionMessageHandlerProc messageHandler, ConnexionAddedHandlerProc addedHandler, ConnexionRemovedHandlerProc removedHandler) __attribute__((weak_import));
00078 }
00079 
00080 // Pascal string name of the application binary used for window 
00081 // focus handling when we don't provide an application bundle key
00082 // at callback registration time
00083 #if defined(ARCH_MACOSX)
00084 static UInt8 *executablename = (UInt8 *) "\pvmd_MACOSX";
00085 #elif defined(ARCH_MACOSXX86)
00086 static UInt8 *executablename = (UInt8 *) "\pvmd_MACOSXX86";
00087 #elif defined(ARCH_MACOSXX86_64)
00088 static UInt8 *executablename = (UInt8 *) "\pvmd_MACOSXX86_64";
00089 #else
00090 #error
00091 #endif
00092 
00093 typedef struct {
00094   int enabled;   // flag indicating whether we're live or not
00095   UInt16 client; // 3DConnexion API client used for focus handling
00096   int tx;
00097   int ty;
00098   int tz;
00099   int rx; 
00100   int ry;
00101   int rz;
00102   int buttons;
00103   int eventcount;
00104 } tdx_data;
00105 
00106 // global event data structure
00107 static tdx_data tdxevent;
00108 
00109 // event handler proc
00110 // XXX note that the default single-threaded implementation
00111 //     described in the 3DConnexion documentation leaves a lot
00112 //     to be desired.  In reality, we realistically want a multithreaded
00113 //     implementation, otherwise the events queue up and get way behind
00114 //     when we draw a complex molecule.  In order to handle the device
00115 //     events separately, we can install a special event handler in 
00116 //     a second thread and have it store event data to a shared memory area.
00117 static void tdx_msghandler(io_connect_t connection, 
00118                            natural_t msgtype, void *msgarg) {
00119   ConnexionDeviceState *state = NULL;
00120   switch (msgtype) {
00121     case kConnexionMsgDeviceState:
00122       state = (ConnexionDeviceState *) msgarg;
00123       if (state->client == tdxevent.client) {
00124         switch (state->command) {
00125           case kConnexionCmdHandleAxis:
00126             tdxevent.tx +=  state->axis[0];
00127             tdxevent.ty += -state->axis[2];
00128             tdxevent.tz += -state->axis[1];
00129             tdxevent.rx +=  state->axis[3];
00130             tdxevent.ry += -state->axis[5];
00131             tdxevent.rz += -state->axis[4];
00132             tdxevent.eventcount++;
00133             break;
00134 
00135           case kConnexionCmdHandleButtons:
00136             tdxevent.buttons = state->buttons;
00137             tdxevent.eventcount++;
00138             break;
00139         }
00140       }
00141       break;
00142 
00143     default:
00144 //      printf("Unknown message type\n");
00145       break;
00146   }
00147 }
00148 
00149 static void tdx_clear() {
00150   memset(&tdxevent, 0, sizeof(tdxevent));
00151 }
00152 
00153 static int tdx_enable() {
00154   UInt16 clientID;
00155 
00156   if (InstallConnexionHandlers == NULL) {
00157     msgInfo << "No 3DConnexion driver on this system." << sendmsg;
00158     return -1;
00159   }
00160   OSErr result = InstallConnexionHandlers(tdx_msghandler, 0L, 0L);
00161   if (result != noErr) {
00162     msgInfo << "Unable to register with 3DConnexion driver." << sendmsg;
00163     return -1;
00164   }
00165 
00166 #if 1
00167   // only respond to all events when we have focus
00168   clientID = RegisterConnexionClient(0, executablename,
00169                kConnexionClientModeTakeOver, kConnexionMaskAll);
00170 #else
00171   // respond to all events whether we have focus or not
00172   clientID = RegisterConnexionClient(kConnexionClientWildcard, NULL,
00173                kConnexionClientModeTakeOver, kConnexionMaskAll);
00174 #endif
00175 
00176   tdxevent.enabled = 1;
00177   tdxevent.client = clientID;
00178 
00179   return 0;
00180 }
00181 
00182 static int tdx_detach() {
00183   if (tdxevent.enabled) {
00184     UnregisterConnexionClient(tdxevent.client);
00185     CleanupConnexionHandlers();
00186   }
00187   tdx_clear();
00188 }
00189 
00190 int tdx_getstatus(int &tx, int &ty, int &tz, int &rx, int &ry, int &rz, int &buttons) {
00191   int eventcount = tdxevent.eventcount;
00192 
00193   tx = tdxevent.tx; 
00194   ty = tdxevent.ty; 
00195   tz = tdxevent.tz; 
00196   rx = tdxevent.rx; 
00197   ry = tdxevent.ry; 
00198   rz = tdxevent.rz; 
00199   buttons = tdxevent.buttons;
00200   
00201   tdxevent.tx = 0;
00202   tdxevent.ty = 0;
00203   tdxevent.tz = 0;
00204   tdxevent.rx = 0;
00205   tdxevent.ry = 0;
00206   tdxevent.rz = 0;
00207   tdxevent.eventcount = 0;
00208   
00209   return eventcount;
00210 }
00211 
00212 #endif
00213 
00214 
00215 
00216 // constructor
00217 Spaceball::Spaceball(VMDApp *vmdapp)
00218         : UIObject(vmdapp) {
00219 
00220 #if defined(VMDTDCONNEXION) && defined(__APPLE__)
00221   // Enable input from MacOS X 3DConnexion API
00222   tdx_clear();
00223   if (tdx_enable() == 0)
00224     msgInfo << "3DConnexion SpaceNavigator enabled." << sendmsg;
00225 #endif
00226 
00227 #if defined(VMDLIBSBALL) && !defined(VMDSPACEWARE)
00228   sball=NULL; // zero it out to begin with
00229   if (getenv("VMDSPACEBALLPORT") != NULL) {
00230     msgInfo << "Opening Spaceball (direct I/O) on port: " 
00231             << getenv("VMDSPACEBALLPORT") << sendmsg;
00232     sball = sball_open(getenv("VMDSPACEBALLPORT"));
00233     if (sball == NULL) 
00234       msgErr << "Failed to open Spaceball direct I/O serial port, device disabled." 
00235              << sendmsg; 
00236   }
00237 #endif
00238 
00239   buttonDown = 0;
00240 
00241   reset();
00242 }
00243 
00244 
00245 // destructor
00246 Spaceball::~Spaceball(void) {
00247 #if defined(VMDTDCONNEXION) && defined(__APPLE__)
00248   // Disable input from MacOS X 3DConnextion API
00249   tdx_detach();
00250 #endif
00251 
00252 #if defined(VMDLIBSBALL) && !defined(VMDSPACEWARE)
00253   if (sball != NULL)
00254     sball_close(sball);
00255 #endif
00256 }
00257 
00258 
00260    
00261 // reset the spaceball to original settings
00262 void Spaceball::reset(void) {
00263   // set the default motion mode and initialize button state
00264   move_mode(NORMAL);
00265 
00266   // set global spaceball sensitivity within VMD
00267   // (this has no effect on underlying driver sensitivity settings)
00268   set_sensitivity(1.0f);
00269 
00270   // set the null region to a small value initially
00271   set_null_region(16);
00272 
00273   // set the maximum animate stride allowed to 20 by default
00274   set_max_stride(20);
00275 
00276   // set the default translation and rotation increments
00277   // these really need to be made user modifiable at runtime
00278   transInc = 1.0f / 25000.0f;
00279     rotInc = 1.0f /   200.0f;
00280   scaleInc = 1.0f / 25000.0f;
00281    animInc = 1.0f /    75.0f;
00282 }
00283 
00284 // update the display due to a command being executed.  Return whether
00285 // any action was taken on this command.
00286 // Arguments are the command type, command object, and the 
00287 // success of the command (T or F).
00288 int Spaceball::act_on_command(int type, Command *cmd) {
00289   return FALSE; // we don't take any commands presently
00290 }
00291 
00292 
00293 // check for an event, and queue it if found.  Return TRUE if an event
00294 // was generated.
00295 int Spaceball::check_event(void) {
00296   int tx, ty, tz, rx, ry, rz, buttons;
00297   int buttonchanged;
00298   int win_event=FALSE;
00299   int direct_event=FALSE;
00300   // for use in UserKeyEvent() calls
00301   DisplayDevice::EventCodes keydev=DisplayDevice::WIN_KBD;
00302 
00303   // explicitly initialize event state variables
00304   rx=ry=rz=tx=ty=tz=buttons=0;
00305 
00306 #if defined(VMDTDCONNEXION) && defined(__APPLE__)
00307   if (tdx_getstatus(tx, ty, tz, rx, ry, rz, buttons))
00308     win_event = TRUE;
00309 #else
00310   if (app->display->spaceball(&rx, &ry, &rz, &tx, &ty, &tz, &buttons)) 
00311     win_event = TRUE;
00312 #endif
00313 
00314 
00315 #if defined(VMDLIBSBALL)
00316   // combine direct spaceball events together with window-system events
00317   if (sball != NULL) {
00318     int rx2, ry2, rz2, tx2, ty2, tz2, buttons2;
00319     if (sball_getstatus(sball, &tx2, &ty2, &tz2, &rx2, &ry2, &rz2, &buttons2)) {
00320       direct_event = TRUE;
00321       rx += rx2;
00322       ry += ry2;
00323       rz += rz2;
00324       tx += tx2; 
00325       ty += ty2; 
00326       tz += tz2; 
00327       buttons |= buttons2;
00328     }
00329   }
00330 #endif
00331 
00332   if (!win_event && !direct_event)
00333     return FALSE; // no events to report
00334 
00335   // find which buttons changed state
00336   buttonchanged = buttons ^ buttonDown; 
00337 
00338   // if the user presses button 1, reset the view, a very very very
00339   // important feature to have implemented early on... ;-)
00340 #if defined(VMDLIBSBALL)  && !defined(VMDSPACEWARE)
00341   if (((buttonchanged & SBALL_BUTTON_1) && (buttons & SBALL_BUTTON_1)) ||
00342       ((buttonchanged & SBALL_BUTTON_LEFT) && (buttons & SBALL_BUTTON_LEFT))){
00343 #else 
00344 // #elif!defined(VMDLIBSBALL) && defined(VMDSPACEWARE)
00345   if ((buttonchanged & 2) && (buttons & 2)) {
00346 #endif
00347 
00348     app->scene_resetview();
00349     msgInfo << "Spaceball reset view orientation" << sendmsg;
00350   }
00351 
00352   // Toggle between the different modes
00353 #if   defined(VMDLIBSBALL)  &&  !defined(VMDSPACEWARE)
00354   if (((buttonchanged & SBALL_BUTTON_2) && (buttons & SBALL_BUTTON_2)) ||
00355       ((buttonchanged & SBALL_BUTTON_RIGHT) && (buttons & SBALL_BUTTON_RIGHT))) {
00356 #else
00357 //#elif !defined(VMDLIBSBALL) &&  defined(VMDSPACEWARE)
00358   if ((buttonchanged & 4) && (buttons & 4)) {
00359 #endif
00360 
00361     switch (moveMode) {
00362       case NORMAL:
00363         move_mode(MAXAXIS);
00364         msgInfo << "Spaceball set to dominant axis rotation/translation mode" << sendmsg;
00365         break;   
00366 
00367       case MAXAXIS:
00368         move_mode(SCALING);
00369         msgInfo << "Spaceball set to scaling mode" << sendmsg;
00370         break;   
00371 
00372       case SCALING:
00373         move_mode(ANIMATE);
00374         msgInfo << "Spaceball set to animate mode" << sendmsg;
00375         break;   
00376 
00377       case ANIMATE:
00378         move_mode(TRACKER);
00379         msgInfo << "Spaceball set to tracker mode" << sendmsg;
00380         break;   
00381 
00382       case TRACKER:
00383         move_mode(USER);
00384         msgInfo << "Spaceball set to user mode" << sendmsg;
00385         break;   
00386 
00387       default: 
00388         move_mode(NORMAL);
00389         msgInfo << "Spaceball set to rotation/translation mode" << sendmsg;
00390         break;
00391     }
00392   }
00393 
00394   // if the user presses button 3 through N, run a User command
00395 #if defined(VMDLIBSBALL)  &&  !defined(VMDSPACEWARE)
00396   if ((buttonchanged & SBALL_BUTTON_3) && (buttons & SBALL_BUTTON_3)) {
00397     runcommand(new UserKeyEvent(keydev, '3', (int) DisplayDevice::AUX));
00398   }
00399   if ((buttonchanged & SBALL_BUTTON_4) && (buttons & SBALL_BUTTON_4)) {
00400     runcommand(new UserKeyEvent(keydev, '4', (int) DisplayDevice::AUX));
00401   }
00402   if ((buttonchanged & SBALL_BUTTON_5) && (buttons & SBALL_BUTTON_5)) {
00403     runcommand(new UserKeyEvent(keydev, '5', (int) DisplayDevice::AUX));
00404   }
00405   if ((buttonchanged & SBALL_BUTTON_6) && (buttons & SBALL_BUTTON_6)) {
00406     runcommand(new UserKeyEvent(keydev, '6', (int) DisplayDevice::AUX));
00407   }
00408   if ((buttonchanged & SBALL_BUTTON_7) && (buttons & SBALL_BUTTON_7)) {
00409     runcommand(new UserKeyEvent(keydev, '7', (int) DisplayDevice::AUX));
00410   }
00411   if ((buttonchanged & SBALL_BUTTON_8) && (buttons & SBALL_BUTTON_8)) {
00412     runcommand(new UserKeyEvent(keydev, '8', (int) DisplayDevice::AUX));
00413   }
00414 //#elif !defined(VMDLIBSBALL) &&  defined(VMDSPACEWARE)
00415 #else
00416   if ((buttonchanged & 8) && (buttons & 8)) {
00417     runcommand(new UserKeyEvent(keydev, '3', (int) DisplayDevice::AUX));
00418   }
00419   if ((buttonchanged & 16) && (buttons & 16)) {
00420     runcommand(new UserKeyEvent(keydev, '4', (int) DisplayDevice::AUX));
00421   }
00422   if ((buttonchanged & 32) && (buttons & 32)) {
00423     runcommand(new UserKeyEvent(keydev, '5', (int) DisplayDevice::AUX));
00424   }
00425   if ((buttonchanged & 64) && (buttons & 64)) {
00426     runcommand(new UserKeyEvent(keydev, '6', (int) DisplayDevice::AUX));
00427   }
00428   if ((buttonchanged & 128) && (buttons & 128)) {
00429     runcommand(new UserKeyEvent(keydev, '7', (int) DisplayDevice::AUX));
00430   }
00431   if ((buttonchanged & 256) && (buttons & 256)) {
00432     runcommand(new UserKeyEvent(keydev, '8', (int) DisplayDevice::AUX));
00433   }
00434 #endif
00435 
00436   // get absolute values of axis forces for use in 
00437   // null region processing and min/max comparison tests
00438   int atx, aty, atz, arx, ary, arz;
00439   atx = abs(tx);
00440   aty = abs(ty);
00441   atz = abs(tz);
00442   arx = abs(rx);
00443   ary = abs(ry);
00444   arz = abs(rz);
00445 
00446 
00447   // perform null region processing
00448   if (atx > null_region) {
00449     tx = ((tx > 0) ? (tx - null_region) : (tx + null_region));
00450   } else {
00451     tx = 0;
00452   }
00453   if (aty > null_region) {
00454     ty = ((ty > 0) ? (ty - null_region) : (ty + null_region));
00455   } else {
00456     ty = 0;
00457   }
00458   if (atz > null_region) {
00459     tz = ((tz > 0) ? (tz - null_region) : (tz + null_region));
00460   } else {
00461     tz = 0;
00462   }
00463   if (arx > null_region) {
00464     rx = ((rx > 0) ? (rx - null_region) : (rx + null_region));
00465   } else {
00466     rx = 0;
00467   }
00468   if (ary > null_region) {
00469     ry = ((ry > 0) ? (ry - null_region) : (ry + null_region));
00470   } else {
00471     ry = 0;
00472   }
00473   if (arz > null_region) {
00474     rz = ((rz > 0) ? (rz - null_region) : (rz + null_region));
00475   } else {
00476     rz = 0;
00477   }
00478 
00479 
00480   // Ignore null motion events since some versions of the Windows 
00481   // Spaceball driver emit a constant stream of null motion event
00482   // packets which would otherwise cause continuous redraws, pegging the 
00483   // CPU and GPU at maximum load.
00484   if ((arx+ary+arz+atx+aty+atz) > 0) {
00485     float ftx = tx * sensitivity;
00486     float fty = ty * sensitivity;
00487     float ftz = tz * sensitivity;
00488     float frx = rx * sensitivity;
00489     float fry = ry * sensitivity;
00490     float frz = rz * sensitivity;
00491     char rmaxaxis = 'x';
00492     float rmaxval = 0.0f;
00493     float tmaxval = 0.0f;
00494     float tmaxvec[3] = { 0.0f, 0.0f, 0.0f };
00495     tmaxvec[0] = tmaxvec[1] = tmaxvec[2] = 0.0f;
00496 
00497     switch(moveMode) {
00498       case NORMAL:
00499         // Z-axis rotation/trans have to be negated in order to please VMD...
00500         app->scene_rotate_by(frx * rotInc, 'x');
00501         app->scene_rotate_by(fry * rotInc, 'y');
00502         app->scene_rotate_by(-frz * rotInc, 'z');
00503         if (app->display_projection_is_perspective()) {
00504           app->scene_translate_by(ftx * transInc, fty * transInc, -ftz * transInc);
00505         } else {
00506           app->scene_scale_by((1.0f + scaleInc * -ftz > 0.0f) ? 
00507                                1.0f + scaleInc * -ftz : 0.0f);
00508           app->scene_translate_by(ftx * transInc, fty * transInc, 0);
00509         }
00510  
00511         break;
00512 
00513       case MAXAXIS:
00514         // Z-axis rotation/trans have to be negated in order to please VMD...
00515         // find dominant rotation axis
00516         if (arx > ary) {
00517           if (arx > arz) {
00518             rmaxaxis = 'x';
00519             rmaxval = frx; 
00520           } else {
00521             rmaxaxis = 'z';
00522             rmaxval = -frz; 
00523           }
00524         } else {     
00525           if (ary > arz) {
00526             rmaxaxis = 'y';
00527             rmaxval = fry; 
00528           } else {
00529             rmaxaxis = 'z';
00530             rmaxval = -frz; 
00531           }
00532         }
00533 
00534         // find dominant translation axis
00535         if (atx > aty) {
00536           if (atx > atz) {
00537             tmaxval = ftx;
00538             tmaxvec[0] = ftx; 
00539           } else {
00540             tmaxval = ftz;
00541             tmaxvec[2] = ftz; 
00542           }
00543         } else {     
00544           if (aty > atz) {
00545             tmaxval = fty;
00546             tmaxvec[1] = fty; 
00547           } else {
00548             tmaxval = ftz;
00549             tmaxvec[2] = ftz; 
00550           }
00551        }
00552 
00553        // determine whether to rotate or translate
00554        if (fabs(rmaxval) > fabs(tmaxval)) {
00555          app->scene_rotate_by(rmaxval * rotInc, rmaxaxis);
00556        } else {
00557          app->scene_translate_by(tmaxvec[0] * transInc, 
00558                                  tmaxvec[1] * transInc, 
00559                                 -tmaxvec[2] * transInc);
00560        }
00561        break;
00562 
00563       case SCALING:
00564         app->scene_scale_by((1.0f + scaleInc * ftz > 0.0f) ? 
00565                              1.0f + scaleInc * ftz : 0.0f);
00566         break;
00567 
00568       case ANIMATE:
00569         // if we got a non-zero input, update the VMD animation state
00570         if (abs(ry) > 0) {
00571 #if 1
00572           // exponential input scaling
00573           float speed = fabsf(expf(fabsf((fabsf(fry) * animInc) / 1.7f))) - 1.0f;
00574 #else
00575           // linear input scaling
00576           float speed = fabsf(fry) * animInc;
00577 #endif
00578 
00579           if (speed > 0) {
00580             if (speed < 1.0) 
00581               app->animation_set_speed(speed);
00582             else
00583               app->animation_set_speed(1.0f);
00584  
00585             int stride = 1;
00586             if (fabs(speed - 1.0) > (double) maxstride)
00587               stride = maxstride;
00588             else
00589               stride = 1 + (int) fabs(speed-1.0);
00590             if (stride < 1)
00591               stride = 1; 
00592             app->animation_set_stride(stride);
00593  
00594             // -ry is turned to the right, like a typical shuttle/jog control
00595             if (fry < 0) 
00596               app->animation_set_dir(Animation::ANIM_FORWARD1);
00597             else
00598               app->animation_set_dir(Animation::ANIM_REVERSE1);
00599           } else {
00600             app->animation_set_dir(Animation::ANIM_PAUSE);
00601             app->animation_set_speed(1.0f);
00602           }
00603         } else {
00604           app->animation_set_dir(Animation::ANIM_PAUSE);
00605           app->animation_set_speed(1.0f);
00606         }
00607         break;
00608 
00609       case TRACKER:
00610         trtx = ftx;
00611         trty = fty;
00612         trtz = ftz;
00613         trrx = frx;
00614         trry = fry;
00615         trrz = frz;
00616         trbuttons = buttons;
00617         break;
00618 
00619       case USER:
00620         // inform TCL
00621         app->commandQueue->runcommand(new SpaceballEvent(ftx, fty, ftz, 
00622                                                          frx, fry, frz, 
00623                                                          buttons));
00624         break;
00625     }
00626   }
00627 
00628   // update button status for next time through
00629   buttonDown = buttons;
00630 
00631   return TRUE;
00632 }
00633 
00634 
00636 
00637 const char* Spaceball::get_mode_str(MoveMode mm) {
00638   const char* modestr;
00639 
00640   switch (mm) {
00641     default:
00642     case NORMAL:      modestr = "rotate";     break;
00643     case MAXAXIS:     modestr = "maxaxis";    break;
00644     case SCALING:     modestr = "scale";      break;
00645     case ANIMATE:     modestr = "animate";    break;
00646     case TRACKER:     modestr = "tracker";    break;
00647     case USER:        modestr = "user";       break;
00648   }
00649 
00650   return modestr;
00651 }
00652 
00653 
00654 void Spaceball::get_tracker_status(float &tx, float &ty, float &tz,
00655                                    float &rx, float &ry, float &rz, 
00656                                    int &buttons) {
00657   tx =  trtx * transInc;
00658   ty =  trty * transInc;
00659   tz = -trtz * transInc;
00660   rx =  trrx * rotInc;
00661   ry =  trry * rotInc;
00662   rz = -trrz * rotInc;
00663   buttons = trbuttons;
00664 }
00665 
00666 
00667 // set the Spaceball move mode to the given state; return success
00668 int Spaceball::move_mode(MoveMode mm) {
00669   // change the mode now
00670   moveMode = mm;
00671 
00673   if (moveMode != TRACKER) {
00674     trtx=trty=trtz=trrx=trry=trrz=0.0f; 
00675     trbuttons=0;
00676   }
00677 
00678   return TRUE; // report success
00679 }
00680 
00681 
00682 

Generated on Sat May 26 01:48:28 2012 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002