PageRenderTime 58ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llworldmapview.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1786 lines | 1329 code | 238 blank | 219 comment | 202 complexity | 054584634f1c4a725fc6d3cc520d3f91 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llworldmapview.cpp
  3. * @brief LLWorldMapView class implementation
  4. *
  5. * $LicenseInfo:firstyear=2001&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 "llworldmapview.h"
  28. #include "indra_constants.h"
  29. #include "llui.h"
  30. #include "llmath.h" // clampf()
  31. #include "llregionhandle.h"
  32. #include "lleventflags.h"
  33. #include "llfloaterreg.h"
  34. #include "llrender.h"
  35. #include "lltooltip.h"
  36. #include "llagent.h"
  37. #include "llagentcamera.h"
  38. #include "llcallingcard.h"
  39. #include "llcommandhandler.h"
  40. #include "llviewercontrol.h"
  41. #include "llfloatermap.h"
  42. #include "llfloaterworldmap.h"
  43. #include "llfocusmgr.h"
  44. #include "lllocalcliprect.h"
  45. #include "lltextbox.h"
  46. #include "lltextureview.h"
  47. #include "lltracker.h"
  48. #include "llviewercamera.h"
  49. #include "llviewertexture.h"
  50. #include "llviewertexturelist.h"
  51. #include "llviewerregion.h"
  52. #include "llviewerwindow.h"
  53. #include "lltrans.h"
  54. #include "llglheaders.h"
  55. // Basically a C++ implementation of the OCEAN_COLOR defined in mapstitcher.py
  56. // Please ensure consistency between those 2 files (TODO: would be better to get that color from an asset source...)
  57. // # Constants
  58. // OCEAN_COLOR = "#1D475F"
  59. const F32 OCEAN_RED = (F32)(0x1D)/255.f;
  60. const F32 OCEAN_GREEN = (F32)(0x47)/255.f;
  61. const F32 OCEAN_BLUE = (F32)(0x5F)/255.f;
  62. const F32 GODLY_TELEPORT_HEIGHT = 200.f;
  63. const S32 SCROLL_HINT_WIDTH = 65;
  64. const F32 BIG_DOT_RADIUS = 5.f;
  65. BOOL LLWorldMapView::sHandledLastClick = FALSE;
  66. LLUIImagePtr LLWorldMapView::sAvatarSmallImage = NULL;
  67. LLUIImagePtr LLWorldMapView::sAvatarYouImage = NULL;
  68. LLUIImagePtr LLWorldMapView::sAvatarYouLargeImage = NULL;
  69. LLUIImagePtr LLWorldMapView::sAvatarLevelImage = NULL;
  70. LLUIImagePtr LLWorldMapView::sAvatarAboveImage = NULL;
  71. LLUIImagePtr LLWorldMapView::sAvatarBelowImage = NULL;
  72. LLUIImagePtr LLWorldMapView::sTelehubImage = NULL;
  73. LLUIImagePtr LLWorldMapView::sInfohubImage = NULL;
  74. LLUIImagePtr LLWorldMapView::sHomeImage = NULL;
  75. LLUIImagePtr LLWorldMapView::sEventImage = NULL;
  76. LLUIImagePtr LLWorldMapView::sEventMatureImage = NULL;
  77. LLUIImagePtr LLWorldMapView::sEventAdultImage = NULL;
  78. LLUIImagePtr LLWorldMapView::sTrackCircleImage = NULL;
  79. LLUIImagePtr LLWorldMapView::sTrackArrowImage = NULL;
  80. LLUIImagePtr LLWorldMapView::sClassifiedsImage = NULL;
  81. LLUIImagePtr LLWorldMapView::sForSaleImage = NULL;
  82. LLUIImagePtr LLWorldMapView::sForSaleAdultImage = NULL;
  83. F32 LLWorldMapView::sPanX = 0.f;
  84. F32 LLWorldMapView::sPanY = 0.f;
  85. F32 LLWorldMapView::sTargetPanX = 0.f;
  86. F32 LLWorldMapView::sTargetPanY = 0.f;
  87. S32 LLWorldMapView::sTrackingArrowX = 0;
  88. S32 LLWorldMapView::sTrackingArrowY = 0;
  89. bool LLWorldMapView::sVisibleTilesLoaded = false;
  90. F32 LLWorldMapView::sMapScale = 128.f;
  91. std::map<std::string,std::string> LLWorldMapView::sStringsMap;
  92. // Fetch and draw info thresholds
  93. const F32 DRAW_TEXT_THRESHOLD = 96.f; // Don't draw text under that resolution value (res = width region in meters)
  94. const S32 DRAW_SIMINFO_THRESHOLD = 3; // Max level for which we load or display sim level information (level in LLWorldMipmap sense)
  95. const S32 DRAW_LANDFORSALE_THRESHOLD = 2; // Max level for which we load or display land for sale picture data (level in LLWorldMipmap sense)
  96. // When on, draw an outline for each mipmap tile gotten from S3
  97. #define DEBUG_DRAW_TILE 0
  98. void LLWorldMapView::initClass()
  99. {
  100. sAvatarSmallImage = LLUI::getUIImage("map_avatar_8.tga");
  101. sAvatarYouImage = LLUI::getUIImage("map_avatar_16.tga");
  102. sAvatarYouLargeImage = LLUI::getUIImage("map_avatar_you_32.tga");
  103. sAvatarLevelImage = LLUI::getUIImage("map_avatar_32.tga");
  104. sAvatarAboveImage = LLUI::getUIImage("map_avatar_above_32.tga");
  105. sAvatarBelowImage = LLUI::getUIImage("map_avatar_below_32.tga");
  106. sHomeImage = LLUI::getUIImage("map_home.tga");
  107. sTelehubImage = LLUI::getUIImage("map_telehub.tga");
  108. sInfohubImage = LLUI::getUIImage("map_infohub.tga");
  109. sEventImage = LLUI::getUIImage("Parcel_PG_Dark");
  110. sEventMatureImage = LLUI::getUIImage("Parcel_M_Dark");
  111. // To Do: update the image resource for adult events.
  112. sEventAdultImage = LLUI::getUIImage("Parcel_R_Dark");
  113. sTrackCircleImage = LLUI::getUIImage("map_track_16.tga");
  114. sTrackArrowImage = LLUI::getUIImage("direction_arrow.tga");
  115. sClassifiedsImage = LLUI::getUIImage("icon_top_pick.tga");
  116. sForSaleImage = LLUI::getUIImage("icon_for_sale.tga");
  117. // To Do: update the image resource for adult lands on sale.
  118. sForSaleAdultImage = LLUI::getUIImage("icon_for_sale_adult.tga");
  119. sStringsMap["loading"] = LLTrans::getString("texture_loading");
  120. sStringsMap["offline"] = LLTrans::getString("worldmap_offline");
  121. }
  122. // static
  123. void LLWorldMapView::cleanupClass()
  124. {
  125. sAvatarSmallImage = NULL;
  126. sAvatarYouImage = NULL;
  127. sAvatarYouLargeImage = NULL;
  128. sAvatarLevelImage = NULL;
  129. sAvatarAboveImage = NULL;
  130. sAvatarBelowImage = NULL;
  131. sTelehubImage = NULL;
  132. sInfohubImage = NULL;
  133. sHomeImage = NULL;
  134. sEventImage = NULL;
  135. sEventMatureImage = NULL;
  136. sEventAdultImage = NULL;
  137. sTrackCircleImage = NULL;
  138. sTrackArrowImage = NULL;
  139. sClassifiedsImage = NULL;
  140. sForSaleImage = NULL;
  141. sForSaleAdultImage = NULL;
  142. }
  143. LLWorldMapView::LLWorldMapView()
  144. : LLPanel(),
  145. mBackgroundColor( LLColor4( OCEAN_RED, OCEAN_GREEN, OCEAN_BLUE, 1.f ) ),
  146. mItemPicked(FALSE),
  147. mPanning( FALSE ),
  148. mMouseDownPanX( 0 ),
  149. mMouseDownPanY( 0 ),
  150. mMouseDownX( 0 ),
  151. mMouseDownY( 0 ),
  152. mSelectIDStart(0)
  153. {
  154. //LL_INFOS("World Map") << "Creating the Map -> LLWorldMapView::LLWorldMapView()" << LL_ENDL;
  155. clearLastClick();
  156. }
  157. BOOL LLWorldMapView::postBuild()
  158. {
  159. mTextBoxNorth = getChild<LLTextBox> ("floater_map_north");
  160. mTextBoxEast = getChild<LLTextBox> ("floater_map_east");
  161. mTextBoxWest = getChild<LLTextBox> ("floater_map_west");
  162. mTextBoxSouth = getChild<LLTextBox> ("floater_map_south");
  163. mTextBoxSouthEast = getChild<LLTextBox> ("floater_map_southeast");
  164. mTextBoxNorthEast = getChild<LLTextBox> ("floater_map_northeast");
  165. mTextBoxSouthWest = getChild<LLTextBox> ("floater_map_southwest");
  166. mTextBoxNorthWest = getChild<LLTextBox> ("floater_map_northwest");
  167. mTextBoxNorth->setText(getString("world_map_north"));
  168. mTextBoxEast->setText(getString ("world_map_east"));
  169. mTextBoxWest->setText(getString("world_map_west"));
  170. mTextBoxSouth->setText(getString ("world_map_south"));
  171. mTextBoxSouthEast ->setText(getString ("world_map_southeast"));
  172. mTextBoxNorthEast ->setText(getString ("world_map_northeast"));
  173. mTextBoxSouthWest->setText(getString ("world_map_southwest"));
  174. mTextBoxNorthWest ->setText(getString("world_map_northwest"));
  175. mTextBoxNorth->reshapeToFitText();
  176. mTextBoxEast->reshapeToFitText();
  177. mTextBoxWest->reshapeToFitText();
  178. mTextBoxSouth->reshapeToFitText();
  179. mTextBoxSouthEast ->reshapeToFitText();
  180. mTextBoxNorthEast ->reshapeToFitText();
  181. mTextBoxSouthWest->reshapeToFitText();
  182. mTextBoxNorthWest ->reshapeToFitText();
  183. return true;
  184. }
  185. LLWorldMapView::~LLWorldMapView()
  186. {
  187. //LL_INFOS("World Map") << "Destroying the map -> LLWorldMapView::~LLWorldMapView()" << LL_ENDL;
  188. cleanupTextures();
  189. }
  190. // static
  191. void LLWorldMapView::cleanupTextures()
  192. {
  193. }
  194. // static
  195. void LLWorldMapView::setScale( F32 scale )
  196. {
  197. if (scale != sMapScale)
  198. {
  199. F32 old_scale = sMapScale;
  200. sMapScale = scale;
  201. if (sMapScale <= 0.f)
  202. {
  203. sMapScale = 0.1f;
  204. }
  205. F32 ratio = (scale / old_scale);
  206. sPanX *= ratio;
  207. sPanY *= ratio;
  208. sTargetPanX = sPanX;
  209. sTargetPanY = sPanY;
  210. sVisibleTilesLoaded = false;
  211. }
  212. }
  213. // static
  214. void LLWorldMapView::translatePan( S32 delta_x, S32 delta_y )
  215. {
  216. sPanX += delta_x;
  217. sPanY += delta_y;
  218. sTargetPanX = sPanX;
  219. sTargetPanY = sPanY;
  220. sVisibleTilesLoaded = false;
  221. }
  222. // static
  223. void LLWorldMapView::setPan( S32 x, S32 y, BOOL snap )
  224. {
  225. sTargetPanX = (F32)x;
  226. sTargetPanY = (F32)y;
  227. if (snap)
  228. {
  229. sPanX = sTargetPanX;
  230. sPanY = sTargetPanY;
  231. }
  232. sVisibleTilesLoaded = false;
  233. }
  234. bool LLWorldMapView::showRegionInfo()
  235. {
  236. return (LLWorldMipmap::scaleToLevel(sMapScale) <= DRAW_SIMINFO_THRESHOLD ? true : false);
  237. }
  238. ///////////////////////////////////////////////////////////////////////////////////
  239. // HELPERS
  240. BOOL is_agent_in_region(LLViewerRegion* region, LLSimInfo* info)
  241. {
  242. return (region && info && info->isName(region->getName()));
  243. }
  244. ///////////////////////////////////////////////////////////////////////////////////
  245. void LLWorldMapView::draw()
  246. {
  247. static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white);
  248. LLTextureView::clearDebugImages();
  249. F64 current_time = LLTimer::getElapsedSeconds();
  250. mVisibleRegions.clear();
  251. // animate pan if necessary
  252. sPanX = lerp(sPanX, sTargetPanX, LLCriticalDamp::getInterpolant(0.1f));
  253. sPanY = lerp(sPanY, sTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
  254. const S32 width = getRect().getWidth();
  255. const S32 height = getRect().getHeight();
  256. const F32 half_width = F32(width) / 2.0f;
  257. const F32 half_height = F32(height) / 2.0f;
  258. LLVector3d camera_global = gAgentCamera.getCameraPositionGlobal();
  259. S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
  260. LLLocalClipRect clip(getLocalRect());
  261. {
  262. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  263. gGL.matrixMode(LLRender::MM_MODELVIEW);
  264. // Clear the background alpha to 0
  265. gGL.flush();
  266. gGL.setColorMask(false, true);
  267. gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.f);
  268. gGL.setSceneBlendType(LLRender::BT_REPLACE);
  269. gGL.color4f(0.0f, 0.0f, 0.0f, 0.0f);
  270. gl_rect_2d(0, height, width, 0);
  271. }
  272. gGL.flush();
  273. gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
  274. gGL.setColorMask(true, true);
  275. // Draw the image tiles
  276. drawMipmap(width, height);
  277. gGL.flush();
  278. gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
  279. gGL.setColorMask(true, true);
  280. // Draw per sim overlayed information (names, mature, offline...)
  281. for (LLWorldMap::sim_info_map_t::const_iterator it = LLWorldMap::getInstance()->getRegionMap().begin();
  282. it != LLWorldMap::getInstance()->getRegionMap().end(); ++it)
  283. {
  284. U64 handle = it->first;
  285. LLSimInfo* info = it->second;
  286. LLVector3d origin_global = from_region_handle(handle);
  287. // Find x and y position relative to camera's center.
  288. LLVector3d rel_region_pos = origin_global - camera_global;
  289. F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * sMapScale;
  290. F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * sMapScale;
  291. // Coordinates of the sim in pixels in the UI panel
  292. // When the view isn't panned, 0,0 = center of rectangle
  293. F32 bottom = sPanY + half_height + relative_y;
  294. F32 left = sPanX + half_width + relative_x;
  295. F32 top = bottom + sMapScale ;
  296. F32 right = left + sMapScale ;
  297. // Discard if region is outside the screen rectangle (not visible on screen)
  298. if ((top < 0.f) || (bottom > height) ||
  299. (right < 0.f) || (left > width) )
  300. {
  301. // Drop the "land for sale" fetching priority since it's outside the view rectangle
  302. info->dropImagePriority();
  303. continue;
  304. }
  305. // This list is used by other methods to know which regions are indeed displayed on screen
  306. mVisibleRegions.push_back(handle);
  307. // Update the agent count for that region if we're not too zoomed out already
  308. if (level <= DRAW_SIMINFO_THRESHOLD)
  309. {
  310. info->updateAgentCount(current_time);
  311. }
  312. if (info->isDown())
  313. {
  314. // Draw a transparent red square over down sims
  315. gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_SOURCE_ALPHA);
  316. gGL.color4f(0.2f, 0.0f, 0.0f, 0.4f);
  317. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  318. gGL.begin(LLRender::QUADS);
  319. gGL.vertex2f(left, top);
  320. gGL.vertex2f(left, bottom);
  321. gGL.vertex2f(right, bottom);
  322. gGL.vertex2f(right, top);
  323. gGL.end();
  324. }
  325. // As part of the AO project, we no longer want to draw access indicators;
  326. // it's too complicated to get all the rules straight and will only
  327. // cause confusion.
  328. /**********************
  329. else if (!info->isPG() && gAgent.isTeen())
  330. {
  331. // If this is a mature region, and you are not, draw a line across it
  332. gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO);
  333. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  334. gGL.color3f(1.f, 0.f, 0.f);
  335. gGL.begin(LLRender::LINES);
  336. gGL.vertex2f(left, top);
  337. gGL.vertex2f(right, bottom);
  338. gGL.vertex2f(left, bottom);
  339. gGL.vertex2f(right, top);
  340. gGL.end();
  341. }
  342. **********************/
  343. else if (gSavedSettings.getBOOL("MapShowLandForSale") && (level <= DRAW_LANDFORSALE_THRESHOLD))
  344. {
  345. // Draw the overlay image "Land for Sale / Land for Auction"
  346. LLViewerFetchedTexture* overlayimage = info->getLandForSaleImage();
  347. if (overlayimage)
  348. {
  349. // Inform the fetch mechanism of the size we need
  350. S32 draw_size = llround(sMapScale);
  351. overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY]));
  352. // Draw something whenever we have enough info
  353. if (overlayimage->hasGLTexture())
  354. {
  355. gGL.blendFunc(LLRender::BF_SOURCE_ALPHA, LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
  356. gGL.getTexUnit(0)->bind(overlayimage);
  357. gGL.color4f(1.f, 1.f, 1.f, 1.f);
  358. gGL.begin(LLRender::QUADS);
  359. gGL.texCoord2f(0.f, 1.f);
  360. gGL.vertex3f(left, top, -0.5f);
  361. gGL.texCoord2f(0.f, 0.f);
  362. gGL.vertex3f(left, bottom, -0.5f);
  363. gGL.texCoord2f(1.f, 0.f);
  364. gGL.vertex3f(right, bottom, -0.5f);
  365. gGL.texCoord2f(1.f, 1.f);
  366. gGL.vertex3f(right, top, -0.5f);
  367. gGL.end();
  368. }
  369. }
  370. }
  371. else
  372. {
  373. // If we're not displaying the "land for sale", drop its fetching priority
  374. info->dropImagePriority();
  375. }
  376. // Draw the region name in the lower left corner
  377. if (sMapScale >= DRAW_TEXT_THRESHOLD)
  378. {
  379. LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Small", LLFontGL::BOLD));
  380. std::string mesg;
  381. if (info->isDown())
  382. {
  383. mesg = llformat( "%s (%s)", info->getName().c_str(), sStringsMap["offline"].c_str());
  384. }
  385. else
  386. {
  387. mesg = info->getName();
  388. }
  389. if (!mesg.empty())
  390. {
  391. font->renderUTF8(
  392. mesg, 0,
  393. llfloor(left + 3), llfloor(bottom + 2),
  394. LLColor4::white,
  395. LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW);
  396. }
  397. }
  398. }
  399. // Draw background rectangle
  400. LLGLSUIDefault gls_ui;
  401. {
  402. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  403. gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.f);
  404. gGL.blendFunc(LLRender::BF_ONE_MINUS_DEST_ALPHA, LLRender::BF_DEST_ALPHA);
  405. gGL.color4fv( mBackgroundColor.mV );
  406. gl_rect_2d(0, height, width, 0);
  407. }
  408. gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
  409. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  410. // Draw item infos if we're not zoomed out too much and there's something to draw
  411. if ((level <= DRAW_SIMINFO_THRESHOLD) && (gSavedSettings.getBOOL("MapShowInfohubs") ||
  412. gSavedSettings.getBOOL("MapShowTelehubs") ||
  413. gSavedSettings.getBOOL("MapShowLandForSale") ||
  414. gSavedSettings.getBOOL("MapShowEvents") ||
  415. gSavedSettings.getBOOL("ShowMatureEvents") ||
  416. gSavedSettings.getBOOL("ShowAdultEvents")))
  417. {
  418. drawItems();
  419. }
  420. // Draw the Home location (always)
  421. LLVector3d home;
  422. if (gAgent.getHomePosGlobal(&home))
  423. {
  424. drawImage(home, sHomeImage);
  425. }
  426. // Draw the current agent after all that other stuff.
  427. LLVector3d pos_global = gAgent.getPositionGlobal();
  428. drawImage(pos_global, sAvatarYouImage);
  429. LLVector3 pos_map = globalPosToView(pos_global);
  430. if (!pointInView(llround(pos_map.mV[VX]), llround(pos_map.mV[VY])))
  431. {
  432. drawTracking(pos_global,
  433. lerp(LLColor4::yellow, LLColor4::orange, 0.4f),
  434. TRUE,
  435. "You are here",
  436. "",
  437. llround(LLFontGL::getFontSansSerifSmall()->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking
  438. }
  439. // Draw the current agent viewing angle
  440. drawFrustum();
  441. // Draw icons for the avatars in each region.
  442. // Drawn this after the current agent avatar so one can see nearby people
  443. if (gSavedSettings.getBOOL("MapShowPeople") && (level <= DRAW_SIMINFO_THRESHOLD))
  444. {
  445. drawAgents();
  446. }
  447. // Always draw tracking information
  448. LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
  449. if ( LLTracker::TRACKING_AVATAR == tracking_status )
  450. {
  451. drawTracking( LLAvatarTracker::instance().getGlobalPos(), map_track_color, TRUE, LLTracker::getLabel(), "" );
  452. }
  453. else if ( LLTracker::TRACKING_LANDMARK == tracking_status
  454. || LLTracker::TRACKING_LOCATION == tracking_status )
  455. {
  456. // While fetching landmarks, will have 0,0,0 location for a while,
  457. // so don't draw. JC
  458. LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
  459. if (!pos_global.isExactlyZero())
  460. {
  461. drawTracking( pos_global, map_track_color, TRUE, LLTracker::getLabel(), LLTracker::getToolTip() );
  462. }
  463. }
  464. else if (LLWorldMap::getInstance()->isTracking())
  465. {
  466. if (LLWorldMap::getInstance()->isTrackingInvalidLocation())
  467. {
  468. // We know this location to be invalid, draw a blue circle
  469. LLColor4 loading_color(0.0, 0.5, 1.0, 1.0);
  470. drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, getString("InvalidLocation"), "");
  471. }
  472. else
  473. {
  474. // We don't know yet what that location is, draw a throbing blue circle
  475. double value = fmod(current_time, 2);
  476. value = 0.5 + 0.5*cos(value * F_PI);
  477. LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
  478. drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, getString("Loading"), "");
  479. }
  480. }
  481. // turn off the scissor
  482. LLGLDisable no_scissor(GL_SCISSOR_TEST);
  483. updateDirections();
  484. LLView::draw();
  485. // Get sim info for all sims in view
  486. updateVisibleBlocks();
  487. } // end draw()
  488. //virtual
  489. void LLWorldMapView::setVisible(BOOL visible)
  490. {
  491. LLPanel::setVisible(visible);
  492. if (!visible)
  493. {
  494. // Drop the download of tiles and images priority to nil if we hide the map
  495. LLWorldMap::getInstance()->dropImagePriorities();
  496. }
  497. }
  498. void LLWorldMapView::drawMipmap(S32 width, S32 height)
  499. {
  500. // Compute the level of the mipmap to use for the current scale level
  501. S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
  502. // Set the tile boost level so that unused tiles get to 0
  503. LLWorldMap::getInstance()->equalizeBoostLevels();
  504. // Render whatever we already have loaded if we haven't the current level
  505. // complete and use it as a background (scaled up or scaled down)
  506. if (!sVisibleTilesLoaded)
  507. {
  508. // Note: the (load = false) parameter avoids missing tiles to be fetched (i.e. we render what we have, no more)
  509. // Check all the lower res levels and render them in reverse order (worse to best)
  510. // We need to traverse all the levels as the user can zoom in very fast
  511. for (S32 l = LLWorldMipmap::MAP_LEVELS; l > level; l--)
  512. {
  513. drawMipmapLevel(width, height, l, false);
  514. }
  515. // Skip the current level, as we'll do it anyway here under...
  516. // Just go one level down in res as it can really get too much stuff
  517. // when zooming out and too small to see anyway...
  518. if (level > 1)
  519. {
  520. drawMipmapLevel(width, height, level - 1, false);
  521. }
  522. }
  523. else
  524. {
  525. //LL_INFOS("World Map") << "Render complete, don't draw background..." << LL_ENDL;
  526. }
  527. // Render the current level
  528. sVisibleTilesLoaded = drawMipmapLevel(width, height, level);
  529. return;
  530. }
  531. // Return true if all the tiles required to render that level have been fetched or are truly missing
  532. bool LLWorldMapView::drawMipmapLevel(S32 width, S32 height, S32 level, bool load)
  533. {
  534. // Check input level
  535. llassert (level > 0);
  536. if (level <= 0)
  537. return false;
  538. // Count tiles hit and completed
  539. S32 completed_tiles = 0;
  540. S32 total_tiles = 0;
  541. // Size in meters (global) of each tile of that level
  542. S32 tile_width = LLWorldMipmap::MAP_TILE_SIZE * (1 << (level - 1));
  543. // Dimension of the screen in meter at that scale
  544. LLVector3d pos_SW = viewPosToGlobal(0, 0);
  545. LLVector3d pos_NE = viewPosToGlobal(width, height);
  546. // Add external band of tiles on the outskirt so to hit the partially displayed tiles right and top
  547. pos_NE[VX] += tile_width;
  548. pos_NE[VY] += tile_width;
  549. // Iterate through the tiles on screen: we just need to ask for one tile every tile_width meters
  550. U32 grid_x, grid_y;
  551. for (F64 index_y = pos_SW[VY]; index_y < pos_NE[VY]; index_y += tile_width)
  552. {
  553. for (F64 index_x = pos_SW[VX]; index_x < pos_NE[VX]; index_x += tile_width)
  554. {
  555. // Compute the world coordinates of the current point
  556. LLVector3d pos_global(index_x, index_y, pos_SW[VZ]);
  557. // Convert to the mipmap level coordinates for that point (i.e. which tile to we hit)
  558. LLWorldMipmap::globalToMipmap(pos_global[VX], pos_global[VY], level, &grid_x, &grid_y);
  559. // Get the tile. Note: NULL means that the image does not exist (so it's considered "complete" as far as fetching is concerned)
  560. LLPointer<LLViewerFetchedTexture> simimage = LLWorldMap::getInstance()->getObjectsTile(grid_x, grid_y, level, load);
  561. if (simimage)
  562. {
  563. // Checks that the image has a valid texture
  564. if (simimage->hasGLTexture())
  565. {
  566. // Increment the number of completly fetched tiles
  567. completed_tiles++;
  568. // Convert those coordinates (SW corner of the mipmap tile) into world (meters) coordinates
  569. pos_global[VX] = grid_x * REGION_WIDTH_METERS;
  570. pos_global[VY] = grid_y * REGION_WIDTH_METERS;
  571. // Now to screen coordinates for SW corner of that tile
  572. LLVector3 pos_screen = globalPosToView (pos_global);
  573. F32 left = pos_screen[VX];
  574. F32 bottom = pos_screen[VY];
  575. // Compute the NE corner coordinates of the tile now
  576. pos_global[VX] += tile_width;
  577. pos_global[VY] += tile_width;
  578. pos_screen = globalPosToView (pos_global);
  579. F32 right = pos_screen[VX];
  580. F32 top = pos_screen[VY];
  581. // Draw the tile
  582. LLGLSUIDefault gls_ui;
  583. gGL.getTexUnit(0)->bind(simimage.get());
  584. simimage->setAddressMode(LLTexUnit::TAM_CLAMP);
  585. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  586. gGL.color4f(1.f, 1.0f, 1.0f, 1.0f);
  587. gGL.begin(LLRender::QUADS);
  588. gGL.texCoord2f(0.f, 1.f);
  589. gGL.vertex3f(left, top, 0.f);
  590. gGL.texCoord2f(0.f, 0.f);
  591. gGL.vertex3f(left, bottom, 0.f);
  592. gGL.texCoord2f(1.f, 0.f);
  593. gGL.vertex3f(right, bottom, 0.f);
  594. gGL.texCoord2f(1.f, 1.f);
  595. gGL.vertex3f(right, top, 0.f);
  596. gGL.end();
  597. #if DEBUG_DRAW_TILE
  598. drawTileOutline(level, top, left, bottom, right);
  599. #endif // DEBUG_DRAW_TILE
  600. }
  601. //else
  602. //{
  603. // Waiting for a tile -> the level is not complete
  604. // LL_INFOS("World Map") << "Unfetched tile. level = " << level << LL_ENDL;
  605. //}
  606. }
  607. else
  608. {
  609. // Unexistent tiles are counted as "completed"
  610. completed_tiles++;
  611. }
  612. // Increment the number of tiles in that level / screen
  613. total_tiles++;
  614. }
  615. }
  616. return (completed_tiles == total_tiles);
  617. }
  618. // Draw lines (rectangle outline and cross) to visualize the position of the tile
  619. // Used for debug only
  620. void LLWorldMapView::drawTileOutline(S32 level, F32 top, F32 left, F32 bottom, F32 right)
  621. {
  622. gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO);
  623. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  624. if (level == 1)
  625. gGL.color3f(1.f, 0.f, 0.f); // red
  626. else if (level == 2)
  627. gGL.color3f(0.f, 1.f, 0.f); // green
  628. else if (level == 3)
  629. gGL.color3f(0.f, 0.f, 1.f); // blue
  630. else if (level == 4)
  631. gGL.color3f(1.f, 1.f, 0.f); // yellow
  632. else if (level == 5)
  633. gGL.color3f(1.f, 0.f, 1.f); // magenta
  634. else if (level == 6)
  635. gGL.color3f(0.f, 1.f, 1.f); // cyan
  636. else if (level == 7)
  637. gGL.color3f(1.f, 1.f, 1.f); // white
  638. else
  639. gGL.color3f(0.f, 0.f, 0.f); // black
  640. gGL.begin(LLRender::LINE_STRIP);
  641. gGL.vertex2f(left, top);
  642. gGL.vertex2f(right, bottom);
  643. gGL.vertex2f(left, bottom);
  644. gGL.vertex2f(right, top);
  645. gGL.vertex2f(left, top);
  646. gGL.vertex2f(left, bottom);
  647. gGL.vertex2f(right, bottom);
  648. gGL.vertex2f(right, top);
  649. gGL.end();
  650. }
  651. void LLWorldMapView::drawGenericItems(const LLSimInfo::item_info_list_t& items, LLUIImagePtr image)
  652. {
  653. LLSimInfo::item_info_list_t::const_iterator e;
  654. for (e = items.begin(); e != items.end(); ++e)
  655. {
  656. drawGenericItem(*e, image);
  657. }
  658. }
  659. void LLWorldMapView::drawGenericItem(const LLItemInfo& item, LLUIImagePtr image)
  660. {
  661. drawImage(item.getGlobalPosition(), image);
  662. }
  663. void LLWorldMapView::drawImage(const LLVector3d& global_pos, LLUIImagePtr image, const LLColor4& color)
  664. {
  665. LLVector3 pos_map = globalPosToView( global_pos );
  666. image->draw(llround(pos_map.mV[VX] - image->getWidth() /2.f),
  667. llround(pos_map.mV[VY] - image->getHeight()/2.f),
  668. color);
  669. }
  670. void LLWorldMapView::drawImageStack(const LLVector3d& global_pos, LLUIImagePtr image, U32 count, F32 offset, const LLColor4& color)
  671. {
  672. LLVector3 pos_map = globalPosToView( global_pos );
  673. for(U32 i=0; i<count; i++)
  674. {
  675. image->draw(llround(pos_map.mV[VX] - image->getWidth() /2.f),
  676. llround(pos_map.mV[VY] - image->getHeight()/2.f + i*offset),
  677. color);
  678. }
  679. }
  680. void LLWorldMapView::drawItems()
  681. {
  682. bool mature_enabled = gAgent.canAccessMature();
  683. bool adult_enabled = gAgent.canAccessAdult();
  684. BOOL show_mature = mature_enabled && gSavedSettings.getBOOL("ShowMatureEvents");
  685. BOOL show_adult = adult_enabled && gSavedSettings.getBOOL("ShowAdultEvents");
  686. for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
  687. {
  688. U64 handle = *iter;
  689. LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
  690. if ((info == NULL) || (info->isDown()))
  691. {
  692. continue;
  693. }
  694. // Infohubs
  695. if (gSavedSettings.getBOOL("MapShowInfohubs"))
  696. {
  697. drawGenericItems(info->getInfoHub(), sInfohubImage);
  698. }
  699. // Telehubs
  700. if (gSavedSettings.getBOOL("MapShowTelehubs"))
  701. {
  702. drawGenericItems(info->getTeleHub(), sTelehubImage);
  703. }
  704. // Land for sale
  705. if (gSavedSettings.getBOOL("MapShowLandForSale"))
  706. {
  707. drawGenericItems(info->getLandForSale(), sForSaleImage);
  708. // for 1.23, we're showing normal land and adult land in the same UI; you don't
  709. // get a choice about which ones you want. If you're currently asking for adult
  710. // content and land you'll get the adult land.
  711. if (gAgent.canAccessAdult())
  712. {
  713. drawGenericItems(info->getLandForSaleAdult(), sForSaleAdultImage);
  714. }
  715. }
  716. // PG Events
  717. if (gSavedSettings.getBOOL("MapShowEvents"))
  718. {
  719. drawGenericItems(info->getPGEvent(), sEventImage);
  720. }
  721. // Mature Events
  722. if (show_mature)
  723. {
  724. drawGenericItems(info->getMatureEvent(), sEventMatureImage);
  725. }
  726. // Adult Events
  727. if (show_adult)
  728. {
  729. drawGenericItems(info->getAdultEvent(), sEventAdultImage);
  730. }
  731. }
  732. }
  733. void LLWorldMapView::drawAgents()
  734. {
  735. static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white);
  736. for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
  737. {
  738. U64 handle = *iter;
  739. LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
  740. if ((siminfo == NULL) || (siminfo->isDown()))
  741. {
  742. continue;
  743. }
  744. LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAgentLocation().begin();
  745. while (it != siminfo->getAgentLocation().end())
  746. {
  747. // Show Individual agents (or little stacks where real agents are)
  748. // Here's how we'd choose the color if info.mID were available but it's not being sent:
  749. // LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? friend_color : avatar_color;
  750. drawImageStack(it->getGlobalPosition(), sAvatarSmallImage, it->getCount(), 3.f, map_avatar_color);
  751. ++it;
  752. }
  753. }
  754. }
  755. void LLWorldMapView::drawFrustum()
  756. {
  757. // Draw frustum
  758. F32 meters_to_pixels = sMapScale/ REGION_WIDTH_METERS;
  759. F32 horiz_fov = LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect();
  760. F32 far_clip_meters = LLViewerCamera::getInstance()->getFar();
  761. F32 far_clip_pixels = far_clip_meters * meters_to_pixels;
  762. F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 );
  763. F32 half_width_pixels = half_width_meters * meters_to_pixels;
  764. // Compute the frustum coordinates. Take the UI scale into account.
  765. F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
  766. F32 ctr_x = (getLocalRect().getWidth() * 0.5f + sPanX) * ui_scale_factor;
  767. F32 ctr_y = (getLocalRect().getHeight() * 0.5f + sPanY) * ui_scale_factor;
  768. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  769. // Since we don't rotate the map, we have to rotate the frustum.
  770. gGL.pushMatrix();
  771. {
  772. gGL.translatef( ctr_x, ctr_y, 0 );
  773. // Draw triangle with more alpha in far pixels to make it
  774. // fade out in distance.
  775. gGL.begin( LLRender::TRIANGLES );
  776. {
  777. // get camera look at and left axes
  778. LLVector3 at_axis = LLViewerCamera::instance().getAtAxis();
  779. LLVector3 left_axis = LLViewerCamera::instance().getLeftAxis();
  780. // grab components along XY plane
  781. LLVector2 cam_lookat(at_axis.mV[VX], at_axis.mV[VY]);
  782. LLVector2 cam_left(left_axis.mV[VX], left_axis.mV[VY]);
  783. // but, when looking near straight up or down...
  784. if (is_approx_zero(cam_lookat.magVecSquared()))
  785. {
  786. //...just fall back to looking down the x axis
  787. cam_lookat = LLVector2(1.f, 0.f); // x axis
  788. cam_left = LLVector2(0.f, 1.f); // y axis
  789. }
  790. // normalize to unit length
  791. cam_lookat.normVec();
  792. cam_left.normVec();
  793. gGL.color4f(1.f, 1.f, 1.f, 0.25f);
  794. gGL.vertex2f( 0, 0 );
  795. gGL.color4f(1.f, 1.f, 1.f, 0.02f);
  796. // use 2d camera vectors to render frustum triangle
  797. LLVector2 vert = cam_lookat * far_clip_pixels + cam_left * half_width_pixels;
  798. gGL.vertex2f(vert.mV[VX], vert.mV[VY]);
  799. vert = cam_lookat * far_clip_pixels - cam_left * half_width_pixels;
  800. gGL.vertex2f(vert.mV[VX], vert.mV[VY]);
  801. }
  802. gGL.end();
  803. }
  804. gGL.popMatrix();
  805. }
  806. LLVector3 LLWorldMapView::globalPosToView( const LLVector3d& global_pos )
  807. {
  808. LLVector3d relative_pos_global = global_pos - gAgentCamera.getCameraPositionGlobal();
  809. LLVector3 pos_local;
  810. pos_local.setVec(relative_pos_global); // convert to floats from doubles
  811. pos_local.mV[VX] *= sMapScale / REGION_WIDTH_METERS;
  812. pos_local.mV[VY] *= sMapScale / REGION_WIDTH_METERS;
  813. // leave Z component in meters
  814. pos_local.mV[VX] += getRect().getWidth() / 2 + sPanX;
  815. pos_local.mV[VY] += getRect().getHeight() / 2 + sPanY;
  816. return pos_local;
  817. }
  818. void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& color, BOOL draw_arrow,
  819. const std::string& label, const std::string& tooltip, S32 vert_offset )
  820. {
  821. LLVector3 pos_local = globalPosToView( pos_global );
  822. S32 x = llround( pos_local.mV[VX] );
  823. S32 y = llround( pos_local.mV[VY] );
  824. LLFontGL* font = LLFontGL::getFontSansSerifSmall();
  825. S32 text_x = x;
  826. S32 text_y = (S32)(y - sTrackCircleImage->getHeight()/2 - font->getLineHeight());
  827. BOOL is_in_window = true;
  828. if( x < 0
  829. || y < 0
  830. || x >= getRect().getWidth()
  831. || y >= getRect().getHeight() )
  832. {
  833. if (draw_arrow)
  834. {
  835. drawTrackingCircle( getRect(), x, y, color, 3, 15 );
  836. drawTrackingArrow( getRect(), x, y, color );
  837. text_x = sTrackingArrowX;
  838. text_y = sTrackingArrowY;
  839. }
  840. is_in_window = false;
  841. }
  842. else if (LLTracker::getTrackingStatus() == LLTracker::TRACKING_LOCATION &&
  843. LLTracker::getTrackedLocationType() != LLTracker::LOCATION_NOTHING)
  844. {
  845. drawTrackingCircle( getRect(), x, y, color, 3, 15 );
  846. }
  847. else
  848. {
  849. drawImage(pos_global, sTrackCircleImage, color);
  850. }
  851. // clamp text position to on-screen
  852. const S32 TEXT_PADDING = DEFAULT_TRACKING_ARROW_SIZE + 2;
  853. S32 half_text_width = llfloor(font->getWidthF32(label) * 0.5f);
  854. text_x = llclamp(text_x, half_text_width + TEXT_PADDING, getRect().getWidth() - half_text_width - TEXT_PADDING);
  855. text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, getRect().getHeight() - llround(font->getLineHeight()) - TEXT_PADDING - vert_offset);
  856. if (label != "")
  857. {
  858. font->renderUTF8(
  859. label, 0,
  860. text_x,
  861. text_y,
  862. LLColor4::white, LLFontGL::HCENTER,
  863. LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW);
  864. if (tooltip != "")
  865. {
  866. text_y -= (S32)font->getLineHeight();
  867. font->renderUTF8(
  868. tooltip, 0,
  869. text_x,
  870. text_y,
  871. LLColor4::white, LLFontGL::HCENTER,
  872. LLFontGL::BASELINE, LLFontGL::NORMAL, LLFontGL::DROP_SHADOW);
  873. }
  874. }
  875. }
  876. // If you change this, then you need to change LLTracker::getTrackedPositionGlobal() as well
  877. LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
  878. {
  879. x -= llfloor((getRect().getWidth() / 2 + sPanX));
  880. y -= llfloor((getRect().getHeight() / 2 + sPanY));
  881. LLVector3 pos_local( (F32)x, (F32)y, 0.f );
  882. pos_local *= ( REGION_WIDTH_METERS / sMapScale );
  883. LLVector3d pos_global;
  884. pos_global.setVec( pos_local );
  885. pos_global += gAgentCamera.getCameraPositionGlobal();
  886. if(gAgent.isGodlike())
  887. {
  888. pos_global.mdV[VZ] = GODLY_TELEPORT_HEIGHT; // Godly height should always be 200.
  889. }
  890. else
  891. {
  892. pos_global.mdV[VZ] = gAgent.getPositionAgent().mV[VZ]; // Want agent's height, not camera's
  893. }
  894. return pos_global;
  895. }
  896. BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
  897. {
  898. LLVector3d pos_global = viewPosToGlobal(x, y);
  899. U64 handle = to_region_handle(pos_global);
  900. std::string tooltip_msg;
  901. LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
  902. if (info)
  903. {
  904. LLViewerRegion *region = gAgent.getRegion();
  905. std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str());
  906. if (!info->isDown())
  907. {
  908. S32 agent_count = info->getAgentCount();
  909. if (region && (region->getHandle() == handle))
  910. {
  911. ++agent_count; // Bump by 1 if we're here
  912. }
  913. // We may not have an agent count when the map is really
  914. // zoomed out, so don't display anything about the count. JC
  915. if (agent_count > 0)
  916. {
  917. LLStringUtil::format_map_t string_args;
  918. string_args["[NUMBER]"] = llformat("%d", agent_count);
  919. message += '\n';
  920. message += getString((agent_count == 1 ? "world_map_person" : "world_map_people") , string_args);
  921. }
  922. }
  923. tooltip_msg.assign( message );
  924. // Optionally show region flags
  925. std::string region_flags = info->getFlagsString();
  926. if (!region_flags.empty())
  927. {
  928. tooltip_msg += '\n';
  929. tooltip_msg += region_flags;
  930. }
  931. const S32 SLOP = 9;
  932. S32 screen_x, screen_y;
  933. localPointToScreen(x, y, &screen_x, &screen_y);
  934. LLRect sticky_rect_screen;
  935. sticky_rect_screen.setCenterAndSize(screen_x, screen_y, SLOP, SLOP);
  936. LLToolTipMgr::instance().show(LLToolTip::Params()
  937. .message(tooltip_msg)
  938. .sticky_rect(sticky_rect_screen));
  939. }
  940. return TRUE;
  941. }
  942. // Pass relative Z of 0 to draw at same level.
  943. // static
  944. static void drawDot(F32 x_pixels, F32 y_pixels,
  945. const LLColor4& color,
  946. F32 relative_z,
  947. F32 dot_radius,
  948. LLUIImagePtr dot_image)
  949. {
  950. const F32 HEIGHT_THRESHOLD = 7.f;
  951. if(-HEIGHT_THRESHOLD <= relative_z && relative_z <= HEIGHT_THRESHOLD)
  952. {
  953. dot_image->draw(llround(x_pixels) - dot_image->getWidth()/2,
  954. llround(y_pixels) - dot_image->getHeight()/2,
  955. color);
  956. }
  957. else
  958. {
  959. // Draw V indicator for above or below
  960. // *TODO: Replace this vector drawing with icons
  961. F32 left = x_pixels - dot_radius;
  962. F32 right = x_pixels + dot_radius;
  963. F32 center = (left + right) * 0.5f;
  964. F32 top = y_pixels + dot_radius;
  965. F32 bottom = y_pixels - dot_radius;
  966. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  967. gGL.color4fv( color.mV );
  968. LLUI::setLineWidth(3.0f);
  969. F32 point = relative_z > HEIGHT_THRESHOLD ? top : bottom; // Y pos of the point of the V
  970. F32 back = relative_z > HEIGHT_THRESHOLD ? bottom : top; // Y pos of the ends of the V
  971. gGL.begin( LLRender::LINES );
  972. gGL.vertex2f(left, back);
  973. gGL.vertex2f(center, point);
  974. gGL.vertex2f(center, point);
  975. gGL.vertex2f(right, back);
  976. gGL.end();
  977. LLUI::setLineWidth(1.0f);
  978. }
  979. }
  980. // Pass relative Z of 0 to draw at same level.
  981. // static
  982. void LLWorldMapView::drawAvatar(F32 x_pixels,
  983. F32 y_pixels,
  984. const LLColor4& color,
  985. F32 relative_z,
  986. F32 dot_radius)
  987. {
  988. const F32 HEIGHT_THRESHOLD = 7.f;
  989. LLUIImagePtr dot_image = sAvatarLevelImage;
  990. if(relative_z < -HEIGHT_THRESHOLD)
  991. {
  992. dot_image = sAvatarBelowImage;
  993. }
  994. else if(relative_z > HEIGHT_THRESHOLD)
  995. {
  996. dot_image = sAvatarAboveImage;
  997. }
  998. S32 dot_width = llround(dot_radius * 2.f);
  999. dot_image->draw(llround(x_pixels - dot_radius),
  1000. llround(y_pixels - dot_radius),
  1001. dot_width,
  1002. dot_width,
  1003. color);
  1004. }
  1005. // Pass relative Z of 0 to draw at same level.
  1006. // static
  1007. void LLWorldMapView::drawTrackingDot( F32 x_pixels,
  1008. F32 y_pixels,
  1009. const LLColor4& color,
  1010. F32 relative_z,
  1011. F32 dot_radius)
  1012. {
  1013. drawDot(x_pixels, y_pixels, color, relative_z, dot_radius, sTrackCircleImage);
  1014. }
  1015. // Pass relative Z of 0 to draw at same level.
  1016. // static
  1017. void LLWorldMapView::drawIconName(F32 x_pixels,
  1018. F32 y_pixels,
  1019. const LLColor4& color,
  1020. const std::string& first_line,
  1021. const std::string& second_line)
  1022. {
  1023. const S32 VERT_PAD = 8;
  1024. S32 text_x = llround(x_pixels);
  1025. S32 text_y = llround(y_pixels
  1026. - BIG_DOT_RADIUS
  1027. - VERT_PAD);
  1028. // render text
  1029. LLFontGL::getFontSansSerif()->renderUTF8(first_line, 0,
  1030. text_x,
  1031. text_y,
  1032. color,
  1033. LLFontGL::HCENTER,
  1034. LLFontGL::TOP,
  1035. LLFontGL::NORMAL,
  1036. LLFontGL::DROP_SHADOW);
  1037. text_y -= llround(LLFontGL::getFontSansSerif()->getLineHeight());
  1038. // render text
  1039. LLFontGL::getFontSansSerif()->renderUTF8(second_line, 0,
  1040. text_x,
  1041. text_y,
  1042. color,
  1043. LLFontGL::HCENTER,
  1044. LLFontGL::TOP,
  1045. LLFontGL::NORMAL,
  1046. LLFontGL::DROP_SHADOW);
  1047. }
  1048. //static
  1049. void LLWorldMapView::drawTrackingCircle( const LLRect& rect, S32 x, S32 y, const LLColor4& color, S32 min_thickness, S32 overlap )
  1050. {
  1051. F32 start_theta = 0.f;
  1052. F32 end_theta = F_TWO_PI;
  1053. F32 x_delta = 0.f;
  1054. F32 y_delta = 0.f;
  1055. if (x < 0)
  1056. {
  1057. x_delta = 0.f - (F32)x;
  1058. start_theta = F_PI + F_PI_BY_TWO;
  1059. end_theta = F_TWO_PI + F_PI_BY_TWO;
  1060. }
  1061. else if (x > rect.getWidth())
  1062. {
  1063. x_delta = (F32)(x - rect.getWidth());
  1064. start_theta = F_PI_BY_TWO;
  1065. end_theta = F_PI + F_PI_BY_TWO;
  1066. }
  1067. if (y < 0)
  1068. {
  1069. y_delta = 0.f - (F32)y;
  1070. if (x < 0)
  1071. {
  1072. start_theta = 0.f;
  1073. end_theta = F_PI_BY_TWO;
  1074. }
  1075. else if (x > rect.getWidth())
  1076. {
  1077. start_theta = F_PI_BY_TWO;
  1078. end_theta = F_PI;
  1079. }
  1080. else
  1081. {
  1082. start_theta = 0.f;
  1083. end_theta = F_PI;
  1084. }
  1085. }
  1086. else if (y > rect.getHeight())
  1087. {
  1088. y_delta = (F32)(y - rect.getHeight());
  1089. if (x < 0)
  1090. {
  1091. start_theta = F_PI + F_PI_BY_TWO;
  1092. end_theta = F_TWO_PI;
  1093. }
  1094. else if (x > rect.getWidth())
  1095. {
  1096. start_theta = F_PI;
  1097. end_theta = F_PI + F_PI_BY_TWO;
  1098. }
  1099. else
  1100. {
  1101. start_theta = F_PI;
  1102. end_theta = F_TWO_PI;
  1103. }
  1104. }
  1105. F32 distance = sqrtf(x_delta * x_delta + y_delta * y_delta);
  1106. distance = llmax(0.1f, distance);
  1107. F32 outer_radius = distance + (1.f + (9.f * sqrtf(x_delta * y_delta) / distance)) * (F32)overlap;
  1108. F32 inner_radius = outer_radius - (F32)min_thickness;
  1109. F32 angle_adjust_x = asin(x_delta / outer_radius);
  1110. F32 angle_adjust_y = asin(y_delta / outer_radius);
  1111. if (angle_adjust_x)
  1112. {
  1113. if (angle_adjust_y)
  1114. {
  1115. F32 angle_adjust = llmin(angle_adjust_x, angle_adjust_y);
  1116. start_theta += angle_adjust;
  1117. end_theta -= angle_adjust;
  1118. }
  1119. else
  1120. {
  1121. start_theta += angle_adjust_x;
  1122. end_theta -= angle_adjust_x;
  1123. }
  1124. }
  1125. else if (angle_adjust_y)
  1126. {
  1127. start_theta += angle_adjust_y;
  1128. end_theta -= angle_adjust_y;
  1129. }
  1130. gGL.matrixMode(LLRender::MM_MODELVIEW);
  1131. gGL.pushMatrix();
  1132. gGL.translatef((F32)x, (F32)y, 0.f);
  1133. gl_washer_segment_2d(inner_radius, outer_radius, start_theta, end_theta, 40, color, color);
  1134. gGL.popMatrix();
  1135. }
  1136. // static
  1137. void LLWorldMapView::drawTrackingArrow(const LLRect& rect, S32 x, S32 y,
  1138. const LLColor4& color,
  1139. S32 arrow_size)
  1140. {
  1141. F32 x_center = (F32)rect.getWidth() / 2.f;
  1142. F32 y_center = (F32)rect.getHeight() / 2.f;
  1143. F32 x_clamped = (F32)llclamp( x, 0, rect.getWidth() - arrow_size );
  1144. F32 y_clamped = (F32)llclamp( y, 0, rect.getHeight() - arrow_size );
  1145. F32 slope = (F32)(y - y_center) / (F32)(x - x_center);
  1146. F32 window_ratio = (F32)rect.getHeight() / (F32)rect.getWidth();
  1147. if (llabs(slope) > window_ratio && y_clamped != (F32)y)
  1148. {
  1149. // clamp by y
  1150. x_clamped = (y_clamped - y_center) / slope + x_center;
  1151. // adjust for arrow size
  1152. x_clamped = llclamp(x_clamped , 0.f, (F32)(rect.getWidth() - arrow_size) );
  1153. }
  1154. else if (x_clamped != (F32)x)
  1155. {
  1156. // clamp by x
  1157. y_clamped = (x_clamped - x_center) * slope + y_center;
  1158. // adjust for arrow size
  1159. y_clamped = llclamp( y_clamped, 0.f, (F32)(rect.getHeight() - arrow_size) );
  1160. }
  1161. // *FIX: deal with non-square window properly.
  1162. // I do not understand what this comment means -- is it actually
  1163. // broken or is it correctly dealing with non-square
  1164. // windows. Phoenix 2007-01-03.
  1165. S32 half_arrow_size = (S32) (0.5f * arrow_size);
  1166. F32 angle = atan2( y + half_arrow_size - y_center, x + half_arrow_size - x_center);
  1167. sTrackingArrowX = llfloor(x_clamped);
  1168. sTrackingArrowY = llfloor(y_clamped);
  1169. gl_draw_scaled_rotated_image(
  1170. sTrackingArrowX,
  1171. sTrackingArrowY,
  1172. arrow_size, arrow_size,
  1173. RAD_TO_DEG * angle,
  1174. sTrackArrowImage->getImage(),
  1175. color);
  1176. }
  1177. void LLWorldMapView::setDirectionPos( LLTextBox* text_box, F32 rotation )
  1178. {
  1179. // Rotation is in radians.
  1180. // Rotation of 0 means x = 1, y = 0 on the unit circle.
  1181. F32 map_half_height = getRect().getHeight() * 0.5f;
  1182. F32 map_half_width = getRect().getWidth() * 0.5f;
  1183. F32 text_half_height = text_box->getRect().getHeight() * 0.5f;
  1184. F32 text_half_width = text_box->getRect().getWidth() * 0.5f;
  1185. F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width );
  1186. text_box->setOrigin(
  1187. llround(map_half_width - text_half_width + radius * cos( rotation )),
  1188. llround(map_half_height - text_half_height + radius * sin( rotation )) );
  1189. }
  1190. void LLWorldMapView::updateDirections()
  1191. {
  1192. S32 width = getRect().getWidth();
  1193. S32 height = getRect().getHeight();
  1194. S32 text_height = mTextBoxNorth->getRect().getHeight();
  1195. S32 text_width = mTextBoxNorth->getRect().getWidth();
  1196. const S32 PAD = 2;
  1197. S32 top = height - text_height - PAD;
  1198. S32 left = PAD*2;
  1199. S32 bottom = PAD;
  1200. S32 right = width - text_width - PAD;
  1201. S32 center_x = width/2 - text_width/2;
  1202. S32 center_y = height/2 - text_height/2;
  1203. mTextBoxNorth->setOrigin( center_x, top );
  1204. mTextBoxEast->setOrigin( right, center_y );
  1205. mTextBoxSouth->setOrigin( center_x, bottom );
  1206. mTextBoxWest->setOrigin( left, center_y );
  1207. // These have wider text boxes
  1208. text_width = mTextBoxNorthWest->getRect().getWidth();
  1209. right = width - text_width - PAD;
  1210. mTextBoxNorthWest->setOrigin(left, top);
  1211. mTextBoxNorthEast->setOrigin(right, top);
  1212. mTextBoxSouthWest->setOrigin(left, bottom);
  1213. mTextBoxSouthEast->setOrigin(right, bottom);
  1214. // S32 hint_width = mTextBoxScrollHint->getRect().getWidth();
  1215. // mTextBoxScrollHint->setOrigin( width - hint_width - text_width - 2 * PAD,
  1216. // PAD * 2 + text_height );
  1217. }
  1218. void LLWorldMapView::reshape( S32 width, S32 height, BOOL called_from_parent )
  1219. {
  1220. LLView::reshape( width, height, called_from_parent );
  1221. }
  1222. bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track)
  1223. {
  1224. LLVector3 pos_view = globalPosToView(item.getGlobalPosition());
  1225. S32 item_x = llround(pos_view.mV[VX]);
  1226. S32 item_y = llround(pos_view.mV[VY]);
  1227. if (x < item_x - BIG_DOT_RADIUS) return false;
  1228. if (x > item_x + BIG_DOT_RADIUS) return false;
  1229. if (y < item_y - BIG_DOT_RADIUS) return false;
  1230. if (y > item_y + BIG_DOT_RADIUS) return false;
  1231. LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromHandle(item.getRegionHandle());
  1232. if (sim_info)
  1233. {
  1234. if (track)
  1235. {
  1236. gFloaterWorldMap->trackLocation(item.getGlobalPosition());
  1237. }
  1238. }
  1239. if (track)
  1240. {
  1241. gFloaterWorldMap->trackGenericItem(item);
  1242. }
  1243. // item.setSelected(true);
  1244. *id = item.getUUID();
  1245. return true;
  1246. }
  1247. // Handle a click, which might be on a dot
  1248. void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask,
  1249. S32* hit_type,
  1250. LLUUID* id)
  1251. {
  1252. LLVector3d pos_global = viewPosToGlobal(x, y);
  1253. // *HACK: Adjust Z values automatically for liaisons & gods so
  1254. // we swoop down when they click on the map. Sadly, the P2P
  1255. // branch does not pay attention to this value; however, the
  1256. // Distributed Messaging branch honors it.
  1257. if(gAgent.isGodlike())
  1258. {
  1259. pos_global.mdV[VZ] = 200.0;
  1260. }
  1261. *hit_type = 0; // hit nothing
  1262. LLWorldMap::getInstance()->cancelTracking();
  1263. S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
  1264. // If the zoom level is not too far out already, test hits
  1265. if (level <= DRAW_SIMINFO_THRESHOLD)
  1266. {
  1267. bool show_mature = gAgent.canAccessMature() && gSavedSettings.getBOOL("ShowMatureEvents");
  1268. bool show_adult = gAgent.canAccessAdult() && gSavedSettings.getBOOL("ShowAdultEvents");
  1269. // Test hits if trackable data are displayed, otherwise, we don't even bother
  1270. if (gSavedSettings.getBOOL("MapShowEvents") || show_mature || show_adult || gSavedSettings.getBOOL("MapShowLandForSale"))
  1271. {
  1272. // Iterate through the visible regions
  1273. for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
  1274. {
  1275. U64 handle = *iter;
  1276. LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
  1277. if ((siminfo == NULL) || (siminfo->isDown()))
  1278. {
  1279. continue;
  1280. }
  1281. // If on screen check hits with the visible item lists
  1282. if (gSavedSettings.getBOOL("MapShowEvents"))
  1283. {
  1284. LLSimInfo::item_info_list_t::const_iterator it = siminfo->getPGEvent().begin();
  1285. while (it != siminfo->getPGEvent().end())
  1286. {
  1287. LLItemInfo event = *it;
  1288. if (checkItemHit(x, y, event, id, false))
  1289. {
  1290. *hit_type = MAP_ITEM_PG_EVENT;
  1291. mItemPicked = TRUE;
  1292. gFloaterWorldMap->trackEvent(event);
  1293. return;
  1294. }
  1295. ++it;
  1296. }
  1297. }
  1298. if (show_mature)
  1299. {
  1300. LLSimInfo::item_info_list_t::const_iterator it = siminfo->getMatureEvent().begin();
  1301. while (it != siminfo->getMatureEvent().end())
  1302. {
  1303. LLItemInfo event = *it;
  1304. if (checkItemHit(x, y, event, id, false))
  1305. {
  1306. *hit_type = MAP_ITEM_MATURE_EVENT;
  1307. mItemPicked = TRUE;
  1308. gFloaterWorldMap->trackEvent(event);
  1309. return;
  1310. }
  1311. ++it;
  1312. }
  1313. }
  1314. if (show_adult)
  1315. {
  1316. LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAdultEvent().begin();
  1317. while (it != siminfo->getAdultEvent().end())
  1318. {
  1319. LLItemInfo event = *it;
  1320. if (checkItemHit(x, y, event, id, false))
  1321. {
  1322. *hit_type = MAP_ITEM_ADULT_EVENT;
  1323. mItemPicked = TRUE;
  1324. gFloaterWorldMap->trackEvent(event);
  1325. return;
  1326. }
  1327. ++it;
  1328. }
  1329. }
  1330. if (gSavedSettings.getBOOL("MapShowLandForSale"))
  1331. {
  1332. LLSimInfo::item_info_list_t::const_iterator it = siminfo->getLandForSale().begin();
  1333. while (it != siminfo->getLandForSale().end())
  1334. {
  1335. LLItemInfo event = *it;
  1336. if (checkItemHit(x, y, event, id, true))
  1337. {
  1338. *hit_type = MAP_ITEM_LAND_FOR_SALE;
  1339. mItemPicked = TRUE;
  1340. return;
  1341. }
  1342. ++it;
  1343. }
  1344. // for 1.23, we're showing normal land and adult land in the same UI; you don't
  1345. // get a choice about which ones you want. If you're currently asking for adult
  1346. // content and land you'll get the adult land.
  1347. if (gAgent.canAccessAdult())
  1348. {
  1349. LLSimInfo::item_info_list_t::const_iterator it = siminfo->getLandForSaleAdult().begin();
  1350. while (it != siminfo->getLandForSaleAdult().end())
  1351. {
  1352. LLItemInfo event = *it;
  1353. if (checkItemHit(x, y, event, id, true))
  1354. {
  1355. *hit_type = MAP_ITEM_LAND_FOR_SALE_ADULT;
  1356. mItemPicked = TRUE;
  1357. return;
  1358. }
  1359. ++it;
  1360. }
  1361. }
  1362. }
  1363. }
  1364. }
  1365. }
  1366. // If we get here, we haven't clicked on anything
  1367. gFloaterWorldMap->trackLocation(pos_global);
  1368. mItemPicked = FALSE;
  1369. *id = LLUUID::null;
  1370. return;
  1371. }
  1372. BOOL outside_slop(S32 x, S32 y, S32 start_x, S32 start_y)
  1373. {
  1374. S32 dx = x - start_x;
  1375. S32 dy = y - start_y;
  1376. return (dx <= -2 || 2 <= dx || dy <= -2 || 2 <= dy);
  1377. }
  1378. BOOL LLWorldMapView::handleMouseDown( S32 x, S32 y, MASK mask )
  1379. {
  1380. gFocusMgr.setMouseCapture( this );
  1381. mMouseDownPanX = llround(sPanX);
  1382. mMouseDownPanY = llround(sPanY);
  1383. mMouseDownX = x;
  1384. mMouseDownY = y;
  1385. sHandledLastClick = TRUE;
  1386. return TRUE;
  1387. }
  1388. BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask )
  1389. {
  1390. if (hasMouseCapture())
  1391. {
  1392. if (mPanning)
  1393. {
  1394. // restore mouse cursor
  1395. S32 local_x, local_y;
  1396. local_x = mMouseDownX + llfloor(sPanX - mMouseDownPanX);
  1397. local_y = mMouseDownY + llfloor(sPanY - mMouseDownPanY);
  1398. LLRect clip_rect = getRect();
  1399. clip_rect.stretch(-8);
  1400. clip_rect.clipPointToRect(mMouseDownX, mMouseDownY, local_x, local_y);
  1401. LLUI::setMousePositionLocal(this, local_x, local_y);
  1402. // finish the pan
  1403. mPanning = FALSE;
  1404. mMouseDownX = 0;
  1405. mMouseDownY = 0;
  1406. }
  1407. else
  1408. {
  1409. // ignore whether we hit an event or not
  1410. S32 hit_type;
  1411. LLUUID id;
  1412. handleClick(x, y, mask, &hit_type, &id);
  1413. }
  1414. gViewerWindow->showCursor();
  1415. gFocusMgr.setMouseCapture( NULL );
  1416. return TRUE;
  1417. }
  1418. return FALSE;
  1419. }
  1420. void LLWorldMapView::updateVisibleBlocks()
  1421. {
  1422. if (LLWorldMipmap::scaleToLevel(sMapScale) > DRAW_SIMINFO_THRESHOLD)
  1423. {
  1424. // If we're zoomed out too much, we just don't load all those sim info: too much!
  1425. return;
  1426. }
  1427. // Load the blocks visible in the current World Map view
  1428. // Get the World Map view coordinates and boundaries
  1429. LLVector3d camera_global = gAgentCamera.getCameraPositionGlobal();
  1430. const S32 width = getRect().getWidth();
  1431. const S32 height = getRect().getHeight();
  1432. const F32 half_width = F32(width) / 2.0f;
  1433. const F32 half_height = F32(height) / 2.0f;
  1434. // Compute center into sim grid coordinates
  1435. S32 world_center_x = S32((-sPanX / sMapScale) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
  1436. S32 world_center_y = S32((-sPanY / sMapScale) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
  1437. // Compute the boundaries into sim grid coordinates
  1438. S32 world_left = world_center_x - S32(half_width / sMapScale) - 1;
  1439. S32 world_right = world_center_x + S32(half_width / sMapScale) + 1;
  1440. S32 world_bottom = world_center_y - S32(half_height / sMapScale) - 1;
  1441. S32 world_top = world_center_y + S32(half_height / sMapScale) + 1;
  1442. //LL_INFOS("World Map") << "LLWorldMapView::updateVisibleBlocks() : sMapScale = " << sMapScale << ", left = " << world_left << ", right = " << world_right << ", bottom = " << world_bottom << ", top = " << world_top << LL_ENDL;
  1443. LLWorldMap::getInstance()->updateRegions(world_left, world_bottom, world_right, world_top);
  1444. }
  1445. BOOL LLWorldMapView::handleHover( S32 x, S32 y, MASK mask )
  1446. {
  1447. if (hasMouseCapture())
  1448. {
  1449. if (mPanning || outside_slop(x, y, mMouseDownX, mMouseDownY))
  1450. {
  1451. // just started panning, so hide cursor
  1452. if (!mPanning)
  1453. {
  1454. mPanning = TRUE;
  1455. gViewerWindow->hideCursor();
  1456. }
  1457. F32 delta_x = (F32)(gViewerWindow->getCurrentMouseDX());
  1458. F32 delta_y = (F32)(gViewerWindow->getCurrentMouseDY());
  1459. // Set pan to value at start of drag + offset
  1460. sPanX += delta_x;
  1461. sPanY += delta_y;
  1462. sTargetPanX = sPanX;
  1463. sTargetPanY = sPanY;
  1464. gViewerWindow->moveCursorToCenter();
  1465. }
  1466. // doesn't matter, cursor should be hidden
  1467. gViewerWindow->setCursor(UI_CURSOR_CROSS );
  1468. return TRUE;
  1469. }
  1470. else
  1471. {
  1472. // While we're waiting for data from the tracker, we're busy. JC
  1473. LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
  1474. if (LLTracker::isTracking(NULL)
  1475. && pos_global.isExactlyZero())
  1476. {
  1477. gViewerWindow->setCursor( UI_CURSOR_WAIT );
  1478. }
  1479. else
  1480. {
  1481. gViewerWindow->setCursor( UI_CURSOR_CROSS );
  1482. }
  1483. lldebugst(LLERR_USER_INPUT) << "hover handled by LLWorldMapView" << llendl;
  1484. return TRUE;
  1485. }
  1486. }
  1487. BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask )
  1488. {
  1489. if( sHandledLastClick )
  1490. {
  1491. S32 hit_type;
  1492. LLUUID id;
  1493. handleClick(x, y, mask, &hit_type, &id);
  1494. switch (hit_type)
  1495. {
  1496. case MAP_ITEM_PG_EVENT:
  1497. case MAP_ITEM_MATURE_EVENT:
  1498. case MAP_ITEM_ADULT_EVENT:
  1499. {
  1500. LLFloaterReg::hideInstance("world_map");
  1501. // This is an ungainly hack
  1502. std::string uuid_str;
  1503. S32 event_id;
  1504. id.toString(uuid_str);
  1505. uuid_str = uuid_str.substr(28);
  1506. sscanf(uuid_str.c_str(), "%X", &event_id);
  1507. // Invoke the event details floater if someone is clicking on an event.
  1508. LLSD params(LLSD::emptyArray());
  1509. params.append(event_id);
  1510. LLCommandDispatcher::dispatch("event", params, LLSD(), NULL, "clicked", true);
  1511. break;
  1512. }
  1513. case MAP_ITEM_LAND_FOR_SALE:
  1514. case MAP_ITEM_LAND_FOR_SALE_ADULT:
  1515. {
  1516. LLFloaterReg::hideInstance("world_map");
  1517. LLFloaterReg::showInstance("search", LLSD().with("category", "destinations").with("query", id));
  1518. break;
  1519. }
  1520. case MAP_ITEM_CLASSIFIED:
  1521. {
  1522. LLFloaterReg::hideInstance("world_map");
  1523. LLFloaterReg::showInstance("search", LLSD().with("category", "classifieds").with("query", id));
  1524. break;
  1525. }
  1526. default:
  1527. {
  1528. if (LLWorldMap::getInstance()->isTracking())
  1529. {
  1530. LLWorldMap::getInstance()->setTrackingDoubleClick();
  1531. }
  1532. else
  1533. {
  1534. // Teleport if we got a valid location
  1535. LLVector3d pos_global = viewPosToGlobal(x,y);
  1536. LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
  1537. if (sim_info && !sim_info->isDown())
  1538. {
  1539. gAgent.teleportViaLocation( pos_global );
  1540. }
  1541. }
  1542. }
  1543. };
  1544. return TRUE;
  1545. }
  1546. return FALSE;
  1547. }