llviewerjoystick.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llviewerjoystick.h"
00035 
00036 #include "llviewercontrol.h"
00037 #include "llviewerwindow.h"
00038 #include "llviewercamera.h"
00039 #include "llappviewer.h"
00040 #include "llkeyboard.h"
00041 #include "lltoolmgr.h"
00042 #include "llselectmgr.h"
00043 #include "llviewermenu.h"
00044 #include "llagent.h"
00045 #include "llfocusmgr.h"
00046 
00047 
00048 // ----------------------------------------------------------------------------
00049 // Constants
00050 
00051 #define  X_I    1
00052 #define  Y_I    2
00053 #define  Z_I    0
00054 #define RX_I    4
00055 #define RY_I    5
00056 #define RZ_I    3
00057 
00058 // flycam translations in build mode should be reduced
00059 const F32 BUILDMODE_FLYCAM_T_SCALE = 3.f;
00060 
00061 F32  LLViewerJoystick::sLastDelta[] = {0,0,0,0,0,0,0};
00062 F32  LLViewerJoystick::sDelta[] = {0,0,0,0,0,0,0};
00063 
00064 // These constants specify the maximum absolute value coming in from the device.
00065 // HACK ALERT! the value of MAX_JOYSTICK_INPUT_VALUE is not arbitrary as it 
00066 // should be.  It has to be equal to 3000 because the SpaceNavigator on Windows 
00067 // refuses to respond to the DirectInput SetProperty call; it always returns 
00068 // values in the [-3000, 3000] range.
00069 #define MAX_SPACENAVIGATOR_INPUT  3000.0f
00070 #define MAX_JOYSTICK_INPUT_VALUE  MAX_SPACENAVIGATOR_INPUT
00071 
00072 // -----------------------------------------------------------------------------
00073 void LLViewerJoystick::updateEnabled(bool autoenable)
00074 {
00075         if (mDriverState == JDS_UNINITIALIZED)
00076         {
00077                 gSavedSettings.setBOOL("JoystickEnabled", FALSE );
00078         }
00079         else
00080         {
00081                 if (isLikeSpaceNavigator() && autoenable)
00082                 {
00083                         gSavedSettings.setBOOL("JoystickEnabled", TRUE );
00084                 }
00085         }
00086         if (!gSavedSettings.getBOOL("JoystickEnabled"))
00087         {
00088                 mOverrideCamera = FALSE;
00089         }
00090 }
00091 
00092 void LLViewerJoystick::setOverrideCamera(bool val)
00093 {
00094         if (!gSavedSettings.getBOOL("JoystickEnabled"))
00095         {
00096                 mOverrideCamera = FALSE;
00097         }
00098         else
00099         {
00100                 mOverrideCamera = val;
00101         }
00102 }
00103 
00104 // -----------------------------------------------------------------------------
00105 #if LIB_NDOF
00106 NDOF_HotPlugResult LLViewerJoystick::HotPlugAddCallback(NDOF_Device *dev)
00107 {
00108         NDOF_HotPlugResult res = NDOF_DISCARD_HOTPLUGGED;
00109         LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
00110         if (joystick->mDriverState == JDS_UNINITIALIZED)
00111         {
00112         llinfos << "HotPlugAddCallback: will use device:" << llendl;
00113                 ndof_dump(dev);
00114                 joystick->mNdofDev = dev;
00115         joystick->mDriverState = JDS_INITIALIZED;
00116         res = NDOF_KEEP_HOTPLUGGED;
00117         }
00118         joystick->updateEnabled(true);
00119     return res;
00120 }
00121 #endif
00122 
00123 // -----------------------------------------------------------------------------
00124 #if LIB_NDOF
00125 void LLViewerJoystick::HotPlugRemovalCallback(NDOF_Device *dev)
00126 {
00127         LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
00128         if (joystick->mNdofDev == dev)
00129         {
00130         llinfos << "HotPlugRemovalCallback: joystick->mNdofDev=" 
00131                                 << joystick->mNdofDev << "; removed device:" << llendl;
00132                 ndof_dump(dev);
00133                 joystick->mDriverState = JDS_UNINITIALIZED;
00134         }
00135         joystick->updateEnabled(true);
00136 }
00137 #endif
00138 
00139 // -----------------------------------------------------------------------------
00140 LLViewerJoystick::LLViewerJoystick()
00141 :       mDriverState(JDS_UNINITIALIZED),
00142         mNdofDev(NULL),
00143         mResetFlag(false),
00144         mCameraUpdated(true),
00145         mOverrideCamera(false)
00146 {
00147         for (int i = 0; i < 6; i++)
00148         {
00149                 mAxes[i] = sDelta[i] = sLastDelta[i] = 0.0f;
00150         }
00151         
00152         memset(mBtn, 0, sizeof(mBtn));
00153 
00154         // factor in bandwidth? bandwidth = gViewerStats->mKBitStat
00155         mPerfScale = 4000.f / gSysCPU.getMhz();
00156 }
00157 
00158 // -----------------------------------------------------------------------------
00159 LLViewerJoystick::~LLViewerJoystick()
00160 {
00161         if (mDriverState == JDS_INITIALIZED)
00162         {
00163                 terminate();
00164         }
00165 }
00166 
00167 // -----------------------------------------------------------------------------
00168 void LLViewerJoystick::init(bool autoenable)
00169 {
00170 #if LIB_NDOF
00171         static bool libinit = false;
00172         mDriverState = JDS_INITIALIZING;
00173 
00174         if (libinit == false)
00175         {
00176                 // Note: The HotPlug callbacks are not actually getting called on Windows
00177                 if (ndof_libinit(HotPlugAddCallback, 
00178                                                  HotPlugRemovalCallback, 
00179                                                  NULL))
00180                 {
00181                         mDriverState = JDS_UNINITIALIZED;
00182                 }
00183                 else
00184                 {
00185                         // NB: ndof_libinit succeeds when there's no device
00186                         libinit = true;
00187 
00188                         // allocate memory once for an eventual device
00189                         mNdofDev = ndof_create();
00190                 }
00191         }
00192 
00193         if (libinit)
00194         {
00195                 if (mNdofDev)
00196                 {
00197                         // Different joysticks will return different ranges of raw values.
00198                         // Since we want to handle every device in the same uniform way, 
00199                         // we initialize the mNdofDev struct and we set the range 
00200                         // of values we would like to receive. 
00201                         // 
00202                         // HACK: On Windows, libndofdev passes our range to DI with a 
00203                         // SetProperty call. This works but with one notable exception, the
00204                         // SpaceNavigator, who doesn't seem to care about the SetProperty
00205                         // call. In theory, we should handle this case inside libndofdev. 
00206                         // However, the range we're setting here is arbitrary anyway, 
00207                         // so let's just use the SpaceNavigator range for our purposes. 
00208                         mNdofDev->axes_min = (long)-MAX_JOYSTICK_INPUT_VALUE;
00209                         mNdofDev->axes_max = (long)+MAX_JOYSTICK_INPUT_VALUE;
00210 
00211                         // libndofdev could be used to return deltas.  Here we choose to
00212                         // just have the absolute values instead.
00213                         mNdofDev->absolute = 1;
00214 
00215                         // init & use the first suitable NDOF device found on the USB chain
00216                         if (ndof_init_first(mNdofDev, NULL))
00217                         {
00218                                 mDriverState = JDS_UNINITIALIZED;
00219                                 llwarns << "ndof_init_first FAILED" << llendl;
00220                         }
00221                         else
00222                         {
00223                                 mDriverState = JDS_INITIALIZED;
00224                         }
00225                 }
00226                 else
00227                 {
00228                         mDriverState = JDS_UNINITIALIZED;
00229                 }
00230         }
00231 
00232         // Autoenable the joystick for recognized devices if nothing was connected previously
00233         if (!autoenable)
00234         {
00235                 autoenable = gSavedSettings.getString("JoystickInitialized").empty() ? true : false;
00236         }
00237         updateEnabled(autoenable);
00238         
00239         if (mDriverState == JDS_INITIALIZED)
00240         {
00241                 // A Joystick device is plugged in
00242                 if (isLikeSpaceNavigator())
00243                 {
00244                         // It's a space navigator, we have defaults for it.
00245                         if (gSavedSettings.getString("JoystickInitialized") != "SpaceNavigator")
00246                         {
00247                                 // Only set the defaults if we haven't already (in case they were overridden)
00248                                 setSNDefaults();
00249                                 gSavedSettings.setString("JoystickInitialized", "SpaceNavigator");
00250                         }
00251                 }
00252                 else
00253                 {
00254                         // It's not a Space Navigator
00255                         gSavedSettings.setString("JoystickInitialized", "UnknownDevice");
00256                 }
00257         }
00258         else
00259         {
00260                 // No device connected, don't change any settings
00261         }
00262         
00263         llinfos << "ndof: mDriverState=" << mDriverState << "; mNdofDev=" 
00264                         << mNdofDev << "; libinit=" << libinit << llendl;
00265 #endif
00266 }
00267 
00268 // -----------------------------------------------------------------------------
00269 void LLViewerJoystick::terminate()
00270 {
00271 #if LIB_NDOF
00272 
00273         ndof_libcleanup();
00274         llinfos << "Terminated connection with NDOF device." << llendl;
00275 
00276 #endif
00277 }
00278 
00279 // -----------------------------------------------------------------------------
00280 void LLViewerJoystick::updateStatus()
00281 {
00282 #if LIB_NDOF
00283 
00284         ndof_update(mNdofDev);
00285 
00286         for (int i=0; i<6; i++)
00287         {
00288                 mAxes[i] = (F32) mNdofDev->axes[i] / mNdofDev->axes_max;
00289         }
00290 
00291         for (int i=0; i<16; i++)
00292         {
00293                 mBtn[i] = mNdofDev->buttons[i];
00294         }
00295         
00296 #endif
00297 }
00298 
00299 // -----------------------------------------------------------------------------
00300 F32 LLViewerJoystick::getJoystickAxis(U32 axis) const
00301 {
00302         if (axis < 6)
00303         {
00304                 return mAxes[axis];
00305         }
00306         return 0.f;
00307 }
00308 
00309 // -----------------------------------------------------------------------------
00310 U32 LLViewerJoystick::getJoystickButton(U32 button) const
00311 {
00312         if (button < 16)
00313         {
00314                 return mBtn[button];
00315         }
00316         return 0;
00317 }
00318 
00319 // -----------------------------------------------------------------------------
00320 void LLViewerJoystick::agentJump()
00321 {
00322     gAgent.moveUp(1);
00323 }
00324 
00325 // -----------------------------------------------------------------------------
00326 void LLViewerJoystick::agentSlide(F32 inc)
00327 {
00328         if (inc < 0)
00329         {
00330                 gAgent.moveLeft(1);
00331         }
00332         else if (inc > 0)
00333         {
00334                 gAgent.moveLeft(-1);
00335         }
00336 }
00337 
00338 // -----------------------------------------------------------------------------
00339 void LLViewerJoystick::agentPush(F32 inc)
00340 {
00341         if (inc < 0)                            // forward
00342         {
00343                 gAgent.moveAt(1, false);
00344         }
00345         else if (inc > 0)                       // backward
00346         {
00347                 gAgent.moveAt(-1, false);
00348         }
00349 }
00350 
00351 // -----------------------------------------------------------------------------
00352 void LLViewerJoystick::agentFly(F32 inc)
00353 {
00354         if (inc < 0)
00355         {
00356                 if (gAgent.getFlying())
00357                 {
00358                         gAgent.moveUp(1);
00359                 }
00360                 else
00361                 {
00362                         gAgent.setFlying(true);
00363                 }
00364         }
00365         else if (inc > 0)
00366         {
00367                 // crouch
00368                 gAgent.moveUp(-1);
00369         }
00370 }
00371 
00372 // -----------------------------------------------------------------------------
00373 void LLViewerJoystick::agentRotate(F32 pitch_inc, F32 yaw_inc)
00374 {
00375         LLQuaternion new_rot;
00376         pitch_inc = gAgent.clampPitchToLimits(-pitch_inc);
00377         const LLQuaternion qx(pitch_inc, gAgent.getLeftAxis());
00378         const LLQuaternion qy(-yaw_inc, gAgent.getReferenceUpVector());
00379         new_rot.setQuat(qx * qy);
00380         gAgent.rotate(new_rot);
00381 }
00382 
00383 // -----------------------------------------------------------------------------
00384 void LLViewerJoystick::resetDeltas(S32 axis[], bool flycam_and_build_mode)
00385 {
00386         for (U32 i = 0; i < 6; i++)
00387         {
00388                 sLastDelta[i] = -mAxes[axis[i]];
00389                 sDelta[i] = 0.f;
00390         }
00391 
00392         if (flycam_and_build_mode)
00393         {
00394                 sLastDelta[X_I] /= BUILDMODE_FLYCAM_T_SCALE;
00395                 sLastDelta[Y_I] /= BUILDMODE_FLYCAM_T_SCALE;
00396                 sLastDelta[Z_I] /= BUILDMODE_FLYCAM_T_SCALE;
00397         }
00398 
00399         sLastDelta[6] = sDelta[6] = 0.f;
00400         mResetFlag = false;
00401 }
00402 
00403 // -----------------------------------------------------------------------------
00404 void LLViewerJoystick::moveObjects(bool reset)
00405 {
00406         static bool toggle_send_to_sim = false;
00407 
00408         if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED
00409                 || !gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickBuildEnabled"))
00410         {
00411                 return;
00412         }
00413 
00414         S32 axis[] = 
00415         {
00416                 gSavedSettings.getS32("JoystickAxis0"),
00417                 gSavedSettings.getS32("JoystickAxis1"),
00418                 gSavedSettings.getS32("JoystickAxis2"),
00419                 gSavedSettings.getS32("JoystickAxis3"),
00420                 gSavedSettings.getS32("JoystickAxis4"),
00421                 gSavedSettings.getS32("JoystickAxis5"),
00422         };
00423 
00424         if (reset || mResetFlag)
00425         {
00426                 resetDeltas(axis);
00427                 return;
00428         }
00429 
00430         F32 axis_scale[] =
00431         {
00432                 gSavedSettings.getF32("BuildAxisScale0"),
00433                 gSavedSettings.getF32("BuildAxisScale1"),
00434                 gSavedSettings.getF32("BuildAxisScale2"),
00435                 gSavedSettings.getF32("BuildAxisScale3"),
00436                 gSavedSettings.getF32("BuildAxisScale4"),
00437                 gSavedSettings.getF32("BuildAxisScale5"),
00438         };
00439 
00440         F32 dead_zone[] =
00441         {
00442                 gSavedSettings.getF32("BuildAxisDeadZone0"),
00443                 gSavedSettings.getF32("BuildAxisDeadZone1"),
00444                 gSavedSettings.getF32("BuildAxisDeadZone2"),
00445                 gSavedSettings.getF32("BuildAxisDeadZone3"),
00446                 gSavedSettings.getF32("BuildAxisDeadZone4"),
00447                 gSavedSettings.getF32("BuildAxisDeadZone5"),
00448         };
00449 
00450         F32 cur_delta[6];
00451         F32 time = gFrameIntervalSeconds;
00452 
00453         // avoid making ridicously big movements if there's a big drop in fps 
00454         if (time > .2f)
00455         {
00456                 time = .2f;
00457         }
00458 
00459         // max feather is 32
00460         F32 feather = gSavedSettings.getF32("BuildFeathering"); 
00461         bool is_zero = true, absolute = gSavedSettings.getBOOL("Cursor3D");
00462         
00463         for (U32 i = 0; i < 6; i++)
00464         {
00465                 cur_delta[i] = -mAxes[axis[i]];
00466                 F32 tmp = cur_delta[i];
00467                 if (absolute)
00468                 {
00469                         cur_delta[i] = cur_delta[i] - sLastDelta[i];
00470                 }
00471                 sLastDelta[i] = tmp;
00472                 is_zero = is_zero && (cur_delta[i] == 0.f);
00473                         
00474                 if (cur_delta[i] > 0)
00475                 {
00476                         cur_delta[i] = llmax(cur_delta[i]-dead_zone[i], 0.f);
00477                 }
00478                 else
00479                 {
00480                         cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f);
00481                 }
00482                 cur_delta[i] *= axis_scale[i];
00483                 
00484                 if (!absolute)
00485                 {
00486                         cur_delta[i] *= time;
00487                 }
00488 
00489                 sDelta[i] = sDelta[i] + (cur_delta[i]-sDelta[i])*time*feather;
00490         }
00491 
00492         U32 upd_type = UPD_NONE;
00493         LLVector3 v;
00494     
00495         if (!is_zero)
00496         {
00497                 if (sDelta[0] || sDelta[1] || sDelta[2])
00498                 {
00499                         upd_type |= UPD_POSITION;
00500                         v.setVec(sDelta[0], sDelta[1], sDelta[2]);
00501                 }
00502                 
00503                 if (sDelta[3] || sDelta[4] || sDelta[5])
00504                 {
00505                         upd_type |= UPD_ROTATION;
00506                 }
00507                                 
00508                 // the selection update could fail, so we won't send 
00509                 if (LLSelectMgr::getInstance()->selectionMove(v, sDelta[3],sDelta[4],sDelta[5], upd_type))
00510                 {
00511                         toggle_send_to_sim = true;
00512                 }
00513         }
00514         else if (toggle_send_to_sim)
00515         {
00516                 LLSelectMgr::getInstance()->sendSelectionMove();
00517                 toggle_send_to_sim = false;
00518         }
00519 }
00520 
00521 // -----------------------------------------------------------------------------
00522 void LLViewerJoystick::moveAvatar(bool reset)
00523 {
00524         if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED
00525                 || !gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickAvatarEnabled"))
00526         {
00527                 return;
00528         }
00529 
00530         S32 axis[] = 
00531         {
00532                 // [1 0 2 4  3  5]
00533                 // [Z X Y RZ RX RY]
00534                 gSavedSettings.getS32("JoystickAxis0"),
00535                 gSavedSettings.getS32("JoystickAxis1"),
00536                 gSavedSettings.getS32("JoystickAxis2"),
00537                 gSavedSettings.getS32("JoystickAxis3"),
00538                 gSavedSettings.getS32("JoystickAxis4"),
00539                 gSavedSettings.getS32("JoystickAxis5")
00540         };
00541 
00542         if (reset || mResetFlag)
00543         {
00544                 resetDeltas(axis);
00545                 if (reset)
00546                 {
00547                         // Note: moving the agent triggers agent camera mode;
00548                         //  don't do this every time we set mResetFlag (e.g. because we gained focus)
00549                         gAgent.moveAt(0, true);
00550                 }
00551                 return;
00552         }
00553 
00554         if (mBtn[1] == 1)
00555     {
00556                 agentJump();
00557                 return;
00558     }
00559 
00560         F32 axis_scale[] =
00561         {
00562                 gSavedSettings.getF32("AvatarAxisScale0"),
00563                 gSavedSettings.getF32("AvatarAxisScale1"),
00564                 gSavedSettings.getF32("AvatarAxisScale2"),
00565                 gSavedSettings.getF32("AvatarAxisScale3"),
00566                 gSavedSettings.getF32("AvatarAxisScale4"),
00567                 gSavedSettings.getF32("AvatarAxisScale5")
00568         };
00569 
00570         F32 dead_zone[] =
00571         {
00572                 gSavedSettings.getF32("AvatarAxisDeadZone0"),
00573                 gSavedSettings.getF32("AvatarAxisDeadZone1"),
00574                 gSavedSettings.getF32("AvatarAxisDeadZone2"),
00575                 gSavedSettings.getF32("AvatarAxisDeadZone3"),
00576                 gSavedSettings.getF32("AvatarAxisDeadZone4"),
00577                 gSavedSettings.getF32("AvatarAxisDeadZone5")
00578         };
00579 
00580         // time interval in seconds between this frame and the previous
00581         F32 time = gFrameIntervalSeconds;
00582 
00583         // avoid making ridicously big movements if there's a big drop in fps 
00584         if (time > .2f)
00585         {
00586                 time = .2f;
00587         }
00588 
00589         // note: max feather is 32.0
00590         F32 feather = gSavedSettings.getF32("AvatarFeathering"); 
00591         
00592         F32 cur_delta[6];
00593         F32 val, dom_mov = 0.f;
00594         U32 dom_axis = Z_I;
00595 #if LIB_NDOF
00596     bool absolute = (gSavedSettings.getBOOL("Cursor3D") && mNdofDev->absolute);
00597 #else
00598     bool absolute = false;
00599 #endif
00600         // remove dead zones and determine biggest movement on the joystick 
00601         for (U32 i = 0; i < 6; i++)
00602         {
00603                 cur_delta[i] = -mAxes[axis[i]];
00604                 if (absolute)
00605                 {
00606                         F32 tmp = cur_delta[i];
00607                         cur_delta[i] = cur_delta[i] - sLastDelta[i];
00608                         sLastDelta[i] = tmp;
00609                 }
00610 
00611                 if (cur_delta[i] > 0)
00612                 {
00613                         cur_delta[i] = llmax(cur_delta[i]-dead_zone[i], 0.f);
00614                 }
00615                 else
00616                 {
00617                         cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f);
00618                 }
00619 
00620                 // we don't care about Roll (RZ) and Z is calculated after the loop
00621         if (i != Z_I && i != RZ_I)
00622                 {
00623                         // find out the axis with the biggest joystick motion
00624                         val = fabs(cur_delta[i]);
00625                         if (val > dom_mov)
00626                         {
00627                                 dom_axis = i;
00628                                 dom_mov = val;
00629                         }
00630                 }
00631         }
00632 
00633         // forward|backward movements overrule the real dominant movement if 
00634         // they're bigger than its 20%. This is what you want cos moving forward
00635         // is what you do most. We also added a special (even more lenient) case 
00636         // for RX|RY to allow walking while pitching n' turning
00637         if (fabs(cur_delta[Z_I]) > .2f * dom_mov
00638                 || ((dom_axis == RX_I || dom_axis == RY_I) 
00639                         && fabs(cur_delta[Z_I]) > .05f * dom_mov))
00640     {
00641                 dom_axis = Z_I;
00642         }
00643 
00644         sDelta[X_I] = -cur_delta[X_I] * axis_scale[X_I];
00645         sDelta[Y_I] = -cur_delta[Y_I] * axis_scale[Y_I];
00646         sDelta[Z_I] = -cur_delta[Z_I] * axis_scale[Z_I];
00647         cur_delta[RX_I] *= -axis_scale[RX_I] * mPerfScale;
00648         cur_delta[RY_I] *= -axis_scale[RY_I] * mPerfScale;
00649                 
00650         if (!absolute)
00651         {
00652                 cur_delta[RX_I] *= time;
00653                 cur_delta[RY_I] *= time;
00654         }
00655         sDelta[RX_I] += (cur_delta[RX_I] - sDelta[RX_I]) * time * feather;
00656         sDelta[RY_I] += (cur_delta[RY_I] - sDelta[RY_I]) * time * feather;
00657         
00658     switch (dom_axis)
00659     {
00660         case X_I:                                         // move sideways
00661                         agentSlide(sDelta[X_I]);
00662             break;
00663         
00664         case Z_I:                                         // forward/back
00665                 {
00666             agentPush(sDelta[Z_I]);
00667             
00668             if (fabs(sDelta[Y_I])  > .1f)
00669                         {
00670                                 agentFly(sDelta[Y_I]);
00671                         }
00672                 
00673                         // too many rotations during walking can be confusing, so apply
00674                         // the deadzones one more time (quick & dirty), at 50%|30% power
00675                         F32 eff_rx = .3f * dead_zone[RX_I];
00676                         F32 eff_ry = .3f * dead_zone[RY_I];
00677                 
00678                         if (sDelta[RX_I] > 0)
00679                         {
00680                                 eff_rx = llmax(sDelta[RX_I] - eff_rx, 0.f);
00681                         }
00682                         else
00683                         {
00684                                 eff_rx = llmin(sDelta[RX_I] + eff_rx, 0.f);
00685                         }
00686 
00687                         if (sDelta[RY_I] > 0)
00688                         {
00689                                 eff_ry = llmax(sDelta[RY_I] - eff_ry, 0.f);
00690                         }
00691                         else
00692                         {
00693                                 eff_ry = llmin(sDelta[RY_I] + eff_ry, 0.f);
00694                         }
00695                         
00696                         
00697                         if (fabs(eff_rx) > 0.f || fabs(eff_ry) > 0.f)
00698                         {
00699                                 if (gAgent.getFlying())
00700                                 {
00701                                         agentRotate(eff_rx, eff_ry);
00702                                 }
00703                                 else
00704                                 {
00705                                         agentRotate(eff_rx, 2.f * eff_ry);
00706                                 }
00707                         }
00708             break;
00709                 }   
00710         case Y_I:                                          // up/crouch
00711             agentFly(sDelta[Y_I]);
00712             break;
00713             
00714         case RX_I:                                         // pitch
00715         case RY_I:                                         // turn
00716                         agentRotate(sDelta[RX_I], sDelta[RY_I]);
00717             break;
00718         // case RZ_I: roll is unused in avatar mode
00719     }// switch
00720 }
00721 
00722 // -----------------------------------------------------------------------------
00723 void LLViewerJoystick::moveFlycam(bool reset)
00724 {
00725         static LLQuaternion             sFlycamRotation;
00726         static LLVector3                sFlycamPosition;
00727         static F32                      sFlycamZoom;
00728         
00729         if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED
00730                 || !gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickFlycamEnabled"))
00731         {
00732                 return;
00733         }
00734 
00735         S32 axis[] = 
00736         {
00737                 gSavedSettings.getS32("JoystickAxis0"),
00738                 gSavedSettings.getS32("JoystickAxis1"),
00739                 gSavedSettings.getS32("JoystickAxis2"),
00740                 gSavedSettings.getS32("JoystickAxis3"),
00741                 gSavedSettings.getS32("JoystickAxis4"),
00742                 gSavedSettings.getS32("JoystickAxis5"),
00743                 gSavedSettings.getS32("JoystickAxis6")
00744         };
00745 
00746         bool in_build_mode = LLToolMgr::getInstance()->inBuildMode();
00747         if (reset || mResetFlag)
00748         {
00749                 sFlycamPosition = LLViewerCamera::getInstance()->getOrigin();
00750                 sFlycamRotation = LLViewerCamera::getInstance()->getQuaternion();
00751                 sFlycamZoom = LLViewerCamera::getInstance()->getView();
00752                 
00753                 resetDeltas(axis, in_build_mode);
00754 
00755                 return;
00756         }
00757 
00758         F32 axis_scale[] =
00759         {
00760                 gSavedSettings.getF32("FlycamAxisScale0"),
00761                 gSavedSettings.getF32("FlycamAxisScale1"),
00762                 gSavedSettings.getF32("FlycamAxisScale2"),
00763                 gSavedSettings.getF32("FlycamAxisScale3"),
00764                 gSavedSettings.getF32("FlycamAxisScale4"),
00765                 gSavedSettings.getF32("FlycamAxisScale5"),
00766                 gSavedSettings.getF32("FlycamAxisScale6")
00767         };
00768 
00769         F32 dead_zone[] =
00770         {
00771                 gSavedSettings.getF32("FlycamAxisDeadZone0"),
00772                 gSavedSettings.getF32("FlycamAxisDeadZone1"),
00773                 gSavedSettings.getF32("FlycamAxisDeadZone2"),
00774                 gSavedSettings.getF32("FlycamAxisDeadZone3"),
00775                 gSavedSettings.getF32("FlycamAxisDeadZone4"),
00776                 gSavedSettings.getF32("FlycamAxisDeadZone5"),
00777                 gSavedSettings.getF32("FlycamAxisDeadZone6")
00778         };
00779 
00780         F32 time = gFrameIntervalSeconds;
00781 
00782         // avoid making ridicously big movements if there's a big drop in fps 
00783         if (time > .2f)
00784         {
00785                 time = .2f;
00786         }
00787 
00788         F32 cur_delta[7];
00789         F32 feather = gSavedSettings.getF32("FlycamFeathering");
00790         bool absolute = gSavedSettings.getBOOL("Cursor3D");
00791 
00792         for (U32 i = 0; i < 7; i++)
00793         {
00794                 cur_delta[i] = -getJoystickAxis(axis[i]);
00795 
00796                 // we need smaller camera movements in build mode
00797                 if (in_build_mode)
00798                 {
00799                         if (i == X_I || i == Y_I || i == Z_I)
00800                         {
00801                                 cur_delta[i] /= BUILDMODE_FLYCAM_T_SCALE;
00802                         }
00803                 }
00804 
00805                 F32 tmp = cur_delta[i];
00806                 if (absolute)
00807                 {
00808                         cur_delta[i] = cur_delta[i] - sLastDelta[i];
00809                 }
00810                 sLastDelta[i] = tmp;
00811 
00812                 if (cur_delta[i] > 0)
00813                 {
00814                         cur_delta[i] = llmax(cur_delta[i]-dead_zone[i], 0.f);
00815                 }
00816                 else
00817                 {
00818                         cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f);
00819                 }
00820                 cur_delta[i] *= axis_scale[i];
00821                 
00822                 if (!absolute)
00823                 {
00824                         cur_delta[i] *= time;
00825                 }
00826 
00827                 sDelta[i] = sDelta[i] + (cur_delta[i]-sDelta[i])*time*feather;
00828         }
00829         
00830         sFlycamPosition += LLVector3(sDelta) * sFlycamRotation;
00831 
00832         LLMatrix3 rot_mat(sDelta[3], sDelta[4], sDelta[5]);
00833         sFlycamRotation = LLQuaternion(rot_mat)*sFlycamRotation;
00834 
00835         if (gSavedSettings.getBOOL("AutoLeveling"))
00836         {
00837                 LLMatrix3 level(sFlycamRotation);
00838 
00839                 LLVector3 x = LLVector3(level.mMatrix[0]);
00840                 LLVector3 y = LLVector3(level.mMatrix[1]);
00841                 LLVector3 z = LLVector3(level.mMatrix[2]);
00842 
00843                 y.mV[2] = 0.f;
00844                 y.normVec();
00845 
00846                 level.setRows(x,y,z);
00847                 level.orthogonalize();
00848                                 
00849                 LLQuaternion quat(level);
00850                 sFlycamRotation = nlerp(llmin(feather*time,1.f), sFlycamRotation, quat);
00851         }
00852 
00853         if (gSavedSettings.getBOOL("ZoomDirect"))
00854         {
00855                 sFlycamZoom = sLastDelta[6]*axis_scale[6]+dead_zone[6];
00856         }
00857         else
00858         {
00859                 sFlycamZoom += sDelta[6];
00860         }
00861 
00862         LLMatrix3 mat(sFlycamRotation);
00863 
00864         LLViewerCamera::getInstance()->setView(sFlycamZoom);
00865         LLViewerCamera::getInstance()->setOrigin(sFlycamPosition);
00866         LLViewerCamera::getInstance()->mXAxis = LLVector3(mat.mMatrix[0]);
00867         LLViewerCamera::getInstance()->mYAxis = LLVector3(mat.mMatrix[1]);
00868         LLViewerCamera::getInstance()->mZAxis = LLVector3(mat.mMatrix[2]);
00869 }
00870 
00871 // -----------------------------------------------------------------------------
00872 bool LLViewerJoystick::toggleFlycam()
00873 {
00874         if (!gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickFlycamEnabled"))
00875         {
00876                 return false;
00877         }
00878         mOverrideCamera = !mOverrideCamera;
00879         if (mOverrideCamera)
00880         {
00881                 moveFlycam(true);
00882         }
00883         else if (!LLToolMgr::getInstance()->inBuildMode())
00884         {
00885                 moveAvatar(true);
00886         }
00887         else 
00888         {
00889                 // we are in build mode, exiting from the flycam mode: since we are 
00890                 // going to keep the flycam POV for the main camera until the avatar
00891                 // moves, we need to track this situation.
00892                 setCameraNeedsUpdate(false);
00893                 setNeedsReset(true);
00894         }
00895         return true;
00896 }
00897 
00898 void LLViewerJoystick::scanJoystick()
00899 {
00900         if (mDriverState != JDS_INITIALIZED || !gSavedSettings.getBOOL("JoystickEnabled"))
00901         {
00902                 return;
00903         }
00904 
00905 #if LL_WINDOWS
00906         // On windows, the flycam is updated syncronously with a timer, so there is
00907         // no need to update the status of the joystick here.
00908         if (!mOverrideCamera)
00909 #endif
00910         updateStatus();
00911 
00912         static long toggle_flycam = 0;
00913 
00914         if (mBtn[0] == 1)
00915     {
00916                 if (mBtn[0] != toggle_flycam)
00917                 {
00918                         toggle_flycam = toggleFlycam() ? 1 : 0;
00919                 }
00920         }
00921         else
00922         {
00923                 toggle_flycam = 0;
00924         }
00925         
00926         if (!mOverrideCamera && !LLToolMgr::getInstance()->inBuildMode())
00927         {
00928                 moveAvatar();
00929         }
00930 }
00931 
00932 // -----------------------------------------------------------------------------
00933 std::string LLViewerJoystick::getDescription()
00934 {
00935         std::string res;
00936 #if LIB_NDOF
00937         if (mDriverState == JDS_INITIALIZED && mNdofDev)
00938         {
00939                 res = ll_safe_string(mNdofDev->product);
00940         }
00941 #endif
00942         return res;
00943 }
00944 
00945 bool LLViewerJoystick::isLikeSpaceNavigator() const
00946 {
00947 #if LIB_NDOF    
00948         return (isJoystickInitialized() 
00949                         && (strncmp(mNdofDev->product, "SpaceNavigator", 14) == 0
00950                                 || strncmp(mNdofDev->product, "SpaceExplorer", 13) == 0
00951                                 || strncmp(mNdofDev->product, "SpaceTraveler", 13) == 0
00952                                 || strncmp(mNdofDev->product, "SpacePilot", 10) == 0));
00953 #else
00954         return false;
00955 #endif
00956 }
00957 
00958 // -----------------------------------------------------------------------------
00959 void LLViewerJoystick::setSNDefaults()
00960 {
00961 #if LL_DARWIN 
00962 #define kPlatformScale  20.f
00963 #else
00964 #define kPlatformScale  1.f
00965 #endif
00966         
00967         //gViewerWindow->alertXml("CacheWillClear");
00968         llinfos << "restoring SpaceNavigator defaults..." << llendl;
00969         
00970         gSavedSettings.setS32("JoystickAxis0", 1); // z (at)
00971         gSavedSettings.setS32("JoystickAxis1", 0); // x (slide)
00972         gSavedSettings.setS32("JoystickAxis2", 2); // y (up)
00973         gSavedSettings.setS32("JoystickAxis3", 4); // pitch
00974         gSavedSettings.setS32("JoystickAxis4", 3); // roll 
00975         gSavedSettings.setS32("JoystickAxis5", 5); // yaw
00976         gSavedSettings.setS32("JoystickAxis6", -1);
00977         
00978 #if LL_DARWIN
00979         // The SpaceNavigator doesn't act as a 3D cursor on OS X. 
00980         gSavedSettings.setBOOL("Cursor3D", false);
00981 #else
00982         gSavedSettings.setBOOL("Cursor3D", true);
00983 #endif
00984         gSavedSettings.setBOOL("AutoLeveling", true);
00985         gSavedSettings.setBOOL("ZoomDirect", false);
00986         
00987         gSavedSettings.setF32("AvatarAxisScale0", 1.f);
00988         gSavedSettings.setF32("AvatarAxisScale1", 1.f);
00989         gSavedSettings.setF32("AvatarAxisScale2", 1.f);
00990         gSavedSettings.setF32("AvatarAxisScale4", .1f * kPlatformScale);
00991         gSavedSettings.setF32("AvatarAxisScale5", .1f * kPlatformScale);
00992         gSavedSettings.setF32("AvatarAxisScale3", 0.f * kPlatformScale);
00993         gSavedSettings.setF32("BuildAxisScale1", .3f * kPlatformScale);
00994         gSavedSettings.setF32("BuildAxisScale2", .3f * kPlatformScale);
00995         gSavedSettings.setF32("BuildAxisScale0", .3f * kPlatformScale);
00996         gSavedSettings.setF32("BuildAxisScale4", .3f * kPlatformScale);
00997         gSavedSettings.setF32("BuildAxisScale5", .3f * kPlatformScale);
00998         gSavedSettings.setF32("BuildAxisScale3", .3f * kPlatformScale);
00999         gSavedSettings.setF32("FlycamAxisScale1", 2.f * kPlatformScale);
01000         gSavedSettings.setF32("FlycamAxisScale2", 2.f * kPlatformScale);
01001         gSavedSettings.setF32("FlycamAxisScale0", 2.1f * kPlatformScale);
01002         gSavedSettings.setF32("FlycamAxisScale4", .1f * kPlatformScale);
01003         gSavedSettings.setF32("FlycamAxisScale5", .15f * kPlatformScale);
01004         gSavedSettings.setF32("FlycamAxisScale3", 0.f * kPlatformScale);
01005         gSavedSettings.setF32("FlycamAxisScale6", 0.f * kPlatformScale);
01006         
01007         gSavedSettings.setF32("AvatarAxisDeadZone0", .1f);
01008         gSavedSettings.setF32("AvatarAxisDeadZone1", .1f);
01009         gSavedSettings.setF32("AvatarAxisDeadZone2", .1f);
01010         gSavedSettings.setF32("AvatarAxisDeadZone3", 1.f);
01011         gSavedSettings.setF32("AvatarAxisDeadZone4", .02f);
01012         gSavedSettings.setF32("AvatarAxisDeadZone5", .01f);
01013         gSavedSettings.setF32("BuildAxisDeadZone0", .01f);
01014         gSavedSettings.setF32("BuildAxisDeadZone1", .01f);
01015         gSavedSettings.setF32("BuildAxisDeadZone2", .01f);
01016         gSavedSettings.setF32("BuildAxisDeadZone3", .01f);
01017         gSavedSettings.setF32("BuildAxisDeadZone4", .01f);
01018         gSavedSettings.setF32("BuildAxisDeadZone5", .01f);
01019         gSavedSettings.setF32("FlycamAxisDeadZone0", .01f);
01020         gSavedSettings.setF32("FlycamAxisDeadZone1", .01f);
01021         gSavedSettings.setF32("FlycamAxisDeadZone2", .01f);
01022         gSavedSettings.setF32("FlycamAxisDeadZone3", .01f);
01023         gSavedSettings.setF32("FlycamAxisDeadZone4", .01f);
01024         gSavedSettings.setF32("FlycamAxisDeadZone5", .01f);
01025         gSavedSettings.setF32("FlycamAxisDeadZone6", 1.f);
01026         
01027         gSavedSettings.setF32("AvatarFeathering", 6.f);
01028         gSavedSettings.setF32("BuildFeathering", 12.f);
01029         gSavedSettings.setF32("FlycamFeathering", 5.f);
01030 }

Generated on Fri May 16 08:34:10 2008 for SecondLife by  doxygen 1.5.5