00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
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"
00063
00064
00065
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
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
00081
00082
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;
00093 UInt16 client;
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
00105 static tdx_data tdxevent;
00106
00107
00108
00109
00110
00111
00112
00113
00114
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
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
00166 clientID = RegisterConnexionClient(0, executablename,
00167 kConnexionClientModeTakeOver, kConnexionMaskAll);
00168 #else
00169
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
00215 Spaceball::Spaceball(VMDApp *vmdapp)
00216 : UIObject(vmdapp) {
00217
00218 #if defined(VMDTDCONNEXION) && (defined(ARCH_MACOSX) || defined(ARCH_MACOSXX86))
00219
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;
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
00244 Spaceball::~Spaceball(void) {
00245 #if defined(VMDTDCONNEXION) && (defined(ARCH_MACOSX) || defined(ARCH_MACOSXX86))
00246
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
00260 void Spaceball::reset(void) {
00261
00262 move_mode(NORMAL);
00263
00264
00265
00266 set_sensitivity(1.0f);
00267
00268
00269 set_null_region(16);
00270
00271
00272 set_max_stride(20);
00273
00274
00275
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
00283
00284
00285
00286 int Spaceball::act_on_command(int type, Command *cmd) {
00287 return FALSE;
00288 }
00289
00290
00291
00292
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
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
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;
00330
00331
00332 buttonchanged = buttons ^ buttonDown;
00333
00334
00335
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
00341 if ((buttonchanged & 2) && (buttons & 2)) {
00342 #endif
00343
00344 app->scene_resetview();
00345 msgInfo << "Spaceball reset view orientation" << sendmsg;
00346 }
00347
00348
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
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
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
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
00433
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
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
00477
00478
00479
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
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
00511
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
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
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
00566 if (abs(ry) > 0) {
00567 #if 1
00568
00569 float speed = fabs(exp(fabs((fabs(fry) * animInc) / 1.7))) - 1.0;
00570 #else
00571
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
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
00617 app->commandQueue->runcommand(new SpaceballEvent(ftx, fty, ftz,
00618 frx, fry, frz,
00619 buttons));
00620 break;
00621 }
00622 }
00623
00624
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
00664 int Spaceball::move_mode(MoveMode mm) {
00665
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;
00675 }
00676
00677
00678