PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llviewerjoystick.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1161 lines | 891 code | 145 blank | 125 comment | 184 complexity | 7525d3f8d89bc502c42653702c8f30db MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llviewerjoystick.cpp
  3. * @brief Joystick / NDOF device functionality.
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llviewerjoystick.h"
  28. #include "llviewercontrol.h"
  29. #include "llviewerwindow.h"
  30. #include "llviewercamera.h"
  31. #include "llappviewer.h"
  32. #include "llkeyboard.h"
  33. #include "lltoolmgr.h"
  34. #include "llselectmgr.h"
  35. #include "llviewermenu.h"
  36. #include "llagent.h"
  37. #include "llagentcamera.h"
  38. #include "llfocusmgr.h"
  39. // ----------------------------------------------------------------------------
  40. // Constants
  41. #define X_I 1
  42. #define Y_I 2
  43. #define Z_I 0
  44. #define RX_I 4
  45. #define RY_I 5
  46. #define RZ_I 3
  47. F32 LLViewerJoystick::sLastDelta[] = {0,0,0,0,0,0,0};
  48. F32 LLViewerJoystick::sDelta[] = {0,0,0,0,0,0,0};
  49. // These constants specify the maximum absolute value coming in from the device.
  50. // HACK ALERT! the value of MAX_JOYSTICK_INPUT_VALUE is not arbitrary as it
  51. // should be. It has to be equal to 3000 because the SpaceNavigator on Windows
  52. // refuses to respond to the DirectInput SetProperty call; it always returns
  53. // values in the [-3000, 3000] range.
  54. #define MAX_SPACENAVIGATOR_INPUT 3000.0f
  55. #define MAX_JOYSTICK_INPUT_VALUE MAX_SPACENAVIGATOR_INPUT
  56. // -----------------------------------------------------------------------------
  57. void LLViewerJoystick::updateEnabled(bool autoenable)
  58. {
  59. if (mDriverState == JDS_UNINITIALIZED)
  60. {
  61. gSavedSettings.setBOOL("JoystickEnabled", FALSE );
  62. }
  63. else
  64. {
  65. if (isLikeSpaceNavigator() && autoenable)
  66. {
  67. gSavedSettings.setBOOL("JoystickEnabled", TRUE );
  68. }
  69. }
  70. if (!gSavedSettings.getBOOL("JoystickEnabled"))
  71. {
  72. mOverrideCamera = FALSE;
  73. }
  74. }
  75. void LLViewerJoystick::setOverrideCamera(bool val)
  76. {
  77. if (!gSavedSettings.getBOOL("JoystickEnabled"))
  78. {
  79. mOverrideCamera = FALSE;
  80. }
  81. else
  82. {
  83. mOverrideCamera = val;
  84. }
  85. if (mOverrideCamera)
  86. {
  87. gAgentCamera.changeCameraToDefault();
  88. }
  89. }
  90. // -----------------------------------------------------------------------------
  91. #if LIB_NDOF
  92. NDOF_HotPlugResult LLViewerJoystick::HotPlugAddCallback(NDOF_Device *dev)
  93. {
  94. NDOF_HotPlugResult res = NDOF_DISCARD_HOTPLUGGED;
  95. LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
  96. if (joystick->mDriverState == JDS_UNINITIALIZED)
  97. {
  98. llinfos << "HotPlugAddCallback: will use device:" << llendl;
  99. ndof_dump(dev);
  100. joystick->mNdofDev = dev;
  101. joystick->mDriverState = JDS_INITIALIZED;
  102. res = NDOF_KEEP_HOTPLUGGED;
  103. }
  104. joystick->updateEnabled(true);
  105. return res;
  106. }
  107. #endif
  108. // -----------------------------------------------------------------------------
  109. #if LIB_NDOF
  110. void LLViewerJoystick::HotPlugRemovalCallback(NDOF_Device *dev)
  111. {
  112. LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
  113. if (joystick->mNdofDev == dev)
  114. {
  115. llinfos << "HotPlugRemovalCallback: joystick->mNdofDev="
  116. << joystick->mNdofDev << "; removed device:" << llendl;
  117. ndof_dump(dev);
  118. joystick->mDriverState = JDS_UNINITIALIZED;
  119. }
  120. joystick->updateEnabled(true);
  121. }
  122. #endif
  123. // -----------------------------------------------------------------------------
  124. LLViewerJoystick::LLViewerJoystick()
  125. : mDriverState(JDS_UNINITIALIZED),
  126. mNdofDev(NULL),
  127. mResetFlag(false),
  128. mCameraUpdated(true),
  129. mOverrideCamera(false),
  130. mJoystickRun(0)
  131. {
  132. for (int i = 0; i < 6; i++)
  133. {
  134. mAxes[i] = sDelta[i] = sLastDelta[i] = 0.0f;
  135. }
  136. memset(mBtn, 0, sizeof(mBtn));
  137. // factor in bandwidth? bandwidth = gViewerStats->mKBitStat
  138. mPerfScale = 4000.f / gSysCPU.getMHz(); // hmm. why?
  139. }
  140. // -----------------------------------------------------------------------------
  141. LLViewerJoystick::~LLViewerJoystick()
  142. {
  143. if (mDriverState == JDS_INITIALIZED)
  144. {
  145. terminate();
  146. }
  147. }
  148. // -----------------------------------------------------------------------------
  149. void LLViewerJoystick::init(bool autoenable)
  150. {
  151. #if LIB_NDOF
  152. static bool libinit = false;
  153. mDriverState = JDS_INITIALIZING;
  154. if (libinit == false)
  155. {
  156. // Note: The HotPlug callbacks are not actually getting called on Windows
  157. if (ndof_libinit(HotPlugAddCallback,
  158. HotPlugRemovalCallback,
  159. NULL))
  160. {
  161. mDriverState = JDS_UNINITIALIZED;
  162. }
  163. else
  164. {
  165. // NB: ndof_libinit succeeds when there's no device
  166. libinit = true;
  167. // allocate memory once for an eventual device
  168. mNdofDev = ndof_create();
  169. }
  170. }
  171. if (libinit)
  172. {
  173. if (mNdofDev)
  174. {
  175. // Different joysticks will return different ranges of raw values.
  176. // Since we want to handle every device in the same uniform way,
  177. // we initialize the mNdofDev struct and we set the range
  178. // of values we would like to receive.
  179. //
  180. // HACK: On Windows, libndofdev passes our range to DI with a
  181. // SetProperty call. This works but with one notable exception, the
  182. // SpaceNavigator, who doesn't seem to care about the SetProperty
  183. // call. In theory, we should handle this case inside libndofdev.
  184. // However, the range we're setting here is arbitrary anyway,
  185. // so let's just use the SpaceNavigator range for our purposes.
  186. mNdofDev->axes_min = (long)-MAX_JOYSTICK_INPUT_VALUE;
  187. mNdofDev->axes_max = (long)+MAX_JOYSTICK_INPUT_VALUE;
  188. // libndofdev could be used to return deltas. Here we choose to
  189. // just have the absolute values instead.
  190. mNdofDev->absolute = 1;
  191. // init & use the first suitable NDOF device found on the USB chain
  192. if (ndof_init_first(mNdofDev, NULL))
  193. {
  194. mDriverState = JDS_UNINITIALIZED;
  195. llwarns << "ndof_init_first FAILED" << llendl;
  196. }
  197. else
  198. {
  199. mDriverState = JDS_INITIALIZED;
  200. }
  201. }
  202. else
  203. {
  204. mDriverState = JDS_UNINITIALIZED;
  205. }
  206. }
  207. // Autoenable the joystick for recognized devices if nothing was connected previously
  208. if (!autoenable)
  209. {
  210. autoenable = gSavedSettings.getString("JoystickInitialized").empty() ? true : false;
  211. }
  212. updateEnabled(autoenable);
  213. if (mDriverState == JDS_INITIALIZED)
  214. {
  215. // A Joystick device is plugged in
  216. if (isLikeSpaceNavigator())
  217. {
  218. // It's a space navigator, we have defaults for it.
  219. if (gSavedSettings.getString("JoystickInitialized") != "SpaceNavigator")
  220. {
  221. // Only set the defaults if we haven't already (in case they were overridden)
  222. setSNDefaults();
  223. gSavedSettings.setString("JoystickInitialized", "SpaceNavigator");
  224. }
  225. }
  226. else
  227. {
  228. // It's not a Space Navigator
  229. gSavedSettings.setString("JoystickInitialized", "UnknownDevice");
  230. }
  231. }
  232. else
  233. {
  234. // No device connected, don't change any settings
  235. }
  236. llinfos << "ndof: mDriverState=" << mDriverState << "; mNdofDev="
  237. << mNdofDev << "; libinit=" << libinit << llendl;
  238. #endif
  239. }
  240. // -----------------------------------------------------------------------------
  241. void LLViewerJoystick::terminate()
  242. {
  243. #if LIB_NDOF
  244. ndof_libcleanup();
  245. llinfos << "Terminated connection with NDOF device." << llendl;
  246. mDriverState = JDS_UNINITIALIZED;
  247. #endif
  248. }
  249. // -----------------------------------------------------------------------------
  250. void LLViewerJoystick::updateStatus()
  251. {
  252. #if LIB_NDOF
  253. ndof_update(mNdofDev);
  254. for (int i=0; i<6; i++)
  255. {
  256. mAxes[i] = (F32) mNdofDev->axes[i] / mNdofDev->axes_max;
  257. }
  258. for (int i=0; i<16; i++)
  259. {
  260. mBtn[i] = mNdofDev->buttons[i];
  261. }
  262. #endif
  263. }
  264. // -----------------------------------------------------------------------------
  265. F32 LLViewerJoystick::getJoystickAxis(U32 axis) const
  266. {
  267. if (axis < 6)
  268. {
  269. return mAxes[axis];
  270. }
  271. return 0.f;
  272. }
  273. // -----------------------------------------------------------------------------
  274. U32 LLViewerJoystick::getJoystickButton(U32 button) const
  275. {
  276. if (button < 16)
  277. {
  278. return mBtn[button];
  279. }
  280. return 0;
  281. }
  282. // -----------------------------------------------------------------------------
  283. void LLViewerJoystick::handleRun(F32 inc)
  284. {
  285. // Decide whether to walk or run by applying a threshold, with slight
  286. // hysteresis to avoid oscillating between the two with input spikes.
  287. // Analog speed control would be better, but not likely any time soon.
  288. if (inc > gSavedSettings.getF32("JoystickRunThreshold"))
  289. {
  290. if (1 == mJoystickRun)
  291. {
  292. ++mJoystickRun;
  293. gAgent.setRunning();
  294. gAgent.sendWalkRun(gAgent.getRunning());
  295. }
  296. else if (0 == mJoystickRun)
  297. {
  298. // hysteresis - respond NEXT frame
  299. ++mJoystickRun;
  300. }
  301. }
  302. else
  303. {
  304. if (mJoystickRun > 0)
  305. {
  306. --mJoystickRun;
  307. if (0 == mJoystickRun)
  308. {
  309. gAgent.clearRunning();
  310. gAgent.sendWalkRun(gAgent.getRunning());
  311. }
  312. }
  313. }
  314. }
  315. // -----------------------------------------------------------------------------
  316. void LLViewerJoystick::agentJump()
  317. {
  318. gAgent.moveUp(1);
  319. }
  320. // -----------------------------------------------------------------------------
  321. void LLViewerJoystick::agentSlide(F32 inc)
  322. {
  323. if (inc < 0.f)
  324. {
  325. gAgent.moveLeft(1);
  326. }
  327. else if (inc > 0.f)
  328. {
  329. gAgent.moveLeft(-1);
  330. }
  331. }
  332. // -----------------------------------------------------------------------------
  333. void LLViewerJoystick::agentPush(F32 inc)
  334. {
  335. if (inc < 0.f) // forward
  336. {
  337. gAgent.moveAt(1, false);
  338. }
  339. else if (inc > 0.f) // backward
  340. {
  341. gAgent.moveAt(-1, false);
  342. }
  343. }
  344. // -----------------------------------------------------------------------------
  345. void LLViewerJoystick::agentFly(F32 inc)
  346. {
  347. if (inc < 0.f)
  348. {
  349. if (! (gAgent.getFlying() ||
  350. !gAgent.canFly() ||
  351. gAgent.upGrabbed() ||
  352. !gSavedSettings.getBOOL("AutomaticFly")) )
  353. {
  354. gAgent.setFlying(true);
  355. }
  356. gAgent.moveUp(1);
  357. }
  358. else if (inc > 0.f)
  359. {
  360. // crouch
  361. gAgent.moveUp(-1);
  362. }
  363. }
  364. // -----------------------------------------------------------------------------
  365. void LLViewerJoystick::agentPitch(F32 pitch_inc)
  366. {
  367. if (pitch_inc < 0)
  368. {
  369. gAgent.setControlFlags(AGENT_CONTROL_PITCH_POS);
  370. }
  371. else if (pitch_inc > 0)
  372. {
  373. gAgent.setControlFlags(AGENT_CONTROL_PITCH_NEG);
  374. }
  375. gAgent.pitch(-pitch_inc);
  376. }
  377. // -----------------------------------------------------------------------------
  378. void LLViewerJoystick::agentYaw(F32 yaw_inc)
  379. {
  380. // Cannot steer some vehicles in mouselook if the script grabs the controls
  381. if (gAgentCamera.cameraMouselook() && !gSavedSettings.getBOOL("JoystickMouselookYaw"))
  382. {
  383. gAgent.rotate(-yaw_inc, gAgent.getReferenceUpVector());
  384. }
  385. else
  386. {
  387. if (yaw_inc < 0)
  388. {
  389. gAgent.setControlFlags(AGENT_CONTROL_YAW_POS);
  390. }
  391. else if (yaw_inc > 0)
  392. {
  393. gAgent.setControlFlags(AGENT_CONTROL_YAW_NEG);
  394. }
  395. gAgent.yaw(-yaw_inc);
  396. }
  397. }
  398. // -----------------------------------------------------------------------------
  399. void LLViewerJoystick::resetDeltas(S32 axis[])
  400. {
  401. for (U32 i = 0; i < 6; i++)
  402. {
  403. sLastDelta[i] = -mAxes[axis[i]];
  404. sDelta[i] = 0.f;
  405. }
  406. sLastDelta[6] = sDelta[6] = 0.f;
  407. mResetFlag = false;
  408. }
  409. // -----------------------------------------------------------------------------
  410. void LLViewerJoystick::moveObjects(bool reset)
  411. {
  412. static bool toggle_send_to_sim = false;
  413. if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED
  414. || !gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickBuildEnabled"))
  415. {
  416. return;
  417. }
  418. S32 axis[] =
  419. {
  420. gSavedSettings.getS32("JoystickAxis0"),
  421. gSavedSettings.getS32("JoystickAxis1"),
  422. gSavedSettings.getS32("JoystickAxis2"),
  423. gSavedSettings.getS32("JoystickAxis3"),
  424. gSavedSettings.getS32("JoystickAxis4"),
  425. gSavedSettings.getS32("JoystickAxis5"),
  426. };
  427. if (reset || mResetFlag)
  428. {
  429. resetDeltas(axis);
  430. return;
  431. }
  432. F32 axis_scale[] =
  433. {
  434. gSavedSettings.getF32("BuildAxisScale0"),
  435. gSavedSettings.getF32("BuildAxisScale1"),
  436. gSavedSettings.getF32("BuildAxisScale2"),
  437. gSavedSettings.getF32("BuildAxisScale3"),
  438. gSavedSettings.getF32("BuildAxisScale4"),
  439. gSavedSettings.getF32("BuildAxisScale5"),
  440. };
  441. F32 dead_zone[] =
  442. {
  443. gSavedSettings.getF32("BuildAxisDeadZone0"),
  444. gSavedSettings.getF32("BuildAxisDeadZone1"),
  445. gSavedSettings.getF32("BuildAxisDeadZone2"),
  446. gSavedSettings.getF32("BuildAxisDeadZone3"),
  447. gSavedSettings.getF32("BuildAxisDeadZone4"),
  448. gSavedSettings.getF32("BuildAxisDeadZone5"),
  449. };
  450. F32 cur_delta[6];
  451. F32 time = gFrameIntervalSeconds;
  452. // avoid making ridicously big movements if there's a big drop in fps
  453. if (time > .2f)
  454. {
  455. time = .2f;
  456. }
  457. // max feather is 32
  458. F32 feather = gSavedSettings.getF32("BuildFeathering");
  459. bool is_zero = true, absolute = gSavedSettings.getBOOL("Cursor3D");
  460. for (U32 i = 0; i < 6; i++)
  461. {
  462. cur_delta[i] = -mAxes[axis[i]];
  463. F32 tmp = cur_delta[i];
  464. if (absolute)
  465. {
  466. cur_delta[i] = cur_delta[i] - sLastDelta[i];
  467. }
  468. sLastDelta[i] = tmp;
  469. is_zero = is_zero && (cur_delta[i] == 0.f);
  470. if (cur_delta[i] > 0)
  471. {
  472. cur_delta[i] = llmax(cur_delta[i]-dead_zone[i], 0.f);
  473. }
  474. else
  475. {
  476. cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f);
  477. }
  478. cur_delta[i] *= axis_scale[i];
  479. if (!absolute)
  480. {
  481. cur_delta[i] *= time;
  482. }
  483. sDelta[i] = sDelta[i] + (cur_delta[i]-sDelta[i])*time*feather;
  484. }
  485. U32 upd_type = UPD_NONE;
  486. LLVector3 v;
  487. if (!is_zero)
  488. {
  489. // Clear AFK state if moved beyond the deadzone
  490. if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
  491. {
  492. gAgent.clearAFK();
  493. }
  494. if (sDelta[0] || sDelta[1] || sDelta[2])
  495. {
  496. upd_type |= UPD_POSITION;
  497. v.setVec(sDelta[0], sDelta[1], sDelta[2]);
  498. }
  499. if (sDelta[3] || sDelta[4] || sDelta[5])
  500. {
  501. upd_type |= UPD_ROTATION;
  502. }
  503. // the selection update could fail, so we won't send
  504. if (LLSelectMgr::getInstance()->selectionMove(v, sDelta[3],sDelta[4],sDelta[5], upd_type))
  505. {
  506. toggle_send_to_sim = true;
  507. }
  508. }
  509. else if (toggle_send_to_sim)
  510. {
  511. LLSelectMgr::getInstance()->sendSelectionMove();
  512. toggle_send_to_sim = false;
  513. }
  514. }
  515. // -----------------------------------------------------------------------------
  516. void LLViewerJoystick::moveAvatar(bool reset)
  517. {
  518. if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED
  519. || !gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickAvatarEnabled"))
  520. {
  521. return;
  522. }
  523. S32 axis[] =
  524. {
  525. // [1 0 2 4 3 5]
  526. // [Z X Y RZ RX RY]
  527. gSavedSettings.getS32("JoystickAxis0"),
  528. gSavedSettings.getS32("JoystickAxis1"),
  529. gSavedSettings.getS32("JoystickAxis2"),
  530. gSavedSettings.getS32("JoystickAxis3"),
  531. gSavedSettings.getS32("JoystickAxis4"),
  532. gSavedSettings.getS32("JoystickAxis5")
  533. };
  534. if (reset || mResetFlag)
  535. {
  536. resetDeltas(axis);
  537. if (reset)
  538. {
  539. // Note: moving the agent triggers agent camera mode;
  540. // don't do this every time we set mResetFlag (e.g. because we gained focus)
  541. gAgent.moveAt(0, true);
  542. }
  543. return;
  544. }
  545. bool is_zero = true;
  546. static bool button_held = false;
  547. if (mBtn[1] == 1)
  548. {
  549. // If AutomaticFly is enabled, then button1 merely causes a
  550. // jump (as the up/down axis already controls flying) if on the
  551. // ground, or cease flight if already flying.
  552. // If AutomaticFly is disabled, then button1 toggles flying.
  553. if (gSavedSettings.getBOOL("AutomaticFly"))
  554. {
  555. if (!gAgent.getFlying())
  556. {
  557. gAgent.moveUp(1);
  558. }
  559. else if (!button_held)
  560. {
  561. button_held = true;
  562. gAgent.setFlying(FALSE);
  563. }
  564. }
  565. else if (!button_held)
  566. {
  567. button_held = true;
  568. gAgent.setFlying(!gAgent.getFlying());
  569. }
  570. is_zero = false;
  571. }
  572. else
  573. {
  574. button_held = false;
  575. }
  576. F32 axis_scale[] =
  577. {
  578. gSavedSettings.getF32("AvatarAxisScale0"),
  579. gSavedSettings.getF32("AvatarAxisScale1"),
  580. gSavedSettings.getF32("AvatarAxisScale2"),
  581. gSavedSettings.getF32("AvatarAxisScale3"),
  582. gSavedSettings.getF32("AvatarAxisScale4"),
  583. gSavedSettings.getF32("AvatarAxisScale5")
  584. };
  585. F32 dead_zone[] =
  586. {
  587. gSavedSettings.getF32("AvatarAxisDeadZone0"),
  588. gSavedSettings.getF32("AvatarAxisDeadZone1"),
  589. gSavedSettings.getF32("AvatarAxisDeadZone2"),
  590. gSavedSettings.getF32("AvatarAxisDeadZone3"),
  591. gSavedSettings.getF32("AvatarAxisDeadZone4"),
  592. gSavedSettings.getF32("AvatarAxisDeadZone5")
  593. };
  594. // time interval in seconds between this frame and the previous
  595. F32 time = gFrameIntervalSeconds;
  596. // avoid making ridicously big movements if there's a big drop in fps
  597. if (time > .2f)
  598. {
  599. time = .2f;
  600. }
  601. // note: max feather is 32.0
  602. F32 feather = gSavedSettings.getF32("AvatarFeathering");
  603. F32 cur_delta[6];
  604. F32 val, dom_mov = 0.f;
  605. U32 dom_axis = Z_I;
  606. #if LIB_NDOF
  607. bool absolute = (gSavedSettings.getBOOL("Cursor3D") && mNdofDev->absolute);
  608. #else
  609. bool absolute = false;
  610. #endif
  611. // remove dead zones and determine biggest movement on the joystick
  612. for (U32 i = 0; i < 6; i++)
  613. {
  614. cur_delta[i] = -mAxes[axis[i]];
  615. if (absolute)
  616. {
  617. F32 tmp = cur_delta[i];
  618. cur_delta[i] = cur_delta[i] - sLastDelta[i];
  619. sLastDelta[i] = tmp;
  620. }
  621. if (cur_delta[i] > 0)
  622. {
  623. cur_delta[i] = llmax(cur_delta[i]-dead_zone[i], 0.f);
  624. }
  625. else
  626. {
  627. cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f);
  628. }
  629. // we don't care about Roll (RZ) and Z is calculated after the loop
  630. if (i != Z_I && i != RZ_I)
  631. {
  632. // find out the axis with the biggest joystick motion
  633. val = fabs(cur_delta[i]);
  634. if (val > dom_mov)
  635. {
  636. dom_axis = i;
  637. dom_mov = val;
  638. }
  639. }
  640. is_zero = is_zero && (cur_delta[i] == 0.f);
  641. }
  642. if (!is_zero)
  643. {
  644. // Clear AFK state if moved beyond the deadzone
  645. if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
  646. {
  647. gAgent.clearAFK();
  648. }
  649. setCameraNeedsUpdate(true);
  650. }
  651. // forward|backward movements overrule the real dominant movement if
  652. // they're bigger than its 20%. This is what you want 'cos moving forward
  653. // is what you do most. We also added a special (even more lenient) case
  654. // for RX|RY to allow walking while pitching and turning
  655. if (fabs(cur_delta[Z_I]) > .2f * dom_mov
  656. || ((dom_axis == RX_I || dom_axis == RY_I)
  657. && fabs(cur_delta[Z_I]) > .05f * dom_mov))
  658. {
  659. dom_axis = Z_I;
  660. }
  661. sDelta[X_I] = -cur_delta[X_I] * axis_scale[X_I];
  662. sDelta[Y_I] = -cur_delta[Y_I] * axis_scale[Y_I];
  663. sDelta[Z_I] = -cur_delta[Z_I] * axis_scale[Z_I];
  664. cur_delta[RX_I] *= -axis_scale[RX_I] * mPerfScale;
  665. cur_delta[RY_I] *= -axis_scale[RY_I] * mPerfScale;
  666. if (!absolute)
  667. {
  668. cur_delta[RX_I] *= time;
  669. cur_delta[RY_I] *= time;
  670. }
  671. sDelta[RX_I] += (cur_delta[RX_I] - sDelta[RX_I]) * time * feather;
  672. sDelta[RY_I] += (cur_delta[RY_I] - sDelta[RY_I]) * time * feather;
  673. handleRun((F32) sqrt(sDelta[Z_I]*sDelta[Z_I] + sDelta[X_I]*sDelta[X_I]));
  674. // Allow forward/backward movement some priority
  675. if (dom_axis == Z_I)
  676. {
  677. agentPush(sDelta[Z_I]); // forward/back
  678. if (fabs(sDelta[X_I]) > .1f)
  679. {
  680. agentSlide(sDelta[X_I]); // move sideways
  681. }
  682. if (fabs(sDelta[Y_I]) > .1f)
  683. {
  684. agentFly(sDelta[Y_I]); // up/down & crouch
  685. }
  686. // too many rotations during walking can be confusing, so apply
  687. // the deadzones one more time (quick & dirty), at 50%|30% power
  688. F32 eff_rx = .3f * dead_zone[RX_I];
  689. F32 eff_ry = .3f * dead_zone[RY_I];
  690. if (sDelta[RX_I] > 0)
  691. {
  692. eff_rx = llmax(sDelta[RX_I] - eff_rx, 0.f);
  693. }
  694. else
  695. {
  696. eff_rx = llmin(sDelta[RX_I] + eff_rx, 0.f);
  697. }
  698. if (sDelta[RY_I] > 0)
  699. {
  700. eff_ry = llmax(sDelta[RY_I] - eff_ry, 0.f);
  701. }
  702. else
  703. {
  704. eff_ry = llmin(sDelta[RY_I] + eff_ry, 0.f);
  705. }
  706. if (fabs(eff_rx) > 0.f || fabs(eff_ry) > 0.f)
  707. {
  708. if (gAgent.getFlying())
  709. {
  710. agentPitch(eff_rx);
  711. agentYaw(eff_ry);
  712. }
  713. else
  714. {
  715. agentPitch(eff_rx);
  716. agentYaw(2.f * eff_ry);
  717. }
  718. }
  719. }
  720. else
  721. {
  722. agentSlide(sDelta[X_I]); // move sideways
  723. agentFly(sDelta[Y_I]); // up/down & crouch
  724. agentPush(sDelta[Z_I]); // forward/back
  725. agentPitch(sDelta[RX_I]); // pitch
  726. agentYaw(sDelta[RY_I]); // turn
  727. }
  728. }
  729. // -----------------------------------------------------------------------------
  730. void LLViewerJoystick::moveFlycam(bool reset)
  731. {
  732. static LLQuaternion sFlycamRotation;
  733. static LLVector3 sFlycamPosition;
  734. static F32 sFlycamZoom;
  735. if (!gFocusMgr.getAppHasFocus() || mDriverState != JDS_INITIALIZED
  736. || !gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickFlycamEnabled"))
  737. {
  738. return;
  739. }
  740. S32 axis[] =
  741. {
  742. gSavedSettings.getS32("JoystickAxis0"),
  743. gSavedSettings.getS32("JoystickAxis1"),
  744. gSavedSettings.getS32("JoystickAxis2"),
  745. gSavedSettings.getS32("JoystickAxis3"),
  746. gSavedSettings.getS32("JoystickAxis4"),
  747. gSavedSettings.getS32("JoystickAxis5"),
  748. gSavedSettings.getS32("JoystickAxis6")
  749. };
  750. bool in_build_mode = LLToolMgr::getInstance()->inBuildMode();
  751. if (reset || mResetFlag)
  752. {
  753. sFlycamPosition = LLViewerCamera::getInstance()->getOrigin();
  754. sFlycamRotation = LLViewerCamera::getInstance()->getQuaternion();
  755. sFlycamZoom = LLViewerCamera::getInstance()->getView();
  756. resetDeltas(axis);
  757. return;
  758. }
  759. F32 axis_scale[] =
  760. {
  761. gSavedSettings.getF32("FlycamAxisScale0"),
  762. gSavedSettings.getF32("FlycamAxisScale1"),
  763. gSavedSettings.getF32("FlycamAxisScale2"),
  764. gSavedSettings.getF32("FlycamAxisScale3"),
  765. gSavedSettings.getF32("FlycamAxisScale4"),
  766. gSavedSettings.getF32("FlycamAxisScale5"),
  767. gSavedSettings.getF32("FlycamAxisScale6")
  768. };
  769. F32 dead_zone[] =
  770. {
  771. gSavedSettings.getF32("FlycamAxisDeadZone0"),
  772. gSavedSettings.getF32("FlycamAxisDeadZone1"),
  773. gSavedSettings.getF32("FlycamAxisDeadZone2"),
  774. gSavedSettings.getF32("FlycamAxisDeadZone3"),
  775. gSavedSettings.getF32("FlycamAxisDeadZone4"),
  776. gSavedSettings.getF32("FlycamAxisDeadZone5"),
  777. gSavedSettings.getF32("FlycamAxisDeadZone6")
  778. };
  779. F32 time = gFrameIntervalSeconds;
  780. // avoid making ridiculously big movements if there's a big drop in fps
  781. if (time > .2f)
  782. {
  783. time = .2f;
  784. }
  785. F32 cur_delta[7];
  786. F32 feather = gSavedSettings.getF32("FlycamFeathering");
  787. bool absolute = gSavedSettings.getBOOL("Cursor3D");
  788. bool is_zero = true;
  789. for (U32 i = 0; i < 7; i++)
  790. {
  791. cur_delta[i] = -getJoystickAxis(axis[i]);
  792. F32 tmp = cur_delta[i];
  793. if (absolute)
  794. {
  795. cur_delta[i] = cur_delta[i] - sLastDelta[i];
  796. }
  797. sLastDelta[i] = tmp;
  798. if (cur_delta[i] > 0)
  799. {
  800. cur_delta[i] = llmax(cur_delta[i]-dead_zone[i], 0.f);
  801. }
  802. else
  803. {
  804. cur_delta[i] = llmin(cur_delta[i]+dead_zone[i], 0.f);
  805. }
  806. // We may want to scale camera movements up or down in build mode.
  807. // NOTE: this needs to remain after the deadzone calculation, otherwise
  808. // we have issues with flycam "jumping" when the build dialog is opened/closed -Nyx
  809. if (in_build_mode)
  810. {
  811. if (i == X_I || i == Y_I || i == Z_I)
  812. {
  813. static LLCachedControl<F32> build_mode_scale(gSavedSettings,"FlycamBuildModeScale");
  814. cur_delta[i] *= build_mode_scale;
  815. }
  816. }
  817. cur_delta[i] *= axis_scale[i];
  818. if (!absolute)
  819. {
  820. cur_delta[i] *= time;
  821. }
  822. sDelta[i] = sDelta[i] + (cur_delta[i]-sDelta[i])*time*feather;
  823. is_zero = is_zero && (cur_delta[i] == 0.f);
  824. }
  825. // Clear AFK state if moved beyond the deadzone
  826. if (!is_zero && gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
  827. {
  828. gAgent.clearAFK();
  829. }
  830. sFlycamPosition += LLVector3(sDelta) * sFlycamRotation;
  831. LLMatrix3 rot_mat(sDelta[3], sDelta[4], sDelta[5]);
  832. sFlycamRotation = LLQuaternion(rot_mat)*sFlycamRotation;
  833. if (gSavedSettings.getBOOL("AutoLeveling"))
  834. {
  835. LLMatrix3 level(sFlycamRotation);
  836. LLVector3 x = LLVector3(level.mMatrix[0]);
  837. LLVector3 y = LLVector3(level.mMatrix[1]);
  838. LLVector3 z = LLVector3(level.mMatrix[2]);
  839. y.mV[2] = 0.f;
  840. y.normVec();
  841. level.setRows(x,y,z);
  842. level.orthogonalize();
  843. LLQuaternion quat(level);
  844. sFlycamRotation = nlerp(llmin(feather*time,1.f), sFlycamRotation, quat);
  845. }
  846. if (gSavedSettings.getBOOL("ZoomDirect"))
  847. {
  848. sFlycamZoom = sLastDelta[6]*axis_scale[6]+dead_zone[6];
  849. }
  850. else
  851. {
  852. sFlycamZoom += sDelta[6];
  853. }
  854. LLMatrix3 mat(sFlycamRotation);
  855. LLViewerCamera::getInstance()->setView(sFlycamZoom);
  856. LLViewerCamera::getInstance()->setOrigin(sFlycamPosition);
  857. LLViewerCamera::getInstance()->mXAxis = LLVector3(mat.mMatrix[0]);
  858. LLViewerCamera::getInstance()->mYAxis = LLVector3(mat.mMatrix[1]);
  859. LLViewerCamera::getInstance()->mZAxis = LLVector3(mat.mMatrix[2]);
  860. }
  861. // -----------------------------------------------------------------------------
  862. bool LLViewerJoystick::toggleFlycam()
  863. {
  864. if (!gSavedSettings.getBOOL("JoystickEnabled") || !gSavedSettings.getBOOL("JoystickFlycamEnabled"))
  865. {
  866. mOverrideCamera = false;
  867. return false;
  868. }
  869. if (!mOverrideCamera)
  870. {
  871. gAgentCamera.changeCameraToDefault();
  872. }
  873. if (gAwayTimer.getElapsedTimeF32() > LLAgent::MIN_AFK_TIME)
  874. {
  875. gAgent.clearAFK();
  876. }
  877. mOverrideCamera = !mOverrideCamera;
  878. if (mOverrideCamera)
  879. {
  880. moveFlycam(true);
  881. }
  882. else
  883. {
  884. // Exiting from the flycam mode: since we are going to keep the flycam POV for
  885. // the main camera until the avatar moves, we need to track this situation.
  886. setCameraNeedsUpdate(false);
  887. setNeedsReset(true);
  888. }
  889. return true;
  890. }
  891. void LLViewerJoystick::scanJoystick()
  892. {
  893. if (mDriverState != JDS_INITIALIZED || !gSavedSettings.getBOOL("JoystickEnabled"))
  894. {
  895. return;
  896. }
  897. #if LL_WINDOWS
  898. // On windows, the flycam is updated syncronously with a timer, so there is
  899. // no need to update the status of the joystick here.
  900. if (!mOverrideCamera)
  901. #endif
  902. updateStatus();
  903. // App focus check Needs to happen AFTER updateStatus in case the joystick
  904. // is not centred when the app loses focus.
  905. if (!gFocusMgr.getAppHasFocus())
  906. {
  907. return;
  908. }
  909. static long toggle_flycam = 0;
  910. if (mBtn[0] == 1)
  911. {
  912. if (mBtn[0] != toggle_flycam)
  913. {
  914. toggle_flycam = toggleFlycam() ? 1 : 0;
  915. }
  916. }
  917. else
  918. {
  919. toggle_flycam = 0;
  920. }
  921. if (!mOverrideCamera && !(LLToolMgr::getInstance()->inBuildMode() && gSavedSettings.getBOOL("JoystickBuildEnabled")))
  922. {
  923. moveAvatar();
  924. }
  925. }
  926. // -----------------------------------------------------------------------------
  927. std::string LLViewerJoystick::getDescription()
  928. {
  929. std::string res;
  930. #if LIB_NDOF
  931. if (mDriverState == JDS_INITIALIZED && mNdofDev)
  932. {
  933. res = ll_safe_string(mNdofDev->product);
  934. }
  935. #endif
  936. return res;
  937. }
  938. bool LLViewerJoystick::isLikeSpaceNavigator() const
  939. {
  940. #if LIB_NDOF
  941. return (isJoystickInitialized()
  942. && (strncmp(mNdofDev->product, "SpaceNavigator", 14) == 0
  943. || strncmp(mNdofDev->product, "SpaceExplorer", 13) == 0
  944. || strncmp(mNdofDev->product, "SpaceTraveler", 13) == 0
  945. || strncmp(mNdofDev->product, "SpacePilot", 10) == 0));
  946. #else
  947. return false;
  948. #endif
  949. }
  950. // -----------------------------------------------------------------------------
  951. void LLViewerJoystick::setSNDefaults()
  952. {
  953. #if LL_DARWIN || LL_LINUX
  954. const float platformScale = 20.f;
  955. const float platformScaleAvXZ = 1.f;
  956. // The SpaceNavigator doesn't act as a 3D cursor on OS X / Linux.
  957. const bool is_3d_cursor = false;
  958. #else
  959. const float platformScale = 1.f;
  960. const float platformScaleAvXZ = 2.f;
  961. const bool is_3d_cursor = true;
  962. #endif
  963. //gViewerWindow->alertXml("CacheWillClear");
  964. llinfos << "restoring SpaceNavigator defaults..." << llendl;
  965. gSavedSettings.setS32("JoystickAxis0", 1); // z (at)
  966. gSavedSettings.setS32("JoystickAxis1", 0); // x (slide)
  967. gSavedSettings.setS32("JoystickAxis2", 2); // y (up)
  968. gSavedSettings.setS32("JoystickAxis3", 4); // pitch
  969. gSavedSettings.setS32("JoystickAxis4", 3); // roll
  970. gSavedSettings.setS32("JoystickAxis5", 5); // yaw
  971. gSavedSettings.setS32("JoystickAxis6", -1);
  972. gSavedSettings.setBOOL("Cursor3D", is_3d_cursor);
  973. gSavedSettings.setBOOL("AutoLeveling", true);
  974. gSavedSettings.setBOOL("ZoomDirect", false);
  975. gSavedSettings.setF32("AvatarAxisScale0", 1.f * platformScaleAvXZ);
  976. gSavedSettings.setF32("AvatarAxisScale1", 1.f * platformScaleAvXZ);
  977. gSavedSettings.setF32("AvatarAxisScale2", 1.f);
  978. gSavedSettings.setF32("AvatarAxisScale4", .1f * platformScale);
  979. gSavedSettings.setF32("AvatarAxisScale5", .1f * platformScale);
  980. gSavedSettings.setF32("AvatarAxisScale3", 0.f * platformScale);
  981. gSavedSettings.setF32("BuildAxisScale1", .3f * platformScale);
  982. gSavedSettings.setF32("BuildAxisScale2", .3f * platformScale);
  983. gSavedSettings.setF32("BuildAxisScale0", .3f * platformScale);
  984. gSavedSettings.setF32("BuildAxisScale4", .3f * platformScale);
  985. gSavedSettings.setF32("BuildAxisScale5", .3f * platformScale);
  986. gSavedSettings.setF32("BuildAxisScale3", .3f * platformScale);
  987. gSavedSettings.setF32("FlycamAxisScale1", 2.f * platformScale);
  988. gSavedSettings.setF32("FlycamAxisScale2", 2.f * platformScale);
  989. gSavedSettings.setF32("FlycamAxisScale0", 2.1f * platformScale);
  990. gSavedSettings.setF32("FlycamAxisScale4", .1f * platformScale);
  991. gSavedSettings.setF32("FlycamAxisScale5", .15f * platformScale);
  992. gSavedSettings.setF32("FlycamAxisScale3", 0.f * platformScale);
  993. gSavedSettings.setF32("FlycamAxisScale6", 0.f * platformScale);
  994. gSavedSettings.setF32("AvatarAxisDeadZone0", .1f);
  995. gSavedSettings.setF32("AvatarAxisDeadZone1", .1f);
  996. gSavedSettings.setF32("AvatarAxisDeadZone2", .1f);
  997. gSavedSettings.setF32("AvatarAxisDeadZone3", 1.f);
  998. gSavedSettings.setF32("AvatarAxisDeadZone4", .02f);
  999. gSavedSettings.setF32("AvatarAxisDeadZone5", .01f);
  1000. gSavedSettings.setF32("BuildAxisDeadZone0", .01f);
  1001. gSavedSettings.setF32("BuildAxisDeadZone1", .01f);
  1002. gSavedSettings.setF32("BuildAxisDeadZone2", .01f);
  1003. gSavedSettings.setF32("BuildAxisDeadZone3", .01f);
  1004. gSavedSettings.setF32("BuildAxisDeadZone4", .01f);
  1005. gSavedSettings.setF32("BuildAxisDeadZone5", .01f);
  1006. gSavedSettings.setF32("FlycamAxisDeadZone0", .01f);
  1007. gSavedSettings.setF32("FlycamAxisDeadZone1", .01f);
  1008. gSavedSettings.setF32("FlycamAxisDeadZone2", .01f);
  1009. gSavedSettings.setF32("FlycamAxisDeadZone3", .01f);
  1010. gSavedSettings.setF32("FlycamAxisDeadZone4", .01f);
  1011. gSavedSettings.setF32("FlycamAxisDeadZone5", .01f);
  1012. gSavedSettings.setF32("FlycamAxisDeadZone6", 1.f);
  1013. gSavedSettings.setF32("AvatarFeathering", 6.f);
  1014. gSavedSettings.setF32("BuildFeathering", 12.f);
  1015. gSavedSettings.setF32("FlycamFeathering", 5.f);
  1016. }