llviewerjoystick.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:30k
源码类别:

游戏引擎

开发平台:

C++ Builder

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