lltracker.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800
  1. /**
  2. * @file lltracker.cpp
  3. * @brief Container for objects user is tracking.
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewergpl$
  6. *
  7. * Copyright (c) 2003-2009, 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 "lltracker.h"
  34. #include "llgl.h"
  35. #include "llrender.h"
  36. #include "llagent.h"
  37. #include "llappviewer.h"
  38. #include "llavatartracker.h"
  39. #include "llchatbar.h"
  40. #include "llfloaterworldmap.h"
  41. #include "llhudtext.h"
  42. #include "llhudview.h"
  43. #include "llinventorymodel.h"
  44. #include "lllandmarklist.h"
  45. #include "llpanelworldmap.h"
  46. //MK
  47. #include "mkrlinterface.h"
  48. //mk
  49. #include "lltoolbar.h"
  50. #include "llviewercamera.h"
  51. #include "llviewercontrol.h"
  52. #include "llviewerinventory.h"
  53. #include "llworld.h"
  54. constexpr F32 DESTINATION_REACHED_RADIUS = 3.f;
  55. constexpr F32 DESTINATION_VISITED_RADIUS = 6.f;
  56. // this last one is useful for when the landmark is
  57. // very close to agent when tracking is turned on
  58. constexpr F32 DESTINATION_UNVISITED_RADIUS = 12.f;
  59. constexpr S32 ARROW_OFF_RADIUS_SQRD = 100;
  60. constexpr S32 HUD_ARROW_SIZE = 32;
  61. // Global
  62. LLTracker gTracker;
  63. LLTracker::LLTracker()
  64. : mTrackingStatus(TRACKING_NOTHING),
  65. mTrackingLocationType(LOCATION_NOTHING),
  66. mHUDArrowCenterX(0),
  67. mHUDArrowCenterY(0),
  68. mHasReachedLandmark(false),
  69. mHasLandmarkPosition(false),
  70. mLandmarkHasBeenVisited(false),
  71. mIsTrackingLocation(false)
  72. {
  73. }
  74. LLTracker::~LLTracker()
  75. {
  76. purgeBeaconText();
  77. }
  78. void LLTracker::drawHUDArrow()
  79. {
  80. switch (mTrackingStatus)
  81. {
  82. case TRACKING_AVATAR:
  83. // Tracked avatar
  84. if (gAvatarTracker.haveTrackingInfo())
  85. {
  86. drawMarker(gAvatarTracker.getGlobalPos(), LLUI::sTrackColor);
  87. }
  88. break;
  89. case TRACKING_LANDMARK:
  90. drawMarker(getTrackedPositionGlobal(), LLUI::sTrackColor);
  91. break;
  92. case TRACKING_LOCATION:
  93. drawMarker(mTrackedPositionGlobal, LLUI::sTrackColor);
  94. break;
  95. default:
  96. break;
  97. }
  98. }
  99. void LLTracker::render3D()
  100. {
  101. if (!gFloaterWorldMapp)
  102. {
  103. return;
  104. }
  105. //MK
  106. if (gRLenabled && gRLInterface.mContainsShowloc)
  107. {
  108. mTrackedLocationName.clear();
  109. }
  110. //mk
  111. if (mIsTrackingLocation)
  112. {
  113. // Arbitary location beacon
  114. if (!mBeaconText)
  115. {
  116. mBeaconText =
  117. (LLHUDText*)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
  118. mBeaconText->setDoFade(false);
  119. }
  120. if (gFloaterWorldMapp->getDistanceToDestination(mTrackedPositionGlobal)
  121. < DESTINATION_REACHED_RADIUS)
  122. {
  123. stopTrackingLocation();
  124. }
  125. else
  126. {
  127. renderBeacon(mTrackedPositionGlobal, LLUI::sTrackColor,
  128. mBeaconText, mTrackedLocationName);
  129. }
  130. }
  131. else if (mTrackedLandmarkAssetID.notNull())
  132. {
  133. // Landmark beacon
  134. if (!mBeaconText)
  135. {
  136. mBeaconText =
  137. (LLHUDText*)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
  138. mBeaconText->setDoFade(false);
  139. }
  140. if (!mHasLandmarkPosition)
  141. {
  142. // Maybe we just finished downloading the asset...
  143. cacheLandmarkPosition();
  144. return;
  145. }
  146. bool close =
  147. gFloaterWorldMapp->getDistanceToDestination(mTrackedPositionGlobal,
  148. 1.f) < DESTINATION_VISITED_RADIUS;
  149. if (!mLandmarkHasBeenVisited && close)
  150. {
  151. // It is close enough: flag as visited
  152. setLandmarkVisited();
  153. }
  154. if (!mHasReachedLandmark && close)
  155. {
  156. // It is VERY close: automatically stop tracking
  157. stopTrackingLandmark();
  158. return;
  159. }
  160. if (mHasReachedLandmark && !close)
  161. {
  162. // This is so that landmark beacons do not immediately disappear
  163. // when they are created only a few meters away, yet disappear when
  164. // the agent wanders away and back again
  165. mHasReachedLandmark = false;
  166. }
  167. renderBeacon(mTrackedPositionGlobal, LLUI::sTrackColor, mBeaconText,
  168. mTrackedLandmarkName);
  169. }
  170. // Avatar beacon
  171. else if (gAvatarTracker.haveTrackingInfo())
  172. {
  173. if (!mBeaconText)
  174. {
  175. mBeaconText =
  176. (LLHUDText*)LLHUDObject::addHUDObject(LLHUDObject::LL_HUD_TEXT);
  177. mBeaconText->setDoFade(false);
  178. }
  179. F32 dist =
  180. gFloaterWorldMapp->getDistanceToDestination(mTrackedPositionGlobal,
  181. 0.f);
  182. if (dist < DESTINATION_REACHED_RADIUS)
  183. {
  184. stopTrackingAvatar();
  185. }
  186. else
  187. {
  188. renderBeacon(gAvatarTracker.getGlobalPos(), LLUI::sTrackColor,
  189. mBeaconText, gAvatarTracker.getName());
  190. }
  191. }
  192. else
  193. {
  194. bool stop_tracking = false;
  195. const LLUUID& avatar_id = gAvatarTracker.getAvatarID();
  196. if (avatar_id.isNull())
  197. {
  198. stop_tracking = true;
  199. }
  200. else if (!gAgent.isGodlike())
  201. {
  202. const LLRelationship* buddy =
  203. gAvatarTracker.getBuddyInfo(avatar_id);
  204. stop_tracking = !buddy || !buddy->isOnline();
  205. }
  206. if (stop_tracking)
  207. {
  208. stopTrackingAvatar();
  209. }
  210. }
  211. }
  212. void LLTracker::trackAvatar(const LLUUID& avatar_id, const std::string& name)
  213. {
  214. stopTrackingLandmark();
  215. stopTrackingLocation();
  216. //MK
  217. if (gRLenabled &&
  218. (gRLInterface.mContainsShownames ||
  219. gRLInterface.mContainsShownametags))
  220. {
  221. stopTrackingAvatar(true);
  222. return;
  223. }
  224. //mk
  225. gAvatarTracker.track(avatar_id, name);
  226. mTrackingStatus = TRACKING_AVATAR;
  227. mLabel = name;
  228. mToolTip.clear();
  229. }
  230. void LLTracker::trackLandmark(const LLUUID& asset_id, const LLUUID& item_id,
  231. const std::string& name)
  232. {
  233. stopTrackingAvatar();
  234. stopTrackingLocation();
  235. //MK
  236. if (gRLenabled &&
  237. (gRLInterface.mContainsShowminimap ||
  238. gRLInterface.mContainsShowworldmap))
  239. {
  240. stopTrackingLandmark(true);
  241. return;
  242. }
  243. //mk
  244. mTrackedLandmarkAssetID = asset_id;
  245. mTrackedLandmarkItemID = item_id;
  246. mTrackedLandmarkName = name;
  247. cacheLandmarkPosition();
  248. mTrackingStatus = TRACKING_LANDMARK;
  249. mLabel = name;
  250. mToolTip.clear();
  251. }
  252. void LLTracker::trackLocation(const LLVector3d& pos_global,
  253. const std::string& full_name,
  254. const std::string& tooltip,
  255. ETrackingLocationType location_type)
  256. {
  257. stopTrackingAvatar();
  258. stopTrackingLandmark();
  259. mTrackedPositionGlobal = pos_global;
  260. F32 clamped_z =
  261. llmax((F32)mTrackedPositionGlobal.mdV[VZ],
  262. gWorld.resolveLandHeightGlobal(mTrackedPositionGlobal) + 1.5f);
  263. mTrackedPositionGlobal.mdV[VZ] = clamped_z;
  264. mTrackedLocationName = full_name;
  265. mIsTrackingLocation = true;
  266. mTrackingStatus = TRACKING_LOCATION;
  267. mTrackingLocationType = location_type;
  268. mLabel = full_name;
  269. mToolTip = tooltip;
  270. }
  271. bool LLTracker::handleMouseDown(S32 x, S32 y)
  272. {
  273. bool eat_mouse_click = false;
  274. // Fortunately, we can always compute the tracking arrow center
  275. S32 dist_sqrd = (x - mHUDArrowCenterX) * (x - mHUDArrowCenterX) +
  276. (y - mHUDArrowCenterY) * (y - mHUDArrowCenterY);
  277. if (dist_sqrd < ARROW_OFF_RADIUS_SQRD)
  278. {
  279. if (mTrackingStatus)
  280. {
  281. stopTracking();
  282. eat_mouse_click = true;
  283. }
  284. }
  285. return eat_mouse_click;
  286. }
  287. LLVector3d LLTracker::getTrackedPositionGlobal()
  288. {
  289. switch (mTrackingStatus)
  290. {
  291. case TRACKING_AVATAR:
  292. {
  293. if (gAvatarTracker.haveTrackingInfo())
  294. {
  295. return gAvatarTracker.getGlobalPos();
  296. }
  297. break;
  298. }
  299. case TRACKING_LANDMARK:
  300. {
  301. if (mHasLandmarkPosition)
  302. {
  303. return mTrackedPositionGlobal;
  304. }
  305. break;
  306. }
  307. case TRACKING_LOCATION:
  308. {
  309. return mTrackedPositionGlobal;
  310. break;
  311. }
  312. default:
  313. break;
  314. }
  315. return LLVector3d::zero;
  316. }
  317. bool LLTracker::hasLandmarkPosition()
  318. {
  319. if (!mHasLandmarkPosition)
  320. {
  321. // Maybe we just received the landmark position info
  322. cacheLandmarkPosition();
  323. }
  324. return mHasLandmarkPosition;
  325. }
  326. LL_INLINE F32 pulse_func(F32 t, F32 z)
  327. {
  328. z -= t * F_PI * 64.f - 256.f;
  329. F32 a = cosf(z * F_PI / 512.f) * 10.f;
  330. a = (llmax(a, 9.9f) - 9.9f) * 10.f;
  331. return a;
  332. }
  333. LL_INLINE void draw_shockwave(F32 center_z, F32 t, S32 steps, LLColor4 color)
  334. {
  335. t *= 0.6284f / F_PI;
  336. t -= (F32)((S32)t);
  337. t = llmax(t, 0.5f);
  338. t -= 0.5f;
  339. t *= 2.f;
  340. F32 radius = t * 16536.f;
  341. // Inexact, but reasonably fast.
  342. F32 delta = F_TWO_PI / steps;
  343. F32 sin_delta = sinf(delta);
  344. F32 cos_delta = cosf(delta);
  345. F32 x = radius;
  346. F32 y = 0.f;
  347. LLColor4 ccol = LLColor4(1.f, 1.f, 1.f, (1.f - t) * 0.25f);
  348. gGL.begin(LLRender::TRIANGLE_FAN);
  349. gGL.color4fv(ccol.mV);
  350. gGL.vertex3f(0.f, 0.f, center_z);
  351. // make sure circle is complete
  352. steps += 1;
  353. color.mV[3] = 1.f - t * t;
  354. gGL.color4fv(color.mV);
  355. while (steps--)
  356. {
  357. // Successive rotations
  358. gGL.vertex3f(x, y, center_z);
  359. F32 x_new = x * cos_delta - y * sin_delta;
  360. y = x * sin_delta + y * cos_delta;
  361. x = x_new;
  362. }
  363. gGL.end();
  364. }
  365. void LLTracker::renderBeacon(LLVector3d pos_global, const LLColor4& color,
  366. LLHUDText* hud_textp, const std::string& label)
  367. {
  368. LLVector3d to_vec = pos_global - gAgent.getCameraPositionGlobal();
  369. F32 dist = (F32)to_vec.length();
  370. F32 color_frac = 1.f;
  371. if (dist > 0.99f * gViewerCamera.getFar())
  372. {
  373. color_frac = 0.4f;
  374. #if 0
  375. pos_global = gAgent.getCameraPositionGlobal() +
  376. 0.99f * (gViewerCamera.getFar() / dist) * to_vec;
  377. #endif
  378. }
  379. else
  380. {
  381. color_frac = 1.f - 0.6f * (dist / gViewerCamera.getFar());
  382. }
  383. static LLCachedControl<bool> cheesy_beacon(gSavedSettings, "CheesyBeacon");
  384. // Note: this was gSky.getSkyFogColor(), but the latter was never updated
  385. // ever since Extended Environment was implemented (and even likely before
  386. // that, with Windlight), and has now been removed... Let's use the default
  387. // value it was given. HB
  388. static const LLColor4 sky_fog(0.5f, 0.5f, 0.5f, 0.f);
  389. LLColor4 fogged_color = color_frac * color + (1.f - color_frac) * sky_fog;
  390. constexpr F32 FADE_DIST = 3.f;
  391. fogged_color.mV[3] = llmax(0.2f,
  392. llmin(0.5f, (dist - FADE_DIST) / FADE_DIST));
  393. LLVector3 pos_agent = gAgent.getPosAgentFromGlobal(pos_global);
  394. LLGLSTracker gls_tracker;
  395. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  396. LLGLDisable cull_face(GL_CULL_FACE);
  397. LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
  398. gGL.matrixMode(LLRender::MM_MODELVIEW);
  399. gGL.pushMatrix();
  400. {
  401. gGL.translatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]);
  402. if (cheesy_beacon)
  403. {
  404. draw_shockwave(1024.f, gRenderStartTime.getElapsedTimeF32(), 32,
  405. fogged_color);
  406. }
  407. gGL.color4fv(fogged_color.mV);
  408. constexpr U32 BEACON_VERTS = 256;
  409. constexpr F32 step = 1024.f / BEACON_VERTS;
  410. LLVector3 x_axis = gViewerCamera.getLeftAxis();
  411. F32 t = gRenderStartTime.getElapsedTimeF32();
  412. F32 dr = dist / gViewerCamera.getFar();
  413. for (U32 i = 0; i < BEACON_VERTS; ++i)
  414. {
  415. F32 x = x_axis.mV[0];
  416. F32 y = x_axis.mV[1];
  417. F32 z = (F32)i * step;
  418. F32 z_next = z + step;
  419. F32 a = 0.f;
  420. F32 an = 0.f;
  421. if (cheesy_beacon)
  422. {
  423. a = pulse_func(t, z);
  424. an = pulse_func(t, z_next);
  425. }
  426. LLColor4 c_col = fogged_color + LLColor4(a, a, a, a);
  427. LLColor4 col_next = fogged_color + LLColor4(an, an, an, an);
  428. LLColor4 col_edge = fogged_color * LLColor4(a, a, a, 0.f);
  429. LLColor4 col_edge_next = fogged_color * LLColor4(an, an, an, 0.f);
  430. a *= 2.f;
  431. a += 1.f + dr;
  432. an *= 2.f;
  433. an += 1.f + dr;
  434. gGL.begin(LLRender::TRIANGLE_STRIP);
  435. gGL.color4fv(col_edge.mV);
  436. gGL.vertex3f(-x * a, -y * a, z);
  437. gGL.color4fv(col_edge_next.mV);
  438. gGL.vertex3f(-x * an, -y * an, z_next);
  439. gGL.color4fv(c_col.mV);
  440. gGL.vertex3f(0.f, 0.f, z);
  441. gGL.color4fv(col_next.mV);
  442. gGL.vertex3f(0.f, 0.f, z_next);
  443. gGL.color4fv(col_edge.mV);
  444. gGL.vertex3f(x * a, y * a, z);
  445. gGL.color4fv(col_edge_next.mV);
  446. gGL.vertex3f(x * an, y * an, z_next);
  447. gGL.end();
  448. }
  449. }
  450. gGL.popMatrix();
  451. LLWString wstr = utf8str_to_wstring(label);
  452. wstr += '\n';
  453. wstr += utf8str_to_wstring(llformat("%.0f m",
  454. dist_vec(pos_global,
  455. gAgent.getPositionGlobal())));
  456. static LLFontGL* font = LLFontGL::getFontSansSerif();
  457. hud_textp->setFont(font);
  458. hud_textp->setZCompare(false);
  459. hud_textp->setColor(LLColor4(1.f, 1.f, 1.f,
  460. llclamp((dist - FADE_DIST) / FADE_DIST, 0.2f, 1.f)));
  461. hud_textp->setString(wstr);
  462. hud_textp->setVertAlignment(LLHUDText::ALIGN_VERT_CENTER);
  463. hud_textp->setPositionAgent(pos_agent);
  464. }
  465. void LLTracker::stopTracking(bool clear_ui)
  466. {
  467. switch (mTrackingStatus)
  468. {
  469. case TRACKING_AVATAR :
  470. stopTrackingAvatar(clear_ui);
  471. break;
  472. case TRACKING_LANDMARK :
  473. stopTrackingLandmark(clear_ui);
  474. break;
  475. case TRACKING_LOCATION :
  476. stopTrackingLocation(clear_ui);
  477. break;
  478. default:
  479. mTrackingStatus = TRACKING_NOTHING;
  480. }
  481. }
  482. void LLTracker::stopTrackingAvatar(bool clear_ui)
  483. {
  484. if (gAvatarTracker.getAvatarID().notNull())
  485. {
  486. gAvatarTracker.untrack(gAvatarTracker.getAvatarID());
  487. }
  488. purgeBeaconText();
  489. if (gFloaterWorldMapp)
  490. {
  491. gFloaterWorldMapp->clearAvatarSelection(clear_ui);
  492. }
  493. mTrackingStatus = TRACKING_NOTHING;
  494. }
  495. void LLTracker::stopTrackingLandmark(bool clear_ui)
  496. {
  497. purgeBeaconText();
  498. mTrackedLandmarkAssetID.setNull();
  499. mTrackedLandmarkItemID.setNull();
  500. mTrackedLandmarkName.clear();
  501. mTrackedPositionGlobal.setZero();
  502. mHasLandmarkPosition = false;
  503. mHasReachedLandmark = false;
  504. mLandmarkHasBeenVisited = true;
  505. if (gFloaterWorldMapp)
  506. {
  507. gFloaterWorldMapp->clearLandmarkSelection(clear_ui);
  508. }
  509. mTrackingStatus = TRACKING_NOTHING;
  510. }
  511. void LLTracker::stopTrackingLocation(bool clear_ui)
  512. {
  513. purgeBeaconText();
  514. mTrackedLocationName.clear();
  515. mIsTrackingLocation = false;
  516. mTrackedPositionGlobal.setZero();
  517. if (gFloaterWorldMapp)
  518. {
  519. gFloaterWorldMapp->clearLocationSelection(clear_ui);
  520. }
  521. mTrackingStatus = TRACKING_NOTHING;
  522. mTrackingLocationType = LOCATION_NOTHING;
  523. }
  524. void LLTracker::drawMarker(const LLVector3d& pos_global, const LLColor4& color)
  525. {
  526. if (!gHUDViewp) return;
  527. // Get our agent position
  528. LLVector3 pos_local = gAgent.getPosAgentFromGlobal(pos_global);
  529. // Check in frustum
  530. LLCoordGL screen;
  531. S32 x = 0;
  532. S32 y = 0;
  533. if (gViewerCamera.projectPosAgentToScreen(pos_local, screen, true) ||
  534. gViewerCamera.projectPosAgentToScreenEdge(pos_local, screen))
  535. {
  536. gHUDViewp->screenPointToLocal(screen.mX, screen.mY, &x, &y);
  537. // The center of the rendered position of the arrow obeys
  538. // the following rules:
  539. // (1) it lies on an ellipse centered on the target position
  540. // (2) it lies on the line between the target and the window center
  541. // (3) right now the radii of the ellipse are fixed, but eventually
  542. // they will be a function of the target text
  543. //
  544. // From those rules we can compute the position of the lower left
  545. // corner of the image
  546. LLRect rect = gHUDViewp->getRect();
  547. S32 x_center = lltrunc(0.5f * (F32)rect.getWidth());
  548. S32 y_center = lltrunc(0.5f * (F32)rect.getHeight());
  549. x = x - x_center; // x and y relative to center
  550. y = y - y_center;
  551. F32 dist = sqrtf((F32)(x * x + y * y));
  552. S32 half_arrow_size = HUD_ARROW_SIZE / 2;
  553. if (dist > 0.f)
  554. {
  555. constexpr F32 ARROW_ELLIPSE_RADIUS_X = 2 * HUD_ARROW_SIZE;
  556. constexpr F32 ARROW_ELLIPSE_RADIUS_Y = HUD_ARROW_SIZE;
  557. // compute where the arrow should be
  558. F32 x_target = (F32)(x + x_center) -
  559. ARROW_ELLIPSE_RADIUS_X * ((F32)x / dist);
  560. F32 y_target = (F32)(y + y_center) -
  561. ARROW_ELLIPSE_RADIUS_Y * ((F32)y / dist);
  562. // keep the arrow within the window
  563. F32 margin = 0.0;
  564. if (gToolBarp && gToolBarp->getVisible() &&
  565. gChatBarp && gChatBarp->getVisible())
  566. {
  567. margin = (F32)(gChatBarp->getRect().getHeight());
  568. }
  569. F32 x_clamped = llclamp(x_target, (F32)half_arrow_size,
  570. (F32)(rect.getWidth() - half_arrow_size));
  571. F32 y_clamped = llclamp(y_target, (F32)half_arrow_size + margin,
  572. (F32)(rect.getHeight() - half_arrow_size));
  573. F32 slope = (F32)(y) / (F32)(x);
  574. F32 window_ratio = (F32)(rect.getHeight() - HUD_ARROW_SIZE) /
  575. (F32)(rect.getWidth() - HUD_ARROW_SIZE);
  576. // If the arrow has been clamped on one axis then we need to
  577. // compute the other axis
  578. if (fabsf(slope) > window_ratio)
  579. {
  580. if (y_clamped != (F32)y_target)
  581. {
  582. // Clamp by y
  583. x_clamped = (y_clamped - (F32)y_center) / slope +
  584. (F32)x_center;
  585. }
  586. }
  587. else if (x_clamped != (F32)x_target)
  588. {
  589. // Clamp by x
  590. y_clamped = (x_clamped - (F32)x_center) * slope +
  591. (F32)y_center;
  592. }
  593. mHUDArrowCenterX = lltrunc(x_clamped);
  594. mHUDArrowCenterY = lltrunc(y_clamped);
  595. }
  596. else
  597. {
  598. // recycle the old values
  599. x = mHUDArrowCenterX - x_center;
  600. y = mHUDArrowCenterY - y_center;
  601. }
  602. F32 angle = atan2f((F32)y, (F32)x);
  603. gl_draw_scaled_rotated_image(mHUDArrowCenterX - half_arrow_size,
  604. mHUDArrowCenterY - half_arrow_size,
  605. HUD_ARROW_SIZE, HUD_ARROW_SIZE,
  606. RAD_TO_DEG * angle,
  607. LLPanelWorldMap::sTrackArrowImage->getImage(),
  608. color);
  609. }
  610. }
  611. void LLTracker::setLandmarkVisited()
  612. {
  613. if (mTrackedLandmarkItemID.isNull())
  614. {
  615. return;
  616. }
  617. LLViewerInventoryItem* item =
  618. (LLViewerInventoryItem*)gInventory.getItem(mTrackedLandmarkItemID);
  619. if (!item)
  620. {
  621. return;
  622. }
  623. U32 flags = item->getFlags();
  624. if ((flags & LLInventoryItem::II_FLAGS_LANDMARK_VISITED))
  625. {
  626. return;
  627. }
  628. flags |= LLInventoryItem::II_FLAGS_LANDMARK_VISITED;
  629. item->setFlags(flags);
  630. LLMessageSystem* msg = gMessageSystemp;
  631. msg->newMessage("ChangeInventoryItemFlags");
  632. msg->nextBlock("AgentData");
  633. msg->addUUID("AgentID", gAgentID);
  634. msg->addUUID("SessionID", gAgentSessionID);
  635. msg->nextBlock("InventoryData");
  636. msg->addUUID("ItemID", mTrackedLandmarkItemID);
  637. msg->addU32("Flags", flags);
  638. gAgent.sendReliableMessage();
  639. LLInventoryModel::LLCategoryUpdate up(item->getParentUUID(), 0);
  640. gInventory.accountForUpdate(up);
  641. // Need to communicate that the icon needs to change...
  642. gInventory.addChangedMask(LLInventoryObserver::REBUILD, item->getUUID());
  643. gInventory.notifyObservers();
  644. }
  645. void LLTracker::cacheLandmarkPosition()
  646. {
  647. // The landmark asset download may have finished, in which case we will now
  648. // be able to figure out where we are trying to go
  649. bool found_landmark = false;
  650. if (mTrackedLandmarkAssetID == LLFloaterWorldMap::getHomeID())
  651. {
  652. LLVector3d pos_global;
  653. if (gAgent.getHomePosGlobal(&mTrackedPositionGlobal))
  654. {
  655. found_landmark = true;
  656. }
  657. else
  658. {
  659. llwarns << "Could not find home position" << llendl;
  660. mTrackedLandmarkAssetID.setNull();
  661. mTrackedLandmarkItemID.setNull();
  662. }
  663. }
  664. else
  665. {
  666. LLLandmark* landmark = gLandmarkList.getAsset(mTrackedLandmarkAssetID);
  667. if (landmark && landmark->getGlobalPos(mTrackedPositionGlobal))
  668. {
  669. found_landmark = true;
  670. // cache the object's visitation status
  671. mLandmarkHasBeenVisited = false;
  672. LLInventoryItem* item = gInventory.getItem(mTrackedLandmarkItemID);
  673. if (item
  674. && item->getFlags()&LLInventoryItem::II_FLAGS_LANDMARK_VISITED)
  675. {
  676. mLandmarkHasBeenVisited = true;
  677. }
  678. }
  679. }
  680. if (found_landmark && gFloaterWorldMapp)
  681. {
  682. mHasReachedLandmark = false;
  683. F32 dist =
  684. gFloaterWorldMapp->getDistanceToDestination(mTrackedPositionGlobal,
  685. 1.f);
  686. if (dist < DESTINATION_UNVISITED_RADIUS)
  687. {
  688. mHasReachedLandmark = true;
  689. }
  690. mHasLandmarkPosition = true;
  691. }
  692. mHasLandmarkPosition = found_landmark;
  693. }
  694. void LLTracker::purgeBeaconText()
  695. {
  696. if (mBeaconText.notNull())
  697. {
  698. mBeaconText->markDead();
  699. mBeaconText = NULL;
  700. }
  701. }