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

游戏引擎

开发平台:

C++ Builder

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