/indra/newview/llnetmap.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 1010 lines · 778 code · 150 blank · 82 comment · 113 complexity · bd42ec7bea077128e9fa75a75d86ea21 MD5 · raw file

  1. /**
  2. * @file llnetmap.cpp
  3. * @author James Cook
  4. * @brief Display of surrounding regions, objects, and agents.
  5. *
  6. * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  7. * Second Life Viewer Source Code
  8. * Copyright (C) 2001-2010, Linden Research, Inc.
  9. *
  10. * This library is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU Lesser General Public
  12. * License as published by the Free Software Foundation;
  13. * version 2.1 of the License only.
  14. *
  15. * This library is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  18. * Lesser General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU Lesser General Public
  21. * License along with this library; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. *
  24. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  25. * $/LicenseInfo$
  26. */
  27. #include "llviewerprecompiledheaders.h"
  28. #include "llnetmap.h"
  29. // Library includes (should move below)
  30. #include "indra_constants.h"
  31. #include "llavatarnamecache.h"
  32. #include "llmath.h"
  33. #include "llfloaterreg.h"
  34. #include "llfocusmgr.h"
  35. #include "lllocalcliprect.h"
  36. #include "llrender.h"
  37. #include "llui.h"
  38. #include "lltooltip.h"
  39. #include "llglheaders.h"
  40. // Viewer includes
  41. #include "llagent.h"
  42. #include "llagentcamera.h"
  43. #include "llappviewer.h" // for gDisconnected
  44. #include "llcallingcard.h" // LLAvatarTracker
  45. #include "llfloaterworldmap.h"
  46. #include "lltracker.h"
  47. #include "llsurface.h"
  48. #include "llviewercamera.h"
  49. #include "llviewercontrol.h"
  50. #include "llviewertexture.h"
  51. #include "llviewertexturelist.h"
  52. #include "llviewermenu.h"
  53. #include "llviewerobjectlist.h"
  54. #include "llviewerregion.h"
  55. #include "llviewerwindow.h"
  56. #include "llworld.h"
  57. #include "llworldmapview.h" // shared draw code
  58. static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map");
  59. const F32 LLNetMap::MAP_SCALE_MIN = 32;
  60. const F32 LLNetMap::MAP_SCALE_MID = 1024;
  61. const F32 LLNetMap::MAP_SCALE_MAX = 4096;
  62. const F32 MAP_SCALE_INCREMENT = 16;
  63. const F32 MAP_SCALE_ZOOM_FACTOR = 1.04f; // Zoom in factor per click of scroll wheel (4%)
  64. const F32 MIN_DOT_RADIUS = 3.5f;
  65. const F32 DOT_SCALE = 0.75f;
  66. const F32 MIN_PICK_SCALE = 2.f;
  67. const S32 MOUSE_DRAG_SLOP = 2; // How far the mouse needs to move before we think it's a drag
  68. LLNetMap::LLNetMap (const Params & p)
  69. : LLUICtrl (p),
  70. mBackgroundColor (p.bg_color()),
  71. mScale( MAP_SCALE_MID ),
  72. mPixelsPerMeter( MAP_SCALE_MID / REGION_WIDTH_METERS ),
  73. mObjectMapTPM(0.f),
  74. mObjectMapPixels(0.f),
  75. mTargetPan(0.f, 0.f),
  76. mCurPan(0.f, 0.f),
  77. mStartPan(0.f, 0.f),
  78. mMouseDown(0, 0),
  79. mPanning(false),
  80. mUpdateNow(false),
  81. mObjectImageCenterGlobal( gAgentCamera.getCameraPositionGlobal() ),
  82. mObjectRawImagep(),
  83. mObjectImagep(),
  84. mClosestAgentToCursor(),
  85. mClosestAgentAtLastRightClick(),
  86. mToolTipMsg(),
  87. mPopupMenu(NULL)
  88. {
  89. mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
  90. setScale(gSavedSettings.getF32("MiniMapScale"));
  91. }
  92. LLNetMap::~LLNetMap()
  93. {
  94. gSavedSettings.setF32("MiniMapScale", mScale);
  95. }
  96. BOOL LLNetMap::postBuild()
  97. {
  98. LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
  99. registrar.add("Minimap.Zoom", boost::bind(&LLNetMap::handleZoom, this, _2));
  100. registrar.add("Minimap.Tracker", boost::bind(&LLNetMap::handleStopTracking, this, _2));
  101. mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
  102. return TRUE;
  103. }
  104. void LLNetMap::setScale( F32 scale )
  105. {
  106. scale = llclamp(scale, MAP_SCALE_MIN, MAP_SCALE_MAX);
  107. mCurPan *= scale / mScale;
  108. mScale = scale;
  109. if (mObjectImagep.notNull())
  110. {
  111. F32 width = (F32)(getRect().getWidth());
  112. F32 height = (F32)(getRect().getHeight());
  113. F32 diameter = sqrt(width * width + height * height);
  114. F32 region_widths = diameter / mScale;
  115. F32 meters = region_widths * LLWorld::getInstance()->getRegionWidthInMeters();
  116. F32 num_pixels = (F32)mObjectImagep->getWidth();
  117. mObjectMapTPM = num_pixels / meters;
  118. mObjectMapPixels = diameter;
  119. }
  120. mPixelsPerMeter = mScale / REGION_WIDTH_METERS;
  121. mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
  122. mUpdateNow = true;
  123. }
  124. ///////////////////////////////////////////////////////////////////////////////////
  125. void LLNetMap::draw()
  126. {
  127. static LLFrameTimer map_timer;
  128. static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white);
  129. static LLUIColor map_avatar_friend_color = LLUIColorTable::instance().getColor("MapAvatarFriendColor", LLColor4::white);
  130. static LLUIColor map_track_color = LLUIColorTable::instance().getColor("MapTrackColor", LLColor4::white);
  131. static LLUIColor map_track_disabled_color = LLUIColorTable::instance().getColor("MapTrackDisabledColor", LLColor4::white);
  132. static LLUIColor map_frustum_color = LLUIColorTable::instance().getColor("MapFrustumColor", LLColor4::white);
  133. static LLUIColor map_frustum_rotating_color = LLUIColorTable::instance().getColor("MapFrustumRotatingColor", LLColor4::white);
  134. if (mObjectImagep.isNull())
  135. {
  136. createObjectImage();
  137. }
  138. static LLUICachedControl<bool> auto_center("MiniMapAutoCenter", true);
  139. if (auto_center)
  140. {
  141. mCurPan = lerp(mCurPan, mTargetPan, LLCriticalDamp::getInterpolant(0.1f));
  142. }
  143. // Prepare a scissor region
  144. F32 rotation = 0;
  145. gGL.pushMatrix();
  146. gGL.pushUIMatrix();
  147. LLVector3 offset = gGL.getUITranslation();
  148. LLVector3 scale = gGL.getUIScale();
  149. gGL.loadIdentity();
  150. gGL.loadUIIdentity();
  151. gGL.scalef(scale.mV[0], scale.mV[1], scale.mV[2]);
  152. gGL.translatef(offset.mV[0], offset.mV[1], offset.mV[2]);
  153. {
  154. LLLocalClipRect clip(getLocalRect());
  155. {
  156. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  157. gGL.matrixMode(LLRender::MM_MODELVIEW);
  158. // Draw background rectangle
  159. LLColor4 background_color = mBackgroundColor.get();
  160. gGL.color4fv( background_color.mV );
  161. gl_rect_2d(0, getRect().getHeight(), getRect().getWidth(), 0);
  162. }
  163. // region 0,0 is in the middle
  164. S32 center_sw_left = getRect().getWidth() / 2 + llfloor(mCurPan.mV[VX]);
  165. S32 center_sw_bottom = getRect().getHeight() / 2 + llfloor(mCurPan.mV[VY]);
  166. gGL.pushMatrix();
  167. gGL.translatef( (F32) center_sw_left, (F32) center_sw_bottom, 0.f);
  168. static LLUICachedControl<bool> rotate_map("MiniMapRotate", true);
  169. if( rotate_map )
  170. {
  171. // rotate subsequent draws to agent rotation
  172. rotation = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] );
  173. gGL.rotatef( rotation * RAD_TO_DEG, 0.f, 0.f, 1.f);
  174. }
  175. // figure out where agent is
  176. S32 region_width = llround(LLWorld::getInstance()->getRegionWidthInMeters());
  177. for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
  178. iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
  179. {
  180. LLViewerRegion* regionp = *iter;
  181. // Find x and y position relative to camera's center.
  182. LLVector3 origin_agent = regionp->getOriginAgent();
  183. LLVector3 rel_region_pos = origin_agent - gAgentCamera.getCameraPositionAgent();
  184. F32 relative_x = (rel_region_pos.mV[0] / region_width) * mScale;
  185. F32 relative_y = (rel_region_pos.mV[1] / region_width) * mScale;
  186. // background region rectangle
  187. F32 bottom = relative_y;
  188. F32 left = relative_x;
  189. F32 top = bottom + mScale ;
  190. F32 right = left + mScale ;
  191. if (regionp == gAgent.getRegion())
  192. {
  193. gGL.color4f(1.f, 1.f, 1.f, 1.f);
  194. }
  195. else
  196. {
  197. gGL.color4f(0.8f, 0.8f, 0.8f, 1.f);
  198. }
  199. if (!regionp->isAlive())
  200. {
  201. gGL.color4f(1.f, 0.5f, 0.5f, 1.f);
  202. }
  203. // Draw using texture.
  204. gGL.getTexUnit(0)->bind(regionp->getLand().getSTexture());
  205. gGL.begin(LLRender::QUADS);
  206. gGL.texCoord2f(0.f, 1.f);
  207. gGL.vertex2f(left, top);
  208. gGL.texCoord2f(0.f, 0.f);
  209. gGL.vertex2f(left, bottom);
  210. gGL.texCoord2f(1.f, 0.f);
  211. gGL.vertex2f(right, bottom);
  212. gGL.texCoord2f(1.f, 1.f);
  213. gGL.vertex2f(right, top);
  214. gGL.end();
  215. // Draw water
  216. gGL.setAlphaRejectSettings(LLRender::CF_GREATER, ABOVE_WATERLINE_ALPHA / 255.f);
  217. {
  218. if (regionp->getLand().getWaterTexture())
  219. {
  220. gGL.getTexUnit(0)->bind(regionp->getLand().getWaterTexture());
  221. gGL.begin(LLRender::QUADS);
  222. gGL.texCoord2f(0.f, 1.f);
  223. gGL.vertex2f(left, top);
  224. gGL.texCoord2f(0.f, 0.f);
  225. gGL.vertex2f(left, bottom);
  226. gGL.texCoord2f(1.f, 0.f);
  227. gGL.vertex2f(right, bottom);
  228. gGL.texCoord2f(1.f, 1.f);
  229. gGL.vertex2f(right, top);
  230. gGL.end();
  231. }
  232. }
  233. gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
  234. }
  235. // Redraw object layer periodically
  236. if (mUpdateNow || (map_timer.getElapsedTimeF32() > 0.5f))
  237. {
  238. mUpdateNow = false;
  239. // Locate the centre of the object layer, accounting for panning
  240. LLVector3 new_center = globalPosToView(gAgentCamera.getCameraPositionGlobal());
  241. new_center.mV[VX] -= mCurPan.mV[VX];
  242. new_center.mV[VY] -= mCurPan.mV[VY];
  243. new_center.mV[VZ] = 0.f;
  244. mObjectImageCenterGlobal = viewPosToGlobal(llfloor(new_center.mV[VX]), llfloor(new_center.mV[VY]));
  245. // Create the base texture.
  246. U8 *default_texture = mObjectRawImagep->getData();
  247. memset( default_texture, 0, mObjectImagep->getWidth() * mObjectImagep->getHeight() * mObjectImagep->getComponents() );
  248. // Draw objects
  249. gObjectList.renderObjectsForMap(*this);
  250. mObjectImagep->setSubImage(mObjectRawImagep, 0, 0, mObjectImagep->getWidth(), mObjectImagep->getHeight());
  251. map_timer.reset();
  252. }
  253. LLVector3 map_center_agent = gAgent.getPosAgentFromGlobal(mObjectImageCenterGlobal);
  254. map_center_agent -= gAgentCamera.getCameraPositionAgent();
  255. map_center_agent.mV[VX] *= mScale/region_width;
  256. map_center_agent.mV[VY] *= mScale/region_width;
  257. gGL.getTexUnit(0)->bind(mObjectImagep);
  258. F32 image_half_width = 0.5f*mObjectMapPixels;
  259. F32 image_half_height = 0.5f*mObjectMapPixels;
  260. gGL.begin(LLRender::QUADS);
  261. gGL.texCoord2f(0.f, 1.f);
  262. gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, image_half_height + map_center_agent.mV[VY]);
  263. gGL.texCoord2f(0.f, 0.f);
  264. gGL.vertex2f(map_center_agent.mV[VX] - image_half_width, map_center_agent.mV[VY] - image_half_height);
  265. gGL.texCoord2f(1.f, 0.f);
  266. gGL.vertex2f(image_half_width + map_center_agent.mV[VX], map_center_agent.mV[VY] - image_half_height);
  267. gGL.texCoord2f(1.f, 1.f);
  268. gGL.vertex2f(image_half_width + map_center_agent.mV[VX], image_half_height + map_center_agent.mV[VY]);
  269. gGL.end();
  270. gGL.popMatrix();
  271. LLVector3d pos_global;
  272. LLVector3 pos_map;
  273. // Mouse pointer in local coordinates
  274. S32 local_mouse_x;
  275. S32 local_mouse_y;
  276. //localMouse(&local_mouse_x, &local_mouse_y);
  277. LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
  278. mClosestAgentToCursor.setNull();
  279. F32 closest_dist_squared = F32_MAX; // value will be overridden in the loop
  280. F32 min_pick_dist_squared = (mDotRadius * MIN_PICK_SCALE) * (mDotRadius * MIN_PICK_SCALE);
  281. // Draw avatars
  282. for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
  283. iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
  284. {
  285. LLViewerRegion* regionp = *iter;
  286. const LLVector3d& origin_global = regionp->getOriginGlobal();
  287. S32 count = regionp->mMapAvatars.count();
  288. S32 i;
  289. LLVector3 pos_local;
  290. U32 compact_local;
  291. U8 bits;
  292. // TODO: it'd be very cool to draw these in sorted order from lowest Z to highest.
  293. // just be careful to sort the avatar IDs along with the positions. -MG
  294. for (i = 0; i < count; i++)
  295. {
  296. compact_local = regionp->mMapAvatars.get(i);
  297. bits = compact_local & 0xFF;
  298. pos_local.mV[VZ] = F32(bits) * 4.f;
  299. compact_local >>= 8;
  300. bits = compact_local & 0xFF;
  301. pos_local.mV[VY] = (F32)bits;
  302. compact_local >>= 8;
  303. bits = compact_local & 0xFF;
  304. pos_local.mV[VX] = (F32)bits;
  305. pos_global.setVec( pos_local );
  306. pos_global += origin_global;
  307. pos_map = globalPosToView(pos_global);
  308. LLUUID uuid(NULL);
  309. BOOL show_as_friend = FALSE;
  310. if( i < regionp->mMapAvatarIDs.count())
  311. {
  312. uuid = regionp->mMapAvatarIDs.get(i);
  313. show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL);
  314. }
  315. LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color;
  316. LLWorldMapView::drawAvatar(
  317. pos_map.mV[VX], pos_map.mV[VY],
  318. color,
  319. pos_map.mV[VZ], mDotRadius);
  320. if(uuid.notNull())
  321. {
  322. bool selected = false;
  323. uuid_vec_t::iterator sel_iter = gmSelected.begin();
  324. for (; sel_iter != gmSelected.end(); sel_iter++)
  325. {
  326. if(*sel_iter == uuid)
  327. {
  328. selected = true;
  329. break;
  330. }
  331. }
  332. if(selected)
  333. {
  334. if( (pos_map.mV[VX] < 0) ||
  335. (pos_map.mV[VY] < 0) ||
  336. (pos_map.mV[VX] >= getRect().getWidth()) ||
  337. (pos_map.mV[VY] >= getRect().getHeight()) )
  338. {
  339. S32 x = llround( pos_map.mV[VX] );
  340. S32 y = llround( pos_map.mV[VY] );
  341. LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10);
  342. } else
  343. {
  344. LLWorldMapView::drawTrackingDot(pos_map.mV[VX],pos_map.mV[VY],color,0.f);
  345. }
  346. }
  347. }
  348. F32 dist_to_cursor_squared = dist_vec_squared(LLVector2(pos_map.mV[VX], pos_map.mV[VY]),
  349. LLVector2(local_mouse_x,local_mouse_y));
  350. if(dist_to_cursor_squared < min_pick_dist_squared && dist_to_cursor_squared < closest_dist_squared)
  351. {
  352. closest_dist_squared = dist_to_cursor_squared;
  353. mClosestAgentToCursor = regionp->mMapAvatarIDs.get(i);
  354. }
  355. }
  356. }
  357. // Draw dot for autopilot target
  358. if (gAgent.getAutoPilot())
  359. {
  360. drawTracking( gAgent.getAutoPilotTargetGlobal(), map_track_color );
  361. }
  362. else
  363. {
  364. LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
  365. if ( LLTracker::TRACKING_AVATAR == tracking_status )
  366. {
  367. drawTracking( LLAvatarTracker::instance().getGlobalPos(), map_track_color );
  368. }
  369. else if ( LLTracker::TRACKING_LANDMARK == tracking_status
  370. || LLTracker::TRACKING_LOCATION == tracking_status )
  371. {
  372. drawTracking( LLTracker::getTrackedPositionGlobal(), map_track_color );
  373. }
  374. }
  375. // Draw dot for self avatar position
  376. pos_global = gAgent.getPositionGlobal();
  377. pos_map = globalPosToView(pos_global);
  378. S32 dot_width = llround(mDotRadius * 2.f);
  379. LLUIImagePtr you = LLWorldMapView::sAvatarYouLargeImage;
  380. if (you)
  381. {
  382. you->draw(llround(pos_map.mV[VX] - mDotRadius),
  383. llround(pos_map.mV[VY] - mDotRadius),
  384. dot_width,
  385. dot_width);
  386. F32 dist_to_cursor_squared = dist_vec_squared(LLVector2(pos_map.mV[VX], pos_map.mV[VY]),
  387. LLVector2(local_mouse_x,local_mouse_y));
  388. if(dist_to_cursor_squared < min_pick_dist_squared && dist_to_cursor_squared < closest_dist_squared)
  389. {
  390. mClosestAgentToCursor = gAgent.getID();
  391. }
  392. }
  393. // Draw frustum
  394. F32 meters_to_pixels = mScale/ LLWorld::getInstance()->getRegionWidthInMeters();
  395. F32 horiz_fov = LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect();
  396. F32 far_clip_meters = LLViewerCamera::getInstance()->getFar();
  397. F32 far_clip_pixels = far_clip_meters * meters_to_pixels;
  398. F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 );
  399. F32 half_width_pixels = half_width_meters * meters_to_pixels;
  400. F32 ctr_x = (F32)center_sw_left;
  401. F32 ctr_y = (F32)center_sw_bottom;
  402. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  403. if( rotate_map )
  404. {
  405. gGL.color4fv((map_frustum_color()).mV);
  406. gGL.begin( LLRender::TRIANGLES );
  407. gGL.vertex2f( ctr_x, ctr_y );
  408. gGL.vertex2f( ctr_x - half_width_pixels, ctr_y + far_clip_pixels );
  409. gGL.vertex2f( ctr_x + half_width_pixels, ctr_y + far_clip_pixels );
  410. gGL.end();
  411. }
  412. else
  413. {
  414. gGL.color4fv((map_frustum_rotating_color()).mV);
  415. // If we don't rotate the map, we have to rotate the frustum.
  416. gGL.pushMatrix();
  417. gGL.translatef( ctr_x, ctr_y, 0 );
  418. gGL.rotatef( atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
  419. gGL.begin( LLRender::TRIANGLES );
  420. gGL.vertex2f( 0, 0 );
  421. gGL.vertex2f( -half_width_pixels, far_clip_pixels );
  422. gGL.vertex2f( half_width_pixels, far_clip_pixels );
  423. gGL.end();
  424. gGL.popMatrix();
  425. }
  426. }
  427. gGL.popMatrix();
  428. gGL.popUIMatrix();
  429. LLUICtrl::draw();
  430. }
  431. void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent)
  432. {
  433. LLUICtrl::reshape(width, height, called_from_parent);
  434. createObjectImage();
  435. }
  436. LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos )
  437. {
  438. LLVector3d relative_pos_global = global_pos - gAgentCamera.getCameraPositionGlobal();
  439. LLVector3 pos_local;
  440. pos_local.setVec(relative_pos_global); // convert to floats from doubles
  441. pos_local.mV[VX] *= mPixelsPerMeter;
  442. pos_local.mV[VY] *= mPixelsPerMeter;
  443. // leave Z component in meters
  444. static LLUICachedControl<bool> rotate_map("MiniMapRotate", true);
  445. if( rotate_map )
  446. {
  447. F32 radians = atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] );
  448. LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f));
  449. pos_local.rotVec( rot );
  450. }
  451. pos_local.mV[VX] += getRect().getWidth() / 2 + mCurPan.mV[VX];
  452. pos_local.mV[VY] += getRect().getHeight() / 2 + mCurPan.mV[VY];
  453. return pos_local;
  454. }
  455. void LLNetMap::drawTracking(const LLVector3d& pos_global, const LLColor4& color,
  456. BOOL draw_arrow )
  457. {
  458. LLVector3 pos_local = globalPosToView( pos_global );
  459. if( (pos_local.mV[VX] < 0) ||
  460. (pos_local.mV[VY] < 0) ||
  461. (pos_local.mV[VX] >= getRect().getWidth()) ||
  462. (pos_local.mV[VY] >= getRect().getHeight()) )
  463. {
  464. if (draw_arrow)
  465. {
  466. S32 x = llround( pos_local.mV[VX] );
  467. S32 y = llround( pos_local.mV[VY] );
  468. LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10 );
  469. LLWorldMapView::drawTrackingArrow( getRect(), x, y, color );
  470. }
  471. }
  472. else
  473. {
  474. LLWorldMapView::drawTrackingDot(pos_local.mV[VX],
  475. pos_local.mV[VY],
  476. color,
  477. pos_local.mV[VZ]);
  478. }
  479. }
  480. LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y )
  481. {
  482. x -= llround(getRect().getWidth() / 2 + mCurPan.mV[VX]);
  483. y -= llround(getRect().getHeight() / 2 + mCurPan.mV[VY]);
  484. LLVector3 pos_local( (F32)x, (F32)y, 0 );
  485. F32 radians = - atan2( LLViewerCamera::getInstance()->getAtAxis().mV[VX], LLViewerCamera::getInstance()->getAtAxis().mV[VY] );
  486. static LLUICachedControl<bool> rotate_map("MiniMapRotate", true);
  487. if( rotate_map )
  488. {
  489. LLQuaternion rot(radians, LLVector3(0.f, 0.f, 1.f));
  490. pos_local.rotVec( rot );
  491. }
  492. pos_local *= ( LLWorld::getInstance()->getRegionWidthInMeters() / mScale );
  493. LLVector3d pos_global;
  494. pos_global.setVec( pos_local );
  495. pos_global += gAgentCamera.getCameraPositionGlobal();
  496. return pos_global;
  497. }
  498. BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
  499. {
  500. // note that clicks are reversed from what you'd think: i.e. > 0 means zoom out, < 0 means zoom in
  501. F32 new_scale = mScale * pow(MAP_SCALE_ZOOM_FACTOR, -clicks);
  502. F32 old_scale = mScale;
  503. setScale(new_scale);
  504. static LLUICachedControl<bool> auto_center("MiniMapAutoCenter", true);
  505. if (!auto_center)
  506. {
  507. // Adjust pan to center the zoom on the mouse pointer
  508. LLVector2 zoom_offset;
  509. zoom_offset.mV[VX] = x - getRect().getWidth() / 2;
  510. zoom_offset.mV[VY] = y - getRect().getHeight() / 2;
  511. mCurPan -= zoom_offset * mScale / old_scale - zoom_offset;
  512. }
  513. return TRUE;
  514. }
  515. BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
  516. {
  517. if (gDisconnected)
  518. {
  519. return FALSE;
  520. }
  521. // If the cursor is near an avatar on the minimap, a mini-inspector will be
  522. // shown for the avatar, instead of the normal map tooltip.
  523. if (handleToolTipAgent(mClosestAgentToCursor))
  524. {
  525. return TRUE;
  526. }
  527. LLRect sticky_rect;
  528. std::string region_name;
  529. LLViewerRegion* region = LLWorld::getInstance()->getRegionFromPosGlobal( viewPosToGlobal( x, y ) );
  530. if(region)
  531. {
  532. // set sticky_rect
  533. S32 SLOP = 4;
  534. localPointToScreen(x - SLOP, y - SLOP, &(sticky_rect.mLeft), &(sticky_rect.mBottom));
  535. sticky_rect.mRight = sticky_rect.mLeft + 2 * SLOP;
  536. sticky_rect.mTop = sticky_rect.mBottom + 2 * SLOP;
  537. region_name = region->getName();
  538. if (!region_name.empty())
  539. {
  540. region_name += "\n";
  541. }
  542. }
  543. LLStringUtil::format_map_t args;
  544. args["[REGION]"] = region_name;
  545. std::string msg = mToolTipMsg;
  546. LLStringUtil::format(msg, args);
  547. LLToolTipMgr::instance().show(LLToolTip::Params()
  548. .message(msg)
  549. .sticky_rect(sticky_rect));
  550. return TRUE;
  551. }
  552. BOOL LLNetMap::handleToolTipAgent(const LLUUID& avatar_id)
  553. {
  554. LLAvatarName av_name;
  555. if (avatar_id.isNull() || !LLAvatarNameCache::get(avatar_id, &av_name))
  556. {
  557. return FALSE;
  558. }
  559. // only show tooltip if same inspector not already open
  560. LLFloater* existing_inspector = LLFloaterReg::findInstance("inspect_avatar");
  561. if (!existing_inspector
  562. || !existing_inspector->getVisible()
  563. || existing_inspector->getKey()["avatar_id"].asUUID() != avatar_id)
  564. {
  565. LLInspector::Params p;
  566. p.fillFrom(LLUICtrlFactory::instance().getDefaultParams<LLInspector>());
  567. p.message(av_name.getCompleteName());
  568. p.image.name("Inspector_I");
  569. p.click_callback(boost::bind(showAvatarInspector, avatar_id));
  570. p.visible_time_near(6.f);
  571. p.visible_time_far(3.f);
  572. p.delay_time(0.35f);
  573. p.wrap(false);
  574. LLToolTipMgr::instance().show(p);
  575. }
  576. return TRUE;
  577. }
  578. // static
  579. void LLNetMap::showAvatarInspector(const LLUUID& avatar_id)
  580. {
  581. LLSD params;
  582. params["avatar_id"] = avatar_id;
  583. if (LLToolTipMgr::instance().toolTipVisible())
  584. {
  585. LLRect rect = LLToolTipMgr::instance().getToolTipRect();
  586. params["pos"]["x"] = rect.mLeft;
  587. params["pos"]["y"] = rect.mTop;
  588. }
  589. LLFloaterReg::showInstance("inspect_avatar", params);
  590. }
  591. void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius_meters )
  592. {
  593. LLVector3 local_pos;
  594. local_pos.setVec( pos - mObjectImageCenterGlobal );
  595. S32 diameter_pixels = llround(2 * radius_meters * mObjectMapTPM);
  596. renderPoint( local_pos, color, diameter_pixels );
  597. }
  598. void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color,
  599. S32 diameter, S32 relative_height)
  600. {
  601. if (diameter <= 0)
  602. {
  603. return;
  604. }
  605. const S32 image_width = (S32)mObjectImagep->getWidth();
  606. const S32 image_height = (S32)mObjectImagep->getHeight();
  607. S32 x_offset = llround(pos_local.mV[VX] * mObjectMapTPM + image_width / 2);
  608. S32 y_offset = llround(pos_local.mV[VY] * mObjectMapTPM + image_height / 2);
  609. if ((x_offset < 0) || (x_offset >= image_width))
  610. {
  611. return;
  612. }
  613. if ((y_offset < 0) || (y_offset >= image_height))
  614. {
  615. return;
  616. }
  617. U8 *datap = mObjectRawImagep->getData();
  618. S32 neg_radius = diameter / 2;
  619. S32 pos_radius = diameter - neg_radius;
  620. S32 x, y;
  621. if (relative_height > 0)
  622. {
  623. // ...point above agent
  624. S32 px, py;
  625. // vertical line
  626. px = x_offset;
  627. for (y = -neg_radius; y < pos_radius; y++)
  628. {
  629. py = y_offset + y;
  630. if ((py < 0) || (py >= image_height))
  631. {
  632. continue;
  633. }
  634. S32 offset = px + py * image_width;
  635. ((U32*)datap)[offset] = color.mAll;
  636. }
  637. // top line
  638. py = y_offset + pos_radius - 1;
  639. for (x = -neg_radius; x < pos_radius; x++)
  640. {
  641. px = x_offset + x;
  642. if ((px < 0) || (px >= image_width))
  643. {
  644. continue;
  645. }
  646. S32 offset = px + py * image_width;
  647. ((U32*)datap)[offset] = color.mAll;
  648. }
  649. }
  650. else
  651. {
  652. // ...point level with agent
  653. for (x = -neg_radius; x < pos_radius; x++)
  654. {
  655. S32 p_x = x_offset + x;
  656. if ((p_x < 0) || (p_x >= image_width))
  657. {
  658. continue;
  659. }
  660. for (y = -neg_radius; y < pos_radius; y++)
  661. {
  662. S32 p_y = y_offset + y;
  663. if ((p_y < 0) || (p_y >= image_height))
  664. {
  665. continue;
  666. }
  667. S32 offset = p_x + p_y * image_width;
  668. ((U32*)datap)[offset] = color.mAll;
  669. }
  670. }
  671. }
  672. }
  673. void LLNetMap::createObjectImage()
  674. {
  675. // Find the size of the side of a square that surrounds the circle that surrounds getRect().
  676. // ... which is, the diagonal of the rect.
  677. F32 width = (F32)getRect().getWidth();
  678. F32 height = (F32)getRect().getHeight();
  679. S32 square_size = llround( sqrt(width*width + height*height) );
  680. // Find the least power of two >= the minimum size.
  681. const S32 MIN_SIZE = 64;
  682. const S32 MAX_SIZE = 256;
  683. S32 img_size = MIN_SIZE;
  684. while( (img_size*2 < square_size ) && (img_size < MAX_SIZE) )
  685. {
  686. img_size <<= 1;
  687. }
  688. if( mObjectImagep.isNull() ||
  689. (mObjectImagep->getWidth() != img_size) ||
  690. (mObjectImagep->getHeight() != img_size) )
  691. {
  692. mObjectRawImagep = new LLImageRaw(img_size, img_size, 4);
  693. U8* data = mObjectRawImagep->getData();
  694. memset( data, 0, img_size * img_size * 4 );
  695. mObjectImagep = LLViewerTextureManager::getLocalTexture( mObjectRawImagep.get(), FALSE);
  696. }
  697. setScale(mScale);
  698. mUpdateNow = true;
  699. }
  700. BOOL LLNetMap::handleMouseDown( S32 x, S32 y, MASK mask )
  701. {
  702. if (!(mask & MASK_SHIFT)) return FALSE;
  703. // Start panning
  704. gFocusMgr.setMouseCapture(this);
  705. mStartPan = mCurPan;
  706. mMouseDown.mX = x;
  707. mMouseDown.mY = y;
  708. return TRUE;
  709. }
  710. BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask )
  711. {
  712. if(abs(mMouseDown.mX-x)<3 && abs(mMouseDown.mY-y)<3)
  713. handleClick(x,y,mask);
  714. if (hasMouseCapture())
  715. {
  716. if (mPanning)
  717. {
  718. // restore mouse cursor
  719. S32 local_x, local_y;
  720. local_x = mMouseDown.mX + llfloor(mCurPan.mV[VX] - mStartPan.mV[VX]);
  721. local_y = mMouseDown.mY + llfloor(mCurPan.mV[VY] - mStartPan.mV[VY]);
  722. LLRect clip_rect = getRect();
  723. clip_rect.stretch(-8);
  724. clip_rect.clipPointToRect(mMouseDown.mX, mMouseDown.mY, local_x, local_y);
  725. LLUI::setMousePositionLocal(this, local_x, local_y);
  726. // finish the pan
  727. mPanning = false;
  728. mMouseDown.set(0, 0);
  729. // auto centre
  730. mTargetPan.setZero();
  731. }
  732. gViewerWindow->showCursor();
  733. gFocusMgr.setMouseCapture(NULL);
  734. return TRUE;
  735. }
  736. return FALSE;
  737. }
  738. BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
  739. {
  740. if (mPopupMenu)
  741. {
  742. mPopupMenu->buildDrawLabels();
  743. mPopupMenu->updateParent(LLMenuGL::sMenuContainer);
  744. mPopupMenu->setItemEnabled("Stop Tracking", LLTracker::isTracking(0));
  745. LLMenuGL::showPopup(this, mPopupMenu, x, y);
  746. }
  747. return TRUE;
  748. }
  749. BOOL LLNetMap::handleClick(S32 x, S32 y, MASK mask)
  750. {
  751. // TODO: allow clicking an avatar on minimap to select avatar in the nearby avatar list
  752. // if(mClosestAgentToCursor.notNull())
  753. // mNearbyList->selectUser(mClosestAgentToCursor);
  754. // Needs a registered observer i guess to accomplish this without using
  755. // globals to tell the mNearbyList in llpeoplepanel to select the user
  756. return TRUE;
  757. }
  758. BOOL LLNetMap::handleDoubleClick(S32 x, S32 y, MASK mask)
  759. {
  760. LLVector3d pos_global = viewPosToGlobal(x, y);
  761. bool double_click_teleport = gSavedSettings.getBOOL("DoubleClickTeleport");
  762. bool double_click_show_world_map = gSavedSettings.getBOOL("DoubleClickShowWorldMap");
  763. if (double_click_teleport || double_click_show_world_map)
  764. {
  765. // If we're not tracking a beacon already, double-click will set one
  766. if (!LLTracker::isTracking(NULL))
  767. {
  768. LLFloaterWorldMap* world_map = LLFloaterWorldMap::getInstance();
  769. if (world_map)
  770. {
  771. world_map->trackLocation(pos_global);
  772. }
  773. }
  774. }
  775. if (double_click_teleport)
  776. {
  777. // If DoubleClickTeleport is on, double clicking the minimap will teleport there
  778. gAgent.teleportViaLocationLookAt(pos_global);
  779. }
  780. else if (double_click_show_world_map)
  781. {
  782. LLFloaterReg::showInstance("world_map");
  783. }
  784. return TRUE;
  785. }
  786. // static
  787. bool LLNetMap::outsideSlop( S32 x, S32 y, S32 start_x, S32 start_y, S32 slop )
  788. {
  789. S32 dx = x - start_x;
  790. S32 dy = y - start_y;
  791. return (dx <= -slop || slop <= dx || dy <= -slop || slop <= dy);
  792. }
  793. BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask )
  794. {
  795. if (hasMouseCapture())
  796. {
  797. if (mPanning || outsideSlop(x, y, mMouseDown.mX, mMouseDown.mY, MOUSE_DRAG_SLOP))
  798. {
  799. if (!mPanning)
  800. {
  801. // just started panning, so hide cursor
  802. mPanning = true;
  803. gViewerWindow->hideCursor();
  804. }
  805. LLVector2 delta(static_cast<F32>(gViewerWindow->getCurrentMouseDX()),
  806. static_cast<F32>(gViewerWindow->getCurrentMouseDY()));
  807. // Set pan to value at start of drag + offset
  808. mCurPan += delta;
  809. mTargetPan = mCurPan;
  810. gViewerWindow->moveCursorToCenter();
  811. }
  812. // Doesn't really matter, cursor should be hidden
  813. gViewerWindow->setCursor( UI_CURSOR_TOOLPAN );
  814. }
  815. else
  816. {
  817. if (mask & MASK_SHIFT)
  818. {
  819. // If shift is held, change the cursor to hint that the map can be dragged
  820. gViewerWindow->setCursor( UI_CURSOR_TOOLPAN );
  821. }
  822. else
  823. {
  824. gViewerWindow->setCursor( UI_CURSOR_CROSS );
  825. }
  826. }
  827. return TRUE;
  828. }
  829. void LLNetMap::handleZoom(const LLSD& userdata)
  830. {
  831. std::string level = userdata.asString();
  832. F32 scale = 0.0f;
  833. if (level == std::string("default"))
  834. {
  835. LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale");
  836. if(pvar)
  837. {
  838. pvar->resetToDefault();
  839. scale = gSavedSettings.getF32("MiniMapScale");
  840. }
  841. }
  842. else if (level == std::string("close"))
  843. scale = LLNetMap::MAP_SCALE_MAX;
  844. else if (level == std::string("medium"))
  845. scale = LLNetMap::MAP_SCALE_MID;
  846. else if (level == std::string("far"))
  847. scale = LLNetMap::MAP_SCALE_MIN;
  848. if (scale != 0.0f)
  849. {
  850. setScale(scale);
  851. }
  852. }
  853. void LLNetMap::handleStopTracking (const LLSD& userdata)
  854. {
  855. if (mPopupMenu)
  856. {
  857. mPopupMenu->setItemEnabled ("Stop Tracking", false);
  858. LLTracker::stopTracking ((void*)LLTracker::isTracking(NULL));
  859. }
  860. }