PageRenderTime 87ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/lltracker.cpp

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