Main Page   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-2008 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.53 $       $Date: 2008/06/20 06:37:18 $
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(ARCH_MACOSX) || defined(ARCH_MACOSXX86))
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 #else
00088 #error
00089 #endif
00090 
00091 typedef struct {
00092   int enabled;   // flag indicating whether we're live or not
00093   UInt16 client; // 3DConnexion API client used for focus handling
00094   int tx;
00095   int ty;
00096   int tz;
00097   int rx; 
00098   int ry;
00099   int rz;
00100   int buttons;
00101   int eventcount;
00102 } tdx_data;
00103 
00104 // global event data structure
00105 static tdx_data tdxevent;
00106 
00107 // event handler proc
00108 // XXX note that the default single-threaded implementation
00109 //     described in the 3DConnexion documentation leaves a lot
00110 //     to be desired.  In reality, we realistically want a multithreaded
00111 //     implementation, otherwise the events queue up and get way behind
00112 //     when we draw a complex molecule.  In order to handle the device
00113 //     events separately, we can install a special event handler in 
00114 //     a second thread and have it store event data to a shared memory area.
00115 static void tdx_msghandler(io_connect_t connection, 
00116                            natural_t msgtype, void *msgarg) {
00117   ConnexionDeviceState *state = NULL;
00118   switch (msgtype) {
00119     case kConnexionMsgDeviceState:
00120       state = (ConnexionDeviceState *) msgarg;
00121       if (state->client == tdxevent.client) {
00122         switch (state->command) {
00123           case kConnexionCmdHandleAxis:
00124             tdxevent.tx +=  state->axis[0];
00125             tdxevent.ty += -state->axis[2];
00126             tdxevent.tz += -state->axis[1];
00127             tdxevent.rx +=  state->axis[3];
00128             tdxevent.ry += -state->axis[5];
00129             tdxevent.rz += -state->axis[4];
00130             tdxevent.eventcount++;
00131             break;
00132 
00133           case kConnexionCmdHandleButtons:
00134             tdxevent.buttons = state->buttons;
00135             tdxevent.eventcount++;
00136             break;
00137         }
00138       }
00139       break;
00140 
00141     default:
00142 //      printf("Unknown message type\n");
00143       break;
00144   }
00145 }
00146 
00147 static void tdx_clear() {
00148   memset(&tdxevent, 0, sizeof(tdxevent));
00149 }
00150 
00151 static int tdx_enable() {
00152   UInt16 clientID;
00153 
00154   if (InstallConnexionHandlers == NULL) {
00155     msgInfo << "No 3DConnexion driver on this system." << sendmsg;
00156     return -1;
00157   }
00158   OSErr result = InstallConnexionHandlers(tdx_msghandler, 0L, 0L);
00159   if (result != noErr) {
00160     msgInfo << "Unable to register with 3DConnexion driver." << sendmsg;
00161     return -1;
00162   }
00163 
00164 #if 1
00165   // only respond to all events when we have focus
00166   clientID = RegisterConnexionClient(0, executablename,
00167                kConnexionClientModeTakeOver, kConnexionMaskAll);
00168 #else
00169   // respond to all events whether we have focus or not
00170   clientID = RegisterConnexionClient(kConnexionClientWildcard, NULL,
00171                kConnexionClientModeTakeOver, kConnexionMaskAll);
00172 #endif
00173 
00174   tdxevent.enabled = 1;
00175   tdxevent.client = clientID;
00176 
00177   return 0;
00178 }
00179 
00180 static int tdx_detach() {
00181   if (tdxevent.enabled) {
00182     UnregisterConnexionClient(tdxevent.client);
00183     CleanupConnexionHandlers();
00184   }
00185   tdx_clear();
00186 }
00187 
00188 int tdx_getstatus(int &tx, int &ty, int &tz, int &rx, int &ry, int &rz, int &buttons) {
00189   int eventcount = tdxevent.eventcount;
00190 
00191   tx = tdxevent.tx; 
00192   ty = tdxevent.ty; 
00193   tz = tdxevent.tz; 
00194   rx = tdxevent.rx; 
00195   ry = tdxevent.ry; 
00196   rz = tdxevent.rz; 
00197   buttons = tdxevent.buttons;
00198   
00199   tdxevent.tx = 0;
00200   tdxevent.ty = 0;
00201   tdxevent.tz = 0;
00202   tdxevent.rx = 0;
00203   tdxevent.ry = 0;
00204   tdxevent.rz = 0;
00205   tdxevent.eventcount = 0;
00206   
00207   return eventcount;
00208 }
00209 
00210 #endif
00211 
00212 
00213 
00214 // constructor
00215 Spaceball::Spaceball(VMDApp *vmdapp)
00216         : UIObject(vmdapp) {
00217 
00218 #if defined(VMDTDCONNEXION) && (defined(ARCH_MACOSX) || defined(ARCH_MACOSXX86))
00219   // Enable input from MacOS X 3DConnexion API
00220   tdx_clear();
00221   if (tdx_enable() == 0)
00222     msgInfo << "3DConnexion SpaceNavigator enabled." << sendmsg;
00223 #endif
00224 
00225 #if defined(VMDLIBSBALL) && !defined(VMDSPACEWARE)
00226   sball=NULL; // zero it out to begin with
00227   if (getenv("VMDSPACEBALLPORT") != NULL) {
00228     msgInfo << "Opening Spaceball (direct I/O) on port: " 
00229             << getenv("VMDSPACEBALLPORT") << sendmsg;
00230     sball = sball_open(getenv("VMDSPACEBALLPORT"));
00231     if (sball == NULL) 
00232       msgErr << "Failed to open Spaceball direct I/O serial port, device disabled." 
00233              << sendmsg; 
00234   }
00235 #endif
00236 
00237   buttonDown = 0;
00238 
00239   reset();
00240 }
00241 
00242 
00243 // destructor
00244 Spaceball::~Spaceball(void) {
00245 #if defined(VMDTDCONNEXION) && (defined(ARCH_MACOSX) || defined(ARCH_MACOSXX86))
00246   // Disable input from MacOS X 3DConnextion API
00247   tdx_detach();
00248 #endif
00249 
00250 #if defined(VMDLIBSBALL) && !defined(VMDSPACEWARE)
00251   if (sball != NULL)
00252     sball_close(sball);
00253 #endif
00254 }
00255 
00256 
00258    
00259 // reset the spaceball to original settings
00260 void Spaceball::reset(void) {
00261   // set the default motion mode and initialize button state
00262   move_mode(NORMAL);
00263 
00264   // set global spaceball sensitivity within VMD
00265   // (this has no effect on underlying driver sensitivity settings)
00266   set_sensitivity(1.0f);
00267 
00268   // set the null region to a small value initially
00269   set_null_region(16);
00270 
00271   // set the maximum animate stride allowed to 20 by default
00272   set_max_stride(20);
00273 
00274   // set the default translation and rotation increments
00275   // these really need to be made user modifiable at runtime
00276   transInc = 1.0f / 25000.0f;
00277     rotInc = 1.0f /   200.0f;
00278   scaleInc = 1.0f / 25000.0f;
00279    animInc = 1.0f /    75.0f;
00280 }
00281 
00282 // update the display due to a command being executed.  Return whether
00283 // any action was taken on this command.
00284 // Arguments are the command type, command object, and the 
00285 // success of the command (T or F).
00286 int Spaceball::act_on_command(int type, Command *cmd) {
00287   return FALSE; // we don't take any commands presently
00288 }
00289 
00290 
00291 // check for an event, and queue it if found.  Return TRUE if an event
00292 // was generated.
00293 int Spaceball::check_event(void) {
00294   int tx, ty, tz, rx, ry, rz, buttons;
00295   int buttonchanged;
00296   int win_event=FALSE;
00297   int direct_event=FALSE;
00298 
00299   // explicitly initialize event state variables
00300   rx=ry=rz=tx=ty=tz=buttons=0;
00301 
00302 #if defined(VMDTDCONNEXION) && (defined(ARCH_MACOSX) || defined(ARCH_MACOSXX86))
00303   if (tdx_getstatus(tx, ty, tz, rx, ry, rz, buttons))
00304     win_event = TRUE;
00305 #else
00306   if (app->display->spaceball(&rx, &ry, &rz, &tx, &ty, &tz, &buttons)) 
00307     win_event = TRUE;
00308 #endif
00309 
00310 
00311 #if defined(VMDLIBSBALL)
00312   // combine direct spaceball events together with window-system events
00313   if (sball != NULL) {
00314     int rx2, ry2, rz2, tx2, ty2, tz2, buttons2;
00315     if (sball_getstatus(sball, &tx2, &ty2, &tz2, &rx2, &ry2, &rz2, &buttons2)) {
00316       direct_event = TRUE;
00317       rx += rx2;
00318       ry += ry2;
00319       rz += rz2;
00320       tx += tx2; 
00321       ty += ty2; 
00322       tz += tz2; 
00323       buttons |= buttons2;
00324     }
00325   }
00326 #endif
00327 
00328   if (!win_event && !direct_event)
00329     return FALSE; // no events to report
00330 
00331   // find which buttons changed state
00332   buttonchanged = buttons ^ buttonDown; 
00333 
00334   // if the user presses button 1, reset the view, a very very very
00335   // important feature to have implemented early on... ;-)
00336 #if defined(VMDLIBSBALL)  && !defined(VMDSPACEWARE)
00337   if (((buttonchanged & SBALL_BUTTON_1) && (buttons & SBALL_BUTTON_1)) ||
00338       ((buttonchanged & SBALL_BUTTON_LEFT) && (buttons & SBALL_BUTTON_LEFT))){
00339 #else 
00340 // #elif!defined(VMDLIBSBALL) && defined(VMDSPACEWARE)
00341   if ((buttonchanged & 2) && (buttons & 2)) {
00342 #endif
00343 
00344     app->scene_resetview();
00345     msgInfo << "Spaceball reset view orientation" << sendmsg;
00346   }
00347 
00348   // Toggle between the different modes
00349 #if   defined(VMDLIBSBALL)  &&  !defined(VMDSPACEWARE)
00350   if (((buttonchanged & SBALL_BUTTON_2) && (buttons & SBALL_BUTTON_2)) ||
00351       ((buttonchanged & SBALL_BUTTON_RIGHT) && (buttons & SBALL_BUTTON_RIGHT))) {
00352 #else
00353 //#elif !defined(VMDLIBSBALL) &&  defined(VMDSPACEWARE)
00354   if ((buttonchanged & 4) && (buttons & 4)) {
00355 #endif
00356 
00357     switch (moveMode) {
00358       case NORMAL:
00359         move_mode(MAXAXIS);
00360         msgInfo << "Spaceball set to dominant axis rotation/translation mode" << sendmsg;
00361         break;   
00362 
00363       case MAXAXIS:
00364         move_mode(SCALING);
00365         msgInfo << "Spaceball set to scaling mode" << sendmsg;
00366         break;   
00367 
00368       case SCALING:
00369         move_mode(ANIMATE);
00370         msgInfo << "Spaceball set to animate mode" << sendmsg;
00371         break;   
00372 
00373       case ANIMATE:
00374         move_mode(TRACKER);
00375         msgInfo << "Spaceball set to tracker mode" << sendmsg;
00376         break;   
00377 
00378       case TRACKER:
00379         move_mode(USER);
00380         msgInfo << "Spaceball set to user mode" << sendmsg;
00381         break;   
00382 
00383       default: 
00384         move_mode(NORMAL);
00385         msgInfo << "Spaceball set to rotation/translation mode" << sendmsg;
00386         break;
00387     }
00388   }
00389 
00390   // if the user presses button 3 through N, run a User command
00391 #if defined(VMDLIBSBALL)  &&  !defined(VMDSPACEWARE)
00392   if ((buttonchanged & SBALL_BUTTON_3) && (buttons & SBALL_BUTTON_3)) {
00393     runcommand(new UserKeyEvent('3', (int) DisplayDevice::AUX));
00394   }
00395   if ((buttonchanged & SBALL_BUTTON_4) && (buttons & SBALL_BUTTON_4)) {
00396     runcommand(new UserKeyEvent('4', (int) DisplayDevice::AUX));
00397   }
00398   if ((buttonchanged & SBALL_BUTTON_5) && (buttons & SBALL_BUTTON_5)) {
00399     runcommand(new UserKeyEvent('5', (int) DisplayDevice::AUX));
00400   }
00401   if ((buttonchanged & SBALL_BUTTON_6) && (buttons & SBALL_BUTTON_6)) {
00402     runcommand(new UserKeyEvent('6', (int) DisplayDevice::AUX));
00403   }
00404   if ((buttonchanged & SBALL_BUTTON_7) && (buttons & SBALL_BUTTON_7)) {
00405     runcommand(new UserKeyEvent('7', (int) DisplayDevice::AUX));
00406   }
00407   if ((buttonchanged & SBALL_BUTTON_8) && (buttons & SBALL_BUTTON_8)) {
00408     runcommand(new UserKeyEvent('8', (int) DisplayDevice::AUX));
00409   }
00410 //#elif !defined(VMDLIBSBALL) &&  defined(VMDSPACEWARE)
00411 #else
00412   if ((buttonchanged & 8) && (buttons & 8)) {
00413     runcommand(new UserKeyEvent('3', (int) DisplayDevice::AUX));
00414   }
00415   if ((buttonchanged & 16) && (buttons & 16)) {
00416     runcommand(new UserKeyEvent('4', (int) DisplayDevice::AUX));
00417   }
00418   if ((buttonchanged & 32) && (buttons & 32)) {
00419     runcommand(new UserKeyEvent('5', (int) DisplayDevice::AUX));
00420   }
00421   if ((buttonchanged & 64) && (buttons & 64)) {
00422     runcommand(new UserKeyEvent('6', (int) DisplayDevice::AUX));
00423   }
00424   if ((buttonchanged & 128) && (buttons & 128)) {
00425     runcommand(new UserKeyEvent('7', (int) DisplayDevice::AUX));
00426   }
00427   if ((buttonchanged & 256) && (buttons & 256)) {
00428     runcommand(new UserKeyEvent('8', (int) DisplayDevice::AUX));
00429   }
00430 #endif
00431 
00432   // get absolute values of axis forces for use in 
00433   // null region processing and min/max comparison tests
00434   int atx, aty, atz, arx, ary, arz;
00435   atx = abs(tx);
00436   aty = abs(ty);
00437   atz = abs(tz);
00438   arx = abs(rx);
00439   ary = abs(ry);
00440   arz = abs(rz);
00441 
00442 
00443   // perform null region processing
00444   if (atx > null_region) {
00445     tx = ((tx > 0) ? (tx - null_region) : (tx + null_region));
00446   } else {
00447     tx = 0;
00448   }
00449   if (aty > null_region) {
00450     ty = ((ty > 0) ? (ty - null_region) : (ty + null_region));
00451   } else {
00452     ty = 0;
00453   }
00454   if (atz > null_region) {
00455     tz = ((tz > 0) ? (tz - null_region) : (tz + null_region));
00456   } else {
00457     tz = 0;
00458   }
00459   if (arx > null_region) {
00460     rx = ((rx > 0) ? (rx - null_region) : (rx + null_region));
00461   } else {
00462     rx = 0;
00463   }
00464   if (ary > null_region) {
00465     ry = ((ry > 0) ? (ry - null_region) : (ry + null_region));
00466   } else {
00467     ry = 0;
00468   }
00469   if (arz > null_region) {
00470     rz = ((rz > 0) ? (rz - null_region) : (rz + null_region));
00471   } else {
00472     rz = 0;
00473   }
00474 
00475 
00476   // Ignore null motion events since some versions of the Windows 
00477   // Spaceball driver emit a constant stream of null motion event
00478   // packets which would otherwise cause continuous redraws, pegging the 
00479   // CPU and GPU at maximum load.
00480   if ((arx+ary+arz+atx+aty+atz) > 0) {
00481     float ftx = tx * sensitivity;
00482     float fty = ty * sensitivity;
00483     float ftz = tz * sensitivity;
00484     float frx = rx * sensitivity;
00485     float fry = ry * sensitivity;
00486     float frz = rz * sensitivity;
00487     char rmaxaxis = 'x';
00488     float rmaxval = 0.0f;
00489     float tmaxval = 0.0f;
00490     float tmaxvec[3] = { 0.0f, 0.0f, 0.0f };
00491     tmaxvec[0] = tmaxvec[1] = tmaxvec[2] = 0.0f;
00492 
00493     switch(moveMode) {
00494       case NORMAL:
00495         // Z-axis rotation/trans have to be negated in order to please VMD...
00496         app->scene_rotate_by(frx * rotInc, 'x');
00497         app->scene_rotate_by(fry * rotInc, 'y');
00498         app->scene_rotate_by(-frz * rotInc, 'z');
00499         if (app->display_projection_is_perspective()) {
00500           app->scene_translate_by(ftx * transInc, fty * transInc, -ftz * transInc);
00501         } else {
00502           app->scene_scale_by((1.0f + scaleInc * -ftz > 0.0f) ? 
00503                                1.0f + scaleInc * -ftz : 0.0f);
00504           app->scene_translate_by(ftx * transInc, fty * transInc, 0);
00505         }
00506  
00507         break;
00508 
00509       case MAXAXIS:
00510         // Z-axis rotation/trans have to be negated in order to please VMD...
00511         // find dominant rotation axis
00512         if (arx > ary) {
00513           if (arx > arz) {
00514             rmaxaxis = 'x';
00515             rmaxval = frx; 
00516           } else {
00517             rmaxaxis = 'z';
00518             rmaxval = -frz; 
00519           }
00520         } else {     
00521           if (ary > arz) {
00522             rmaxaxis = 'y';
00523             rmaxval = fry; 
00524           } else {
00525             rmaxaxis = 'z';
00526             rmaxval = -frz; 
00527           }
00528         }
00529 
00530         // find dominant translation axis
00531         if (atx > aty) {
00532           if (atx > atz) {
00533             tmaxval = ftx;
00534             tmaxvec[0] = ftx; 
00535           } else {
00536             tmaxval = ftz;
00537             tmaxvec[2] = ftz; 
00538           }
00539         } else {     
00540           if (aty > atz) {
00541             tmaxval = ty;
00542             tmaxvec[1] = fty; 
00543           } else {
00544             tmaxval = tz;
00545             tmaxvec[2] = ftz; 
00546           }
00547        }
00548 
00549        // determine whether to rotate or translate
00550        if (fabs(rmaxval) > fabs(tmaxval)) {
00551          app->scene_rotate_by(rmaxval * rotInc, rmaxaxis);
00552        } else {
00553          app->scene_translate_by(tmaxvec[0] * transInc, 
00554                                  tmaxvec[1] * transInc, 
00555                                 -tmaxvec[2] * transInc);
00556        }
00557        break;
00558 
00559       case SCALING:
00560         app->scene_scale_by((1.0f + scaleInc * ftz > 0.0f) ? 
00561                              1.0f + scaleInc * ftz : 0.0f);
00562         break;
00563 
00564       case ANIMATE:
00565         // if we got a non-zero input, update the VMD animation state
00566         if (abs(ry) > 0) {
00567 #if 1
00568           // exponential input scaling
00569           float speed = fabs(exp(fabs((fabs(fry) * animInc) / 1.7))) - 1.0;
00570 #else
00571           // linear input scaling
00572           float speed = fabs(fry) * animInc;
00573 #endif
00574 
00575           if (speed > 0) {
00576             if (speed < 1.0) 
00577               app->animation_set_speed(speed);
00578             else
00579               app->animation_set_speed(1.0f);
00580  
00581             int stride = 1;
00582             if (fabs(speed - 1.0) > (double) maxstride)
00583               stride = maxstride;
00584             else
00585               stride = 1 + (int) fabs(speed-1.0);
00586             if (stride < 1)
00587               stride = 1; 
00588             app->animation_set_stride(stride);
00589  
00590             // -ry is turned to the right, like a typical shuttle/jog control
00591             if (fry < 0) 
00592               app->animation_set_dir(Animation::ANIM_FORWARD1);
00593             else
00594               app->animation_set_dir(Animation::ANIM_REVERSE1);
00595           } else {
00596             app->animation_set_dir(Animation::ANIM_PAUSE);
00597             app->animation_set_speed(1.0f);
00598           }
00599         } else {
00600           app->animation_set_dir(Animation::ANIM_PAUSE);
00601           app->animation_set_speed(1.0f);
00602         }
00603         break;
00604 
00605       case TRACKER:
00606         trtx = ftx;
00607         trty = fty;
00608         trtz = ftz;
00609         trrx = frx;
00610         trry = fry;
00611         trrz = frz;
00612         trbuttons = buttons;
00613         break;
00614 
00615       case USER:
00616         // inform TCL
00617         app->commandQueue->runcommand(new SpaceballEvent(ftx, fty, ftz, 
00618                                                          frx, fry, frz, 
00619                                                          buttons));
00620         break;
00621     }
00622   }
00623 
00624   // update button status for next time through
00625   buttonDown = buttons;
00626 
00627   return TRUE;
00628 }
00629 
00630 
00632 
00633 const char* Spaceball::get_mode_str(MoveMode mm) {
00634   const char* modestr;
00635 
00636   switch (mm) {
00637     default:
00638     case NORMAL:      modestr = "rotate";     break;
00639     case MAXAXIS:     modestr = "maxaxis";    break;
00640     case SCALING:     modestr = "scale";      break;
00641     case ANIMATE:     modestr = "animate";    break;
00642     case TRACKER:     modestr = "tracker";    break;
00643     case USER:        modestr = "user";       break;
00644   }
00645 
00646   return modestr;
00647 }
00648 
00649 
00650 void Spaceball::get_tracker_status(float &tx, float &ty, float &tz,
00651                                    float &rx, float &ry, float &rz, 
00652                                    int &buttons) {
00653   tx =  trtx * transInc;
00654   ty =  trty * transInc;
00655   tz = -trtz * transInc;
00656   rx =  trrx * rotInc;
00657   ry =  trry * rotInc;
00658   rz = -trrz * rotInc;
00659   buttons = trbuttons;
00660 }
00661 
00662 
00663 // set the Spaceball move mode to the given state; return success
00664 int Spaceball::move_mode(MoveMode mm) {
00665   // change the mode now
00666   moveMode = mm;
00667 
00669   if (moveMode != TRACKER) {
00670     trtx=trty=trtz=trrx=trry=trrz=0.0f; 
00671     trbuttons=0;
00672   }
00673 
00674   return TRUE; // report success
00675 }
00676 
00677 
00678 

Generated on Mon Oct 13 01:27:53 2008 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002