llpanelworldmap.cpp 52 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921
  1. /**
  2. * @file llpanelworldmap.cpp
  3. * @brief LLPanelWorldMap class implementation
  4. *
  5. * $LicenseInfo:firstyear=2001&license=viewergpl$
  6. *
  7. * Copyright (c) 2001-2009, Linden Research, Inc.
  8. * Copyright (c) 2009-2021, Henri Beauchamp.
  9. * Changes by Henri Beauchamp:
  10. * - Reorganized (was LLWorldMapView), cleaned up and optimized the code.
  11. * - Backported web map tiles support from v2/3 viewers while keeping the old
  12. * terrain-only map support.
  13. * - Adapted the code for OpenSim variable region size support.
  14. * - Allowed to keep both objects and terrain map tiles in memory (avoids
  15. * seeing the map tiles fully reloaded at each world map tab change).
  16. *
  17. * Second Life Viewer Source Code
  18. * The source code in this file ("Source Code") is provided by Linden Lab
  19. * to you under the terms of the GNU General Public License, version 2.0
  20. * ("GPL"), unless you have obtained a separate licensing agreement
  21. * ("Other License"), formally executed by you and Linden Lab. Terms of
  22. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  23. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  24. *
  25. * There are special exceptions to the terms and conditions of the GPL as
  26. * it is applied to this Source Code. View the full text of the exception
  27. * in the file doc/FLOSS-exception.txt in this software distribution, or
  28. * online at
  29. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  30. *
  31. * By copying, modifying or distributing this software, you acknowledge
  32. * that you have read and understood your obligations described above,
  33. * and agree to abide by those obligations.
  34. *
  35. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  36. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  37. * COMPLETENESS OR PERFORMANCE.
  38. * $/LicenseInfo$
  39. */
  40. #include "llviewerprecompiledheaders.h"
  41. #include "llpanelworldmap.h"
  42. #include "llgl.h"
  43. #include "llregionhandle.h"
  44. #include "llrender.h"
  45. #include "lltextbox.h"
  46. #include "lltrans.h"
  47. #include "llagent.h"
  48. #include "llappviewer.h" // Only for constants !
  49. #include "llavatartracker.h"
  50. #include "hbfloatersearch.h"
  51. #include "llfloaterworldmap.h"
  52. #include "lltexturefetch.h"
  53. #include "lltracker.h"
  54. #include "llviewercamera.h"
  55. #include "llviewercontrol.h"
  56. #include "llviewermenu.h"
  57. #include "llviewerparceloverlay.h"
  58. #include "llviewerregion.h"
  59. #include "llviewertexturelist.h"
  60. #include "llviewerwindow.h"
  61. #include "llworldmap.h"
  62. constexpr F32 GODLY_TELEPORT_HEIGHT = 200.f;
  63. constexpr F32 BIG_DOT_RADIUS = 5.f;
  64. F32 LLPanelWorldMap::sDefaultZ = -1.f;
  65. bool LLPanelWorldMap::sHandledLastClick = false;
  66. LLUIImagePtr LLPanelWorldMap::sAvatarSmallImage = NULL;
  67. LLUIImagePtr LLPanelWorldMap::sAvatarYouImage = NULL;
  68. LLUIImagePtr LLPanelWorldMap::sAvatarYouLargeImage = NULL;
  69. LLUIImagePtr LLPanelWorldMap::sAvatarLevelImage = NULL;
  70. LLUIImagePtr LLPanelWorldMap::sAvatarAboveImage = NULL;
  71. LLUIImagePtr LLPanelWorldMap::sAvatarBelowImage = NULL;
  72. LLUIImagePtr LLPanelWorldMap::sTelehubImage = NULL;
  73. LLUIImagePtr LLPanelWorldMap::sInfohubImage = NULL;
  74. LLUIImagePtr LLPanelWorldMap::sHomeImage = NULL;
  75. LLUIImagePtr LLPanelWorldMap::sEventImage = NULL;
  76. LLUIImagePtr LLPanelWorldMap::sEventMatureImage = NULL;
  77. LLUIImagePtr LLPanelWorldMap::sEventAdultImage = NULL;
  78. LLUIImagePtr LLPanelWorldMap::sTrackCircleImage = NULL;
  79. LLUIImagePtr LLPanelWorldMap::sTrackArrowImage = NULL;
  80. LLUIImagePtr LLPanelWorldMap::sClassifiedsImage = NULL;
  81. LLUIImagePtr LLPanelWorldMap::sForSaleImage = NULL;
  82. LLUIImagePtr LLPanelWorldMap::sForSaleAdultImage = NULL;
  83. F32 LLPanelWorldMap::sThreshold = 96.f;
  84. F32 LLPanelWorldMap::sPanX = 0.f;
  85. F32 LLPanelWorldMap::sPanY = 0.f;
  86. F32 LLPanelWorldMap::sTargetPanX = 0.f;
  87. F32 LLPanelWorldMap::sTargetPanY = 0.f;
  88. S32 LLPanelWorldMap::sTrackingArrowX = 0;
  89. S32 LLPanelWorldMap::sTrackingArrowY = 0;
  90. F32 LLPanelWorldMap::sPixelsPerMeter = 1.f;
  91. F32 LLPanelWorldMap::sMapScale = 128.f;
  92. F32 CONE_SIZE = 0.6f;
  93. // Width in pixels, where we start drawing "null" sims
  94. #define SIM_NULL_MAP_SCALE 1.f
  95. // Width in pixels, where we start drawing agents
  96. #define SIM_MAP_AGENT_SCALE 2.f
  97. // Width in pixels, where we start drawing sim tiles
  98. #define SIM_MAP_SCALE 1.f
  99. // Updates for agent locations.
  100. #define AGENTS_UPDATE_TIME 60.0 // in seconds
  101. #define AGENTS_FAST_UPDATE_TIME 5.0 // in seconds
  102. // Helper function
  103. LL_INLINE bool is_agent_in_region(LLViewerRegion* region, LLSimInfo* info)
  104. {
  105. return region && info && info->mName == region->getName();
  106. }
  107. ///////////////////////////////////////////////////////////////////////////////
  108. void LLPanelWorldMap::initClass()
  109. {
  110. sAvatarSmallImage = LLUI::getUIImage("map_avatar_8.tga");
  111. sAvatarYouImage = LLUI::getUIImage("map_avatar_16.tga");
  112. sAvatarYouLargeImage = LLUI::getUIImage("map_avatar_you_32.tga");
  113. sAvatarLevelImage = LLUI::getUIImage("map_avatar_32.tga");
  114. sAvatarAboveImage = LLUI::getUIImage("map_avatar_above_32.tga");
  115. sAvatarBelowImage = LLUI::getUIImage("map_avatar_below_32.tga");
  116. sHomeImage = LLUI::getUIImage("map_home.tga");
  117. sTelehubImage = LLUI::getUIImage("map_telehub.tga");
  118. sInfohubImage = LLUI::getUIImage("map_infohub.tga");
  119. sEventImage = LLUI::getUIImage("map_event.tga");
  120. sEventMatureImage = LLUI::getUIImage("map_event_mature.tga");
  121. // To Do: update the image resource for adult events.
  122. sEventAdultImage = LLUI::getUIImage("map_event_adult.tga");
  123. sTrackCircleImage = LLUI::getUIImage("map_track_16.tga");
  124. sTrackArrowImage = LLUI::getUIImage("direction_arrow.tga");
  125. sClassifiedsImage = LLUI::getUIImage("icon_top_pick.tga");
  126. sForSaleImage = LLUI::getUIImage("icon_for_sale.tga");
  127. // To Do: update the image resource for adult lands on sale.
  128. sForSaleAdultImage = LLUI::getUIImage("icon_for_sale_adult.tga");
  129. }
  130. //static
  131. void LLPanelWorldMap::cleanupClass()
  132. {
  133. sAvatarSmallImage = sAvatarYouImage = sAvatarYouLargeImage = NULL;
  134. sAvatarLevelImage = sAvatarAboveImage = sAvatarBelowImage = NULL;
  135. sTelehubImage = sInfohubImage = sHomeImage = NULL;
  136. sEventImage = sEventMatureImage = sEventAdultImage = NULL;
  137. sTrackCircleImage = sTrackArrowImage = NULL;
  138. sClassifiedsImage = sForSaleImage = sForSaleAdultImage = NULL;
  139. }
  140. LLPanelWorldMap::LLPanelWorldMap(const std::string& name, const LLRect& rect,
  141. U32 layer)
  142. : LLPanel(name, rect, BORDER_NO),
  143. mLayer(layer),
  144. mBackgroundColor(LLColor4(4.f / 255.f, 4.f / 255.f, 75.f / 255.f, 1.f)),
  145. mItemPicked(false),
  146. mPanning(false),
  147. mMouseDownPanX(0),
  148. mMouseDownPanY(0),
  149. mMouseDownX(0),
  150. mMouseDownY(0),
  151. mSelectIDStart(0)
  152. {
  153. sDefaultZ = -1.f; // Reset default altitude
  154. sPixelsPerMeter = sMapScale / REGION_WIDTH_METERS;
  155. clearLastClick();
  156. constexpr S32 DIR_WIDTH = 10;
  157. constexpr S32 DIR_HEIGHT = 10;
  158. LLRect major_dir_rect(0, DIR_HEIGHT, DIR_WIDTH, 0);
  159. mTextBoxNorth = new LLTextBox("N", major_dir_rect);
  160. addChild(mTextBoxNorth);
  161. LLColor4 minor_color(1.f, 1.f, 1.f, .7f);
  162. mTextBoxEast = new LLTextBox("E", major_dir_rect);
  163. mTextBoxEast->setColor(minor_color);
  164. addChild(mTextBoxEast);
  165. major_dir_rect.mRight += 1 ;
  166. mTextBoxWest = new LLTextBox("W", major_dir_rect);
  167. mTextBoxWest->setColor(minor_color);
  168. addChild(mTextBoxWest);
  169. major_dir_rect.mRight -= 1 ;
  170. mTextBoxSouth = new LLTextBox("S", major_dir_rect);
  171. mTextBoxSouth->setColor(minor_color);
  172. addChild(mTextBoxSouth);
  173. LLRect minor_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH * 2, 0);
  174. mTextBoxSouthEast = new LLTextBox("SE", minor_dir_rect);
  175. mTextBoxSouthEast->setColor(minor_color);
  176. addChild(mTextBoxSouthEast);
  177. mTextBoxNorthEast = new LLTextBox("NE", minor_dir_rect);
  178. mTextBoxNorthEast->setColor(minor_color);
  179. addChild(mTextBoxNorthEast);
  180. mTextBoxSouthWest = new LLTextBox("SW", minor_dir_rect);
  181. mTextBoxSouthWest->setColor(minor_color);
  182. addChild(mTextBoxSouthWest);
  183. mTextBoxNorthWest = new LLTextBox("NW", minor_dir_rect);
  184. mTextBoxNorthWest->setColor(minor_color);
  185. addChild(mTextBoxNorthWest);
  186. }
  187. //static
  188. void LLPanelWorldMap::setScale(F32 scale)
  189. {
  190. if (scale != sMapScale)
  191. {
  192. F32 old_scale = sMapScale;
  193. sMapScale = llmax(scale, 0.1f);
  194. F32 ratio = sMapScale / old_scale;
  195. sPanX *= ratio;
  196. sPanY *= ratio;
  197. sTargetPanX = sPanX;
  198. sTargetPanY = sPanY;
  199. sPixelsPerMeter = sMapScale / REGION_WIDTH_METERS;
  200. }
  201. }
  202. //static
  203. void LLPanelWorldMap::setPan(S32 x, S32 y, bool snap)
  204. {
  205. sTargetPanX = (F32)x;
  206. sTargetPanY = (F32)y;
  207. if (snap)
  208. {
  209. sPanX = sTargetPanX;
  210. sPanY = sTargetPanY;
  211. }
  212. }
  213. void LLPanelWorldMap::draw()
  214. {
  215. F64 current_time = LLTimer::getElapsedSeconds();
  216. mVisibleRegions.clear();
  217. // Animate pan if necessary
  218. F32 critical_damp = LLCriticalDamp::getInterpolant(0.1f);
  219. sPanX = lerp(sPanX, sTargetPanX, critical_damp);
  220. sPanY = lerp(sPanY, sTargetPanY, critical_damp);
  221. const S32 width = getRect().getWidth();
  222. const S32 height = getRect().getHeight();
  223. const F32 half_width = F32(width) * 0.5f;
  224. const F32 half_height = F32(height) * 0.5f;
  225. LLVector3d camera_global = gAgent.getCameraPositionGlobal();
  226. LLLocalClipRect clip(getLocalRect());
  227. LLTexUnit* unit0 = gGL.getTexUnit(0);
  228. unit0->unbind(LLTexUnit::TT_TEXTURE);
  229. gGL.matrixMode(LLRender::MM_MODELVIEW);
  230. if (gUsePBRShaders)
  231. {
  232. // Draw background rectangle
  233. #if 0 // Already done above... Why again ? HB
  234. unit0->unbind(LLTexUnit::TT_TEXTURE);
  235. #endif
  236. gGL.color4fv(mBackgroundColor.mV);
  237. gl_rect_2d(0, height, width, 0);
  238. }
  239. else
  240. {
  241. // Clear the background alpha to 0
  242. gGL.setColorMask(false, true);
  243. gGL.flush();
  244. gGL.setSceneBlendType(LLRender::BT_REPLACE);
  245. gGL.color4f(0.f, 0.f, 0.f, 0.f);
  246. gl_rect_2d(0, height, width, 0);
  247. gGL.setColorMask(true, true);
  248. gGL.flush();
  249. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  250. }
  251. F32 layer_alpha = 1.f;
  252. F32 ui_scale_x = LLUI::sGLScaleFactor.mV[VX];
  253. F32 ui_scale_y = LLUI::sGLScaleFactor.mV[VY];
  254. // Draw one image per layer
  255. for (U32 layer_idx = 0, count = gWorldMap.mMapLayers[mLayer].size();
  256. layer_idx < count; ++layer_idx)
  257. {
  258. if (!gWorldMap.mMapLayers[mLayer][layer_idx].mLayerDefined)
  259. {
  260. continue;
  261. }
  262. LLWorldMapLayer* layerp = &gWorldMap.mMapLayers[mLayer][layer_idx];
  263. LLViewerTexture* curr_texp = layerp->mLayerImage;
  264. if (!curr_texp || curr_texp->isMissingAsset())
  265. {
  266. continue; // Better to draw nothing than the missing asset image
  267. }
  268. LLVector3d origin_global((F64)layerp->mLayerExtents.mLeft *
  269. REGION_WIDTH_METERS,
  270. (F64)layerp->mLayerExtents.mBottom *
  271. REGION_WIDTH_METERS,
  272. 0.f);
  273. // Find x and y position relative to the center of the camera.
  274. LLVector3d rel_region_pos = origin_global - camera_global;
  275. F32 relative_x = rel_region_pos.mdV[0] / REGION_WIDTH_METERS *
  276. sMapScale;
  277. F32 relative_y = rel_region_pos.mdV[1] / REGION_WIDTH_METERS *
  278. sMapScale;
  279. F32 pix_width = sMapScale * (layerp->mLayerExtents.getWidth() + 1);
  280. F32 pix_height = sMapScale * (layerp->mLayerExtents.getHeight() + 1);
  281. // When the view is not panned, 0,0 = center of rectangle
  282. F32 bottom = sPanY + half_height + relative_y;
  283. F32 left = sPanX + half_width + relative_x;
  284. F32 top = bottom + pix_height;
  285. F32 right = left + pix_width;
  286. F32 pixel_area = pix_width * pix_height;
  287. // Discard small layers and layers that are outside the rectangle
  288. if (top < 0.f || bottom > height || right < 0.f || left > width ||
  289. pixel_area < 16)
  290. {
  291. curr_texp->setBoostLevel(0);
  292. continue;
  293. }
  294. curr_texp->setBoostLevel(LLGLTexture::BOOST_MAP);
  295. curr_texp->setKnownDrawSize(ll_roundp(pix_width * ui_scale_x),
  296. ll_roundp(pix_height * ui_scale_y));
  297. if (!curr_texp->hasGLTexture())
  298. {
  299. continue; // Better to draw nothing than the default image
  300. }
  301. // Draw using the texture. Not clamping would cause artifacts at the
  302. // edge.
  303. unit0->bind(curr_texp);
  304. // Draw map image into RGB
  305. gGL.setColorMask(true, false);
  306. gGL.color4f(1.f, 1.f, 1.f, layer_alpha);
  307. gGL.begin(LLRender::TRIANGLES);
  308. gGL.texCoord2f(0.f, 1.f);
  309. gGL.vertex3f(left, top, -1.f);
  310. gGL.texCoord2f(0.f, 0.f);
  311. gGL.vertex3f(left, bottom, -1.f);
  312. gGL.texCoord2f(1.f, 0.f);
  313. gGL.vertex3f(right, bottom, -1.f);
  314. gGL.texCoord2f(0.f, 1.f);
  315. gGL.vertex3f(left, top, -1.f);
  316. gGL.texCoord2f(1.f, 0.f);
  317. gGL.vertex3f(right, bottom, -1.f);
  318. gGL.texCoord2f(1.f, 1.f);
  319. gGL.vertex3f(right, top, -1.f);
  320. gGL.end();
  321. // Draw an alpha of 1 where the sims are visible
  322. gGL.setColorMask(false, true);
  323. gGL.color4f(1.f, 1.f, 1.f, 1.f);
  324. gGL.begin(LLRender::TRIANGLES);
  325. gGL.texCoord2f(0.f, 1.f);
  326. gGL.vertex2f(left, top);
  327. gGL.texCoord2f(0.f, 0.f);
  328. gGL.vertex2f(left, bottom);
  329. gGL.texCoord2f(1.f, 0.f);
  330. gGL.vertex2f(right, bottom);
  331. gGL.texCoord2f(0.f, 1.f);
  332. gGL.vertex2f(left, top);
  333. gGL.texCoord2f(1.f, 0.f);
  334. gGL.vertex2f(right, bottom);
  335. gGL.texCoord2f(1.f, 1.f);
  336. gGL.vertex2f(right, top);
  337. gGL.end();
  338. }
  339. gGL.flush();
  340. gGL.setColorMask(true, true);
  341. // Draw one image per region, centered on the camera position.
  342. constexpr U32 MAX_SIMULTANEOUS_TEX = 100;
  343. constexpr U32 MAX_REQUEST_PER_TICK = 5;
  344. constexpr U32 MIN_REQUEST_PER_TICK = 1;
  345. U32 textures_requested_this_tick = 0;
  346. bool use_web_map_tiles = LLWorldMap::useWebMapTiles();
  347. static LLCachedControl<bool> map_show_land_for_sale(gSavedSettings,
  348. "MapShowLandForSale");
  349. static LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
  350. critical_damp = LLCriticalDamp::getInterpolant(0.15f);
  351. for (LLWorldMap::sim_info_map_t::iterator
  352. it = gWorldMap.mSimInfoMap.begin(),
  353. end = gWorldMap.mSimInfoMap.end();
  354. it != end; ++it)
  355. {
  356. U64 handle = it->first;
  357. LLSimInfo* info = it->second;
  358. LLViewerTexture* simtexp = info->mCurrentImage[mLayer];
  359. LLViewerTexture* overlaytexp = info->mOverlayImage;
  360. if (sMapScale < SIM_MAP_SCALE)
  361. {
  362. if (simtexp)
  363. {
  364. simtexp->setBoostLevel(0);
  365. }
  366. if (overlaytexp)
  367. {
  368. overlaytexp->setBoostLevel(0);
  369. }
  370. continue;
  371. }
  372. LLVector3d origin_global = from_region_handle(handle);
  373. // Find x and y position relative to camera's center.
  374. LLVector3d rel_region_pos = origin_global - camera_global;
  375. F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) *
  376. sMapScale;
  377. F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) *
  378. sMapScale;
  379. // When the view is not panned, 0,0 = center of rectangle
  380. F32 bottom = sPanY + half_height + relative_y;
  381. F32 left = sPanX + half_width + relative_x;
  382. // Variable region size support: sMapScale is further scaled.
  383. F32 top = bottom + sMapScale * (info->mSizeY / REGION_WIDTH_METERS);
  384. F32 right = left + sMapScale * (info->mSizeX / REGION_WIDTH_METERS);
  385. // Switch to world map texture (if available for this region) if either:
  386. // 1. Tiles are zoomed out small enough, or
  387. // 2. Sim's texture has not been loaded yet
  388. F32 map_scale_cutoff = SIM_MAP_SCALE;
  389. #if 0 // REGION_FLAGS_NULL_LAYER is deprecated in SL and reused by
  390. // REGION_FLAGS_ALLOW_ENVIRONMENT_OVERRIDE...
  391. if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) > 0)
  392. {
  393. map_scale_cutoff = SIM_NULL_MAP_SCALE;
  394. }
  395. #endif
  396. info->mShowAgentLocations = (sMapScale >= SIM_MAP_AGENT_SCALE);
  397. bool sim_visible = (sMapScale >= map_scale_cutoff &&
  398. simtexp && simtexp->hasGLTexture());
  399. if (sim_visible)
  400. {
  401. // Fade in
  402. if (info->mAlpha < 0.f)
  403. {
  404. info->mAlpha = 1.f; // Do not fade initially
  405. }
  406. else
  407. {
  408. info->mAlpha = lerp(info->mAlpha, 1.f, critical_damp);
  409. }
  410. }
  411. // Fade out
  412. else if (info->mAlpha < 0.f)
  413. {
  414. info->mAlpha = 0.f; // Do not fade initially
  415. }
  416. else
  417. {
  418. info->mAlpha = lerp(info->mAlpha, 0.f, critical_damp);
  419. }
  420. // Discard regions that are outside the rectangle and discard small
  421. // regions
  422. if (top < 0.f || bottom > height || right < 0.f || left > width)
  423. {
  424. if (simtexp)
  425. {
  426. simtexp->setBoostLevel(0);
  427. }
  428. if (overlaytexp)
  429. {
  430. overlaytexp->setBoostLevel(0);
  431. }
  432. continue;
  433. }
  434. if (!simtexp &&
  435. (textures_requested_this_tick < MIN_REQUEST_PER_TICK ||
  436. (textures_requested_this_tick < MAX_REQUEST_PER_TICK &&
  437. gTextureFetchp->getApproxNumRequests() < MAX_SIMULTANEOUS_TEX)))
  438. {
  439. ++textures_requested_this_tick;
  440. if (use_web_map_tiles)
  441. {
  442. LLVector3d region_pos = info->getGlobalOrigin();
  443. info->mCurrentImage[mLayer] =
  444. LLWorldMap::loadObjectsTile((U32)(region_pos.mdV[VX] /
  445. REGION_WIDTH_UNITS),
  446. (U32)(region_pos.mdV[VY] /
  447. REGION_WIDTH_UNITS));
  448. }
  449. else
  450. {
  451. info->mCurrentImage[mLayer] =
  452. LLViewerTextureManager::getFetchedTexture(info->mMapImageID[mLayer],
  453. FTT_MAP_TILE);
  454. }
  455. simtexp = info->mCurrentImage[mLayer];
  456. }
  457. if (!overlaytexp && info->mMapImageID[2].notNull() &&
  458. (textures_requested_this_tick < MIN_REQUEST_PER_TICK ||
  459. (textures_requested_this_tick < MAX_REQUEST_PER_TICK &&
  460. gTextureFetchp->getApproxNumRequests() < MAX_SIMULTANEOUS_TEX)))
  461. {
  462. ++textures_requested_this_tick;
  463. info->mOverlayImage =
  464. LLViewerTextureManager::getFetchedTexture(info->mMapImageID[2],
  465. FTT_MAP_TILE);
  466. overlaytexp = info->mOverlayImage;
  467. }
  468. mVisibleRegions.push_back(handle);
  469. // See if the agents need updating
  470. F64 delta = current_time - info->mAgentsUpdateTime;
  471. if (delta > AGENTS_UPDATE_TIME ||
  472. // In case of TP failure, increase the update rate
  473. (delta > AGENTS_FAST_UPDATE_TIME &&
  474. handle == gAgent.getTeleportedSimHandle()))
  475. {
  476. info->mAgentsUpdateTime = current_time;
  477. if (info->mAccess == SIM_ACCESS_DOWN)
  478. {
  479. gWorldMap.sendHandleRegionRequest(handle);
  480. }
  481. else
  482. {
  483. gWorldMap.sendItemRequest(MAP_ITEM_AGENT_LOCATIONS,
  484. handle);
  485. }
  486. }
  487. // Bias the priority escalation for images nearer
  488. // Variable region size support: draw_size = ll_roundp(sMapScale) is
  489. // replaced with scaled x_draw_size and y_draw_size
  490. S32 x_draw_size = ll_roundp(sMapScale * info->mSizeX /
  491. REGION_WIDTH_METERS);
  492. S32 y_draw_size = ll_roundp(sMapScale * info->mSizeY /
  493. REGION_WIDTH_METERS);
  494. if (simtexp)
  495. {
  496. simtexp->setBoostLevel(LLGLTexture::BOOST_MAP);
  497. simtexp->setKnownDrawSize(ll_roundp(x_draw_size * ui_scale_x),
  498. ll_roundp(y_draw_size * ui_scale_y));
  499. }
  500. if (overlaytexp)
  501. {
  502. overlaytexp->setBoostLevel(LLGLTexture::BOOST_MAP);
  503. overlaytexp->setKnownDrawSize(ll_roundp(x_draw_size * ui_scale_x),
  504. ll_roundp(y_draw_size * ui_scale_y));
  505. }
  506. if (sim_visible && info->mAlpha > 0.001f)
  507. {
  508. // Draw using the texture. Not clamping would cause artifacts at
  509. // the edges.
  510. LLGLSUIDefault gls_ui;
  511. if (!gUsePBRShaders)
  512. {
  513. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  514. }
  515. F32 alpha = info->mAlpha;
  516. if (simtexp && simtexp->hasGLTexture())
  517. {
  518. unit0->bind(simtexp);
  519. simtexp->setAddressMode(LLTexUnit::TAM_CLAMP);
  520. gGL.color4f(1.f, 1.f, 1.f, alpha);
  521. gGL.begin(LLRender::TRIANGLES);
  522. gGL.texCoord2f(0.f, 1.f);
  523. gGL.vertex3f(left, top, 0.f);
  524. gGL.texCoord2f(0.f, 0.f);
  525. gGL.vertex3f(left, bottom, 0.f);
  526. gGL.texCoord2f(1.f, 0.f);
  527. gGL.vertex3f(right, bottom, 0.f);
  528. gGL.texCoord2f(0.f, 1.f);
  529. gGL.vertex3f(left, top, 0.f);
  530. gGL.texCoord2f(1.f, 0.f);
  531. gGL.vertex3f(right, bottom, 0.f);
  532. gGL.texCoord2f(1.f, 1.f);
  533. gGL.vertex3f(right, top, 0.f);
  534. gGL.end();
  535. }
  536. if (map_show_land_for_sale && overlaytexp &&
  537. overlaytexp->hasGLTexture())
  538. {
  539. unit0->bind(overlaytexp);
  540. overlaytexp->setAddressMode(LLTexUnit::TAM_CLAMP);
  541. gGL.color4f(1.f, 1.f, 1.f, alpha);
  542. gGL.begin(LLRender::TRIANGLES);
  543. gGL.texCoord2f(0.f, 1.f);
  544. gGL.vertex3f(left, top, -0.5f);
  545. gGL.texCoord2f(0.f, 0.f);
  546. gGL.vertex3f(left, bottom, -0.5f);
  547. gGL.texCoord2f(1.f, 0.f);
  548. gGL.vertex3f(right, bottom, -0.5f);
  549. gGL.texCoord2f(0.f, 1.f);
  550. gGL.vertex3f(left, top, -0.5f);
  551. gGL.texCoord2f(1.f, 0.f);
  552. gGL.vertex3f(right, bottom, -0.5f);
  553. gGL.texCoord2f(1.f, 1.f);
  554. gGL.vertex3f(right, top, -0.5f);
  555. gGL.end();
  556. }
  557. }
  558. if (info->mAccess == SIM_ACCESS_DOWN)
  559. {
  560. // Draw a transparent red square over down sims
  561. if (!gUsePBRShaders)
  562. {
  563. gGL.blendFunc(LLRender::BF_DEST_ALPHA,
  564. LLRender::BF_SOURCE_ALPHA);
  565. }
  566. gGL.color4f(0.2f, 0.f, 0.f, 0.4f);
  567. unit0->unbind(LLTexUnit::TT_TEXTURE);
  568. gGL.begin(LLRender::TRIANGLES);
  569. gGL.vertex2f(left, top);
  570. gGL.vertex2f(left, bottom);
  571. gGL.vertex2f(right, bottom);
  572. gGL.vertex2f(left, top);
  573. gGL.vertex2f(right, bottom);
  574. gGL.vertex2f(right, top);
  575. gGL.end();
  576. if (!gUsePBRShaders)
  577. {
  578. gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
  579. LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
  580. }
  581. }
  582. // Draw the region name in the lower left corner
  583. std::string mesg;
  584. if (sMapScale >= sThreshold)
  585. {
  586. static const std::string offline =
  587. LLTrans::getString("worldmap_offline");
  588. std::string access;
  589. switch (info->mAccess)
  590. {
  591. case SIM_ACCESS_DOWN:
  592. access = offline;
  593. break;
  594. case SIM_ACCESS_PG:
  595. access = "PG";
  596. break;
  597. case SIM_ACCESS_MATURE:
  598. access = "M";
  599. break;
  600. case SIM_ACCESS_ADULT:
  601. access = "A";
  602. break;
  603. default:
  604. break;
  605. }
  606. if (access.empty())
  607. {
  608. mesg = info->mName;
  609. }
  610. else
  611. {
  612. mesg = info->mName + " (" + access + ")";
  613. }
  614. }
  615. if (!mesg.empty())
  616. {
  617. fontp->renderUTF8(mesg, 0, llfloor(left + 3), llfloor(bottom + 2),
  618. LLColor4::white, LLFontGL::LEFT,
  619. LLFontGL::BASELINE, LLFontGL::DROP_SHADOW_SOFT);
  620. // If map texture is still loading, display "Loading" placeholder
  621. // text.
  622. if (simtexp && simtexp->getDiscardLevel() != 1 &&
  623. simtexp->getDiscardLevel() != 0)
  624. {
  625. static const LLWString loading =
  626. LLTrans::getWString("texture_loading");
  627. fontp->render(loading, 0, llfloor(left + 18),
  628. llfloor(top - 25), LLColor4::white,
  629. LLFontGL::LEFT, LLFontGL::BASELINE,
  630. LLFontGL::DROP_SHADOW_SOFT);
  631. }
  632. }
  633. }
  634. if (!gUsePBRShaders)
  635. {
  636. // Draw background rectangle
  637. LLGLSUIDefault gls_ui;
  638. unit0->unbind(LLTexUnit::TT_TEXTURE);
  639. gGL.blendFunc(LLRender::BF_ONE_MINUS_DEST_ALPHA,
  640. LLRender::BF_DEST_ALPHA);
  641. gGL.flush();
  642. gGL.color4fv(mBackgroundColor.mV);
  643. gl_rect_2d(0, height, width, 0);
  644. gGL.flush();
  645. gGL.setSceneBlendType(LLRender::BT_ALPHA);
  646. }
  647. // Draw one image per region, centered on the camera position. // Infohubs
  648. static LLCachedControl<bool> map_show_info_hubs(gSavedSettings,
  649. "MapShowInfohubs");
  650. if (map_show_info_hubs) // && sMapScale >= sThreshold)
  651. {
  652. drawGenericItems(gWorldMap.mInfohubs, sInfohubImage);
  653. }
  654. // Telehubs
  655. static LLCachedControl<bool> map_show_telehubs(gSavedSettings,
  656. "MapShowTelehubs");
  657. if (map_show_telehubs) // && sMapScale >= sThreshold)
  658. {
  659. drawGenericItems(gWorldMap.mTelehubs, sTelehubImage);
  660. }
  661. // Home Sweet Home
  662. LLVector3d home;
  663. if (gAgent.getHomePosGlobal(&home))
  664. {
  665. drawImage(home, sHomeImage);
  666. }
  667. // Land for sale
  668. if (map_show_land_for_sale)
  669. {
  670. drawGenericItems(gWorldMap.mLandForSale, sForSaleImage);
  671. // We are showing normal land and adult land in the same UI; you do not
  672. // get a choice about which ones you want. If you are currently asking
  673. // for adult content and land you will get the adult land.
  674. if (gAgent.canAccessAdult())
  675. {
  676. drawGenericItems(gWorldMap.mLandForSaleAdult,
  677. sForSaleAdultImage);
  678. }
  679. }
  680. // Events
  681. drawEvents();
  682. // Now draw your avatar after all that other stuff.
  683. LLVector3d pos_global = gAgent.getPositionGlobal();
  684. drawImage(pos_global, sAvatarYouImage);
  685. LLVector3 pos_map = globalPosToView(pos_global);
  686. if (!pointInView(ll_round(pos_map.mV[VX]), ll_round(pos_map.mV[VY])))
  687. {
  688. // Offset vertically by 1 line to avoid overlap with target tracking
  689. static S32 font_height = ll_round(fontp->getLineHeight());
  690. drawTracking(pos_global,
  691. lerp(LLColor4::yellow, LLColor4::orange, 0.4f),
  692. true, "You are here", "", font_height);
  693. }
  694. // Show your viewing angle
  695. drawFrustum();
  696. // Draw icons for the avatars in each region. Drawn after your avatar so
  697. // you can see nearby people.
  698. static LLCachedControl<bool> map_show_people(gSavedSettings,
  699. "MapShowPeople");
  700. if (map_show_people)
  701. {
  702. drawAgents();
  703. }
  704. // Always draw tracking information
  705. LLTracker::ETrackingStatus tracking_status = gTracker.getTrackingStatus();
  706. if (LLTracker::TRACKING_AVATAR == tracking_status)
  707. {
  708. drawTracking(gAvatarTracker.getGlobalPos(), LLUI::sTrackColor, true,
  709. gTracker.getLabel(), "");
  710. }
  711. else if (LLTracker::TRACKING_LANDMARK == tracking_status ||
  712. LLTracker::TRACKING_LOCATION == tracking_status)
  713. {
  714. // While fetching landmarks, will have 0,0,0 location for a while,
  715. // so do not draw. JC
  716. LLVector3d pos_global = gTracker.getTrackedPositionGlobal();
  717. if (!pos_global.isExactlyZero())
  718. {
  719. drawTracking(pos_global, LLUI::sTrackColor, true,
  720. gTracker.getLabel(), gTracker.getToolTip());
  721. }
  722. }
  723. else if (gWorldMap.mIsTrackingUnknownLocation)
  724. {
  725. if (gWorldMap.mInvalidLocation)
  726. {
  727. // We know this location to be invalid
  728. LLColor4 loading_color(0.f, 0.5f, 1.f, 1.f);
  729. drawTracking(gWorldMap.mUnknownLocation, loading_color, true,
  730. "Invalid Location", "");
  731. }
  732. else
  733. {
  734. F32 value = fmodf(current_time, 2);
  735. value = 0.5f + 0.5f * cosf(value * F_PI);
  736. LLColor4 loading_color(0.f, value * 0.5f, value, 1.f);
  737. drawTracking(gWorldMap.mUnknownLocation, loading_color, true,
  738. "Loading...", "");
  739. }
  740. }
  741. // Turn off the scissor
  742. LLGLDisable no_scissor(GL_SCISSOR_TEST);
  743. updateDirections();
  744. LLView::draw();
  745. updateVisibleBlocks();
  746. gGL.flush();
  747. }
  748. //virtual
  749. void LLPanelWorldMap::setVisible(bool visible)
  750. {
  751. LLPanel::setVisible(visible);
  752. if (!visible)
  753. {
  754. for (S32 map = 0; map < MAP_SIM_IMAGE_TYPES; ++map)
  755. {
  756. for (U32 i = 0, count = gWorldMap.mMapLayers[map].size();
  757. i < count; ++i)
  758. {
  759. LLWorldMapLayer& layer = gWorldMap.mMapLayers[map][i];
  760. if (layer.mLayerDefined)
  761. {
  762. layer.mLayerImage->setBoostLevel(0);
  763. }
  764. }
  765. }
  766. for (LLWorldMap::sim_info_map_t::iterator
  767. it = gWorldMap.mSimInfoMap.begin(),
  768. end = gWorldMap.mSimInfoMap.end();
  769. it != end; ++it)
  770. {
  771. LLSimInfo* info = it->second;
  772. if (info->mCurrentImage[mLayer].notNull())
  773. {
  774. info->mCurrentImage[mLayer]->setBoostLevel(0);
  775. }
  776. if (info->mOverlayImage.notNull())
  777. {
  778. info->mOverlayImage->setBoostLevel(0);
  779. }
  780. }
  781. }
  782. }
  783. void LLPanelWorldMap::drawGenericItems(const LLWorldMap::item_info_list_t& items,
  784. LLUIImagePtr image)
  785. {
  786. for (LLWorldMap::item_info_list_t::const_iterator it = items.begin(),
  787. end = items.end();
  788. it != end; ++it)
  789. {
  790. drawGenericItem(*it, image);
  791. }
  792. }
  793. void LLPanelWorldMap::drawGenericItem(const LLItemInfo& item,
  794. LLUIImagePtr image)
  795. {
  796. drawImage(item.mPosGlobal, image);
  797. }
  798. void LLPanelWorldMap::drawImage(const LLVector3d& global_pos,
  799. LLUIImagePtr image, const LLColor4& color)
  800. {
  801. LLVector3 pos_map = globalPosToView(global_pos);
  802. image->draw(ll_round(pos_map.mV[VX] - image->getWidth() * 0.5f),
  803. ll_round(pos_map.mV[VY] - image->getHeight() * 0.5f), color);
  804. }
  805. void LLPanelWorldMap::drawImageStack(const LLVector3d& global_pos,
  806. LLUIImagePtr image, U32 count, F32 offset,
  807. const LLColor4& color)
  808. {
  809. LLVector3 pos_map = globalPosToView(global_pos);
  810. for (U32 i = 0; i < count; ++i)
  811. {
  812. image->draw(ll_round(pos_map.mV[VX] - image->getWidth() * 0.5f),
  813. ll_round(pos_map.mV[VY] - image->getHeight() * 0.5f +
  814. i * offset),
  815. color);
  816. }
  817. }
  818. void LLPanelWorldMap::drawAgents()
  819. {
  820. F32 agents_scale = sMapScale * (0.9f / 256.f);
  821. static LLCachedControl<LLColor4U> map_avatar(gColors, "MapAvatar");
  822. LLColor4 avatar_color = LLColor4(map_avatar);
  823. LLWorldMap::agent_list_map_t::iterator end_agent_locations =
  824. gWorldMap.mAgentLocationsMap.end();
  825. for (handle_list_t::iterator iter = mVisibleRegions.begin(),
  826. end = mVisibleRegions.end();
  827. iter != end; ++iter)
  828. {
  829. U64 handle = *iter;
  830. LLSimInfo* siminfo = gWorldMap.simInfoFromHandle(handle);
  831. if (!siminfo || siminfo->mAccess == SIM_ACCESS_DOWN)
  832. {
  833. continue;
  834. }
  835. LLWorldMap::agent_list_map_t::iterator counts_iter =
  836. gWorldMap.mAgentLocationsMap.find(handle);
  837. if (siminfo->mShowAgentLocations && counts_iter != end_agent_locations)
  838. {
  839. // Show individual agents (or little stacks where real agents are)
  840. LLWorldMap::item_info_list_t& agentcounts = counts_iter->second;
  841. S32 sim_agent_count = 0;
  842. for (LLWorldMap::item_info_list_t::iterator
  843. iter = agentcounts.begin(), end2 = agentcounts.end();
  844. iter != end2; ++iter)
  845. {
  846. const LLItemInfo& info = *iter;
  847. S32 agent_count = info.mExtra;
  848. sim_agent_count += agent_count;
  849. drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count,
  850. 3.f, avatar_color);
  851. }
  852. // Override number of agents for this sim
  853. siminfo->mAgentsCount = sim_agent_count;
  854. }
  855. else
  856. {
  857. S32 sim_agent_count = siminfo->mAgentsCount;
  858. if (sim_agent_count <= 0) continue;
  859. // Show agent 'stack' at center of sim
  860. LLVector3d region_center = from_region_handle(handle);
  861. region_center[VX] += REGION_WIDTH_METERS / 2;
  862. region_center[VY] += REGION_WIDTH_METERS / 2;
  863. // Reduce the stack size as you zoom out - always display at least
  864. // one agent where there is one or more
  865. S32 agent_count = (S32)(((sim_agent_count - 1) * agents_scale +
  866. (sim_agent_count - 1) * 0.1f) + 0.1f) + 1;
  867. drawImageStack(region_center, sAvatarSmallImage, agent_count,
  868. 3.f, avatar_color);
  869. }
  870. }
  871. }
  872. void LLPanelWorldMap::drawEvents()
  873. {
  874. static LLCachedControl<bool> map_show_pg_events(gSavedSettings,
  875. "MapShowPGEvents");
  876. static LLCachedControl<bool> map_show_mature_events(gSavedSettings,
  877. "MapShowMatureEvents");
  878. static LLCachedControl<bool> map_show_adult_events(gSavedSettings,
  879. "MapShowAdultEvents");
  880. bool show_pg = map_show_pg_events;
  881. bool show_mature = map_show_mature_events && gAgent.canAccessMature();
  882. bool show_adult = map_show_adult_events && gAgent.canAccessAdult();
  883. if (!show_pg && !show_mature && !show_adult)
  884. {
  885. return;
  886. }
  887. // First the non-selected events
  888. if (show_pg)
  889. {
  890. for (LLWorldMap::item_info_list_t::const_iterator
  891. it = gWorldMap.mPGEvents.begin(),
  892. end = gWorldMap.mPGEvents.end();
  893. it != end; ++it)
  894. {
  895. if (!it->mSelected)
  896. {
  897. drawGenericItem(*it, sEventImage);
  898. }
  899. }
  900. }
  901. if (show_mature)
  902. {
  903. for (LLWorldMap::item_info_list_t::const_iterator
  904. it = gWorldMap.mMatureEvents.begin(),
  905. end = gWorldMap.mMatureEvents.end();
  906. it != end; ++it)
  907. {
  908. if (!it->mSelected)
  909. {
  910. drawGenericItem(*it, sEventMatureImage);
  911. }
  912. }
  913. }
  914. if (show_adult)
  915. {
  916. for (LLWorldMap::item_info_list_t::const_iterator
  917. it = gWorldMap.mAdultEvents.begin(),
  918. end = gWorldMap.mAdultEvents.end();
  919. it != end; ++it)
  920. {
  921. if (!it->mSelected)
  922. {
  923. drawGenericItem(*it, sEventAdultImage);
  924. }
  925. }
  926. }
  927. // Then the selected events
  928. if (show_pg)
  929. {
  930. for (LLWorldMap::item_info_list_t::const_iterator
  931. it = gWorldMap.mPGEvents.begin(),
  932. end = gWorldMap.mPGEvents.end();
  933. it != end; ++it)
  934. {
  935. if (it->mSelected)
  936. {
  937. drawGenericItem(*it, sEventImage);
  938. }
  939. }
  940. }
  941. if (show_mature)
  942. {
  943. for (LLWorldMap::item_info_list_t::const_iterator
  944. it = gWorldMap.mMatureEvents.begin(),
  945. end = gWorldMap.mMatureEvents.end();
  946. it != end; ++it)
  947. {
  948. if (it->mSelected)
  949. {
  950. drawGenericItem(*it, sEventMatureImage);
  951. }
  952. }
  953. }
  954. if (show_adult)
  955. {
  956. for (LLWorldMap::item_info_list_t::const_iterator
  957. it = gWorldMap.mAdultEvents.begin(),
  958. end = gWorldMap.mAdultEvents.end();
  959. it != end; ++it)
  960. {
  961. if (it->mSelected)
  962. {
  963. drawGenericItem(*it, sEventAdultImage);
  964. }
  965. }
  966. }
  967. }
  968. void LLPanelWorldMap::drawFrustum()
  969. {
  970. // Draw frustum
  971. F32 meters_to_pixels = sMapScale / REGION_WIDTH_METERS;
  972. F32 horiz_fov = gViewerCamera.getView() * gViewerCamera.getAspect();
  973. F32 far_clip_meters = gViewerCamera.getFar();
  974. F32 far_clip_pixels = far_clip_meters * meters_to_pixels;
  975. F32 half_width_meters = far_clip_meters * tanf(horiz_fov * 0.5f);
  976. F32 half_width_pixels = half_width_meters * meters_to_pixels;
  977. // Compute the frustum coordinates. Take the UI scale into account.
  978. static LLCachedControl<F32> ui_scale(gSavedSettings, "UIScaleFactor");
  979. F32 ctr_x = (getRect().getWidth() * 0.5f + sPanX) * ui_scale;
  980. F32 ctr_y = (getRect().getHeight() * 0.5f + sPanY) * ui_scale;
  981. gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
  982. gGL.pushMatrix();
  983. gGL.translatef(ctr_x, ctr_y, 0.f);
  984. {
  985. LLVector3 at_axis = gViewerCamera.getAtAxis();
  986. LLVector3 left_axis = gViewerCamera.getLeftAxis();
  987. // Grab components along XY plane
  988. LLVector2 cam_lookat(at_axis.mV[VX], at_axis.mV[VY]);
  989. LLVector2 cam_left(left_axis.mV[VX], left_axis.mV[VY]);
  990. // But, when looking near straight up or down...
  991. if (is_approx_zero(cam_lookat.lengthSquared()))
  992. {
  993. // ...just fall back to looking down the x axis
  994. cam_lookat = LLVector2(1.f, 0.f); // x axis
  995. cam_left = LLVector2(0.f, 1.f); // y axis
  996. }
  997. // Normalize to unit length
  998. cam_lookat.normalize();
  999. cam_left.normalize();
  1000. // Draw triangle with more alpha in far pixels to make it fade out in
  1001. // distance.
  1002. gGL.begin(LLRender::TRIANGLES);
  1003. gGL.color4f(1.f, 1.f, 1.f, 0.25f);
  1004. gGL.vertex2f(0.f, 0.f);
  1005. gGL.color4f(1.f, 1.f, 1.f, 0.02f);
  1006. // use 2d camera vectors to render frustum triangle
  1007. LLVector2 vert = cam_lookat * far_clip_pixels +
  1008. cam_left * half_width_pixels;
  1009. gGL.vertex2f(vert.mV[VX], vert.mV[VY]);
  1010. vert = cam_lookat * far_clip_pixels - cam_left * half_width_pixels;
  1011. gGL.vertex2f(vert.mV[VX], vert.mV[VY]);
  1012. gGL.end();
  1013. }
  1014. gGL.popMatrix();
  1015. }
  1016. LLVector3 LLPanelWorldMap::globalPosToView(const LLVector3d& global_pos)
  1017. {
  1018. LLVector3d relative_pos_global = global_pos -
  1019. gAgent.getCameraPositionGlobal();
  1020. LLVector3 pos_local;
  1021. pos_local.set(relative_pos_global); // convert to floats from doubles
  1022. pos_local.mV[VX] *= sPixelsPerMeter;
  1023. pos_local.mV[VY] *= sPixelsPerMeter;
  1024. // leave Z component in meters
  1025. pos_local.mV[VX] += getRect().getWidth() / 2 + sPanX;
  1026. pos_local.mV[VY] += getRect().getHeight() / 2 + sPanY;
  1027. return pos_local;
  1028. }
  1029. void LLPanelWorldMap::drawTracking(const LLVector3d& pos_global,
  1030. const LLColor4& color, bool draw_arrow,
  1031. const std::string& label,
  1032. const std::string& tooltip, S32 vert_offset)
  1033. {
  1034. static LLFontGL* fontp = LLFontGL::getFontSansSerifSmall();
  1035. static F32 font_height = fontp->getLineHeight();
  1036. LLVector3 pos_local = globalPosToView(pos_global);
  1037. S32 x = ll_roundp(pos_local.mV[VX]);
  1038. S32 y = ll_roundp(pos_local.mV[VY]);
  1039. S32 text_x = x;
  1040. S32 text_y = (S32)(y - sTrackCircleImage->getHeight() / 2 - font_height);
  1041. if (x < 0 || y < 0 || x >= getRect().getWidth() ||
  1042. y >= getRect().getHeight())
  1043. {
  1044. if (draw_arrow)
  1045. {
  1046. drawTrackingCircle(getRect(), x, y, color, 3, 15);
  1047. drawTrackingArrow(getRect(), x, y, color);
  1048. text_x = sTrackingArrowX;
  1049. text_y = sTrackingArrowY;
  1050. }
  1051. }
  1052. else if (gTracker.getTrackingStatus() == LLTracker::TRACKING_LOCATION &&
  1053. gTracker.getTrackedLocationType() != LLTracker::LOCATION_NOTHING)
  1054. {
  1055. drawTrackingCircle(getRect(), x, y, color, 3, 15);
  1056. }
  1057. else
  1058. {
  1059. drawImage(pos_global, sTrackCircleImage, color);
  1060. }
  1061. if (label.empty())
  1062. {
  1063. return;
  1064. }
  1065. // Clamp text position to on-screen
  1066. constexpr S32 TEXT_PADDING = DEFAULT_TRACKING_ARROW_SIZE + 2;
  1067. S32 half_text_width = llfloor(fontp->getWidthF32(label) * 0.5f);
  1068. text_x = llclamp(text_x, half_text_width + TEXT_PADDING,
  1069. getRect().getWidth() - half_text_width - TEXT_PADDING);
  1070. text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset,
  1071. getRect().getHeight() - ll_roundp(font_height) -
  1072. TEXT_PADDING - vert_offset);
  1073. fontp->renderUTF8(label, 0, text_x, text_y, LLColor4::white,
  1074. LLFontGL::HCENTER, LLFontGL::BASELINE,
  1075. LLFontGL::DROP_SHADOW_SOFT);
  1076. if (tooltip.empty())
  1077. {
  1078. return;
  1079. }
  1080. fontp->renderUTF8(tooltip, 0, text_x, text_y - (S32)font_height,
  1081. LLColor4::white, LLFontGL::HCENTER,
  1082. LLFontGL::BASELINE, LLFontGL::DROP_SHADOW_SOFT);
  1083. }
  1084. // If you change this, then you need to change
  1085. // gTracker.getTrackedPositionGlobal() as well
  1086. LLVector3d LLPanelWorldMap::viewPosToGlobal(S32 x, S32 y)
  1087. {
  1088. x -= llfloor(getRect().getWidth() / 2 + sPanX);
  1089. y -= llfloor(getRect().getHeight() / 2 + sPanY);
  1090. LLVector3 pos_local((F32)x, (F32)y, 0.f);
  1091. pos_local *= (REGION_WIDTH_METERS / sMapScale);
  1092. LLVector3d pos_global;
  1093. pos_global.set(pos_local);
  1094. pos_global += gAgent.getCameraPositionGlobal();
  1095. if (sDefaultZ >= 0.f)
  1096. {
  1097. // Use the last Z position when available
  1098. pos_global.mdV[VZ] = sDefaultZ;
  1099. }
  1100. else if (gAgent.isGodlike())
  1101. {
  1102. // Godly height should always be 200.
  1103. pos_global.mdV[VZ] = GODLY_TELEPORT_HEIGHT;
  1104. }
  1105. else
  1106. {
  1107. // Want agent's height, not camera's
  1108. pos_global.mdV[VZ] = gAgent.getPositionAgent().mV[VZ];
  1109. }
  1110. return pos_global;
  1111. }
  1112. bool LLPanelWorldMap::handleToolTip(S32 x, S32 y, std::string& msg,
  1113. LLRect* sticky_rect_screen)
  1114. {
  1115. LLVector3d pos_global = viewPosToGlobal(x, y);
  1116. LLSimInfo* info = gWorldMap.simInfoFromPosGlobal(pos_global);
  1117. if (!info)
  1118. {
  1119. return true;
  1120. }
  1121. LLViewerRegion* region = gAgent.getRegion();
  1122. if (!region)
  1123. {
  1124. return true;
  1125. }
  1126. std::string message =
  1127. llformat("%s (%s)", info->mName.c_str(),
  1128. LLViewerRegion::accessToString(info->mAccess).c_str());
  1129. if (info->mAccess != SIM_ACCESS_DOWN)
  1130. {
  1131. S32 agent_count = info->mAgentsCount;
  1132. // We may not have an agent count when the map is really zoomed out, so
  1133. // do not display anything about the count. JC
  1134. if (agent_count >= 0)
  1135. {
  1136. if (region->getHandle() == info->mHandle)
  1137. {
  1138. ++agent_count; // Bump by 1 if we are here
  1139. }
  1140. if (agent_count > 0)
  1141. {
  1142. message += llformat("\n%d resident", agent_count);
  1143. if (agent_count > 1)
  1144. {
  1145. message += "s";
  1146. }
  1147. }
  1148. }
  1149. }
  1150. msg.assign(message);
  1151. // Optionally show region flags
  1152. if (gFloaterWorldMapp) // Paranoia
  1153. {
  1154. message.clear();
  1155. if (info->mRegionFlags & REGION_FLAGS_SANDBOX)
  1156. {
  1157. message = gFloaterWorldMapp->getString("sandbox");
  1158. }
  1159. if (info->mRegionFlags & REGION_FLAGS_ALLOW_DAMAGE)
  1160. {
  1161. if (!message.empty())
  1162. {
  1163. message += " - ";
  1164. }
  1165. message += gFloaterWorldMapp->getString("not_safe");
  1166. }
  1167. if (!message.empty())
  1168. {
  1169. msg += '\n';
  1170. msg += message;
  1171. }
  1172. }
  1173. constexpr S32 SLOP = 4;
  1174. localPointToScreen(x - SLOP, y - SLOP, &(sticky_rect_screen->mLeft),
  1175. &(sticky_rect_screen->mBottom));
  1176. sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
  1177. sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
  1178. return true;
  1179. }
  1180. // Pass relative Z of 0 to draw at same level.
  1181. //static
  1182. void LLPanelWorldMap::drawIconName(F32 x_pixels, F32 y_pixels,
  1183. const LLColor4& color,
  1184. const std::string& first_line,
  1185. const std::string& second_line)
  1186. {
  1187. static LLFontGL* fontp = LLFontGL::getFontSansSerif();
  1188. static F32 font_height = fontp->getLineHeight();
  1189. constexpr S32 VERT_PAD = 8;
  1190. S32 text_x = ll_roundp(x_pixels);
  1191. S32 text_y = ll_roundp(y_pixels - BIG_DOT_RADIUS - VERT_PAD);
  1192. // Render first line of text
  1193. fontp->renderUTF8(first_line, 0, text_x, text_y, color, LLFontGL::HCENTER,
  1194. LLFontGL::TOP, LLFontGL::DROP_SHADOW_SOFT);
  1195. text_y -= ll_roundp(font_height);
  1196. // Render second line of text
  1197. fontp->renderUTF8(second_line, 0, text_x, text_y, color, LLFontGL::HCENTER,
  1198. LLFontGL::TOP, LLFontGL::DROP_SHADOW_SOFT);
  1199. }
  1200. //static
  1201. void LLPanelWorldMap::drawTrackingCircle(const LLRect& rect, S32 x, S32 y,
  1202. const LLColor4& color,
  1203. S32 min_thickness, S32 overlap)
  1204. {
  1205. F32 start_theta = 0.f;
  1206. F32 end_theta = F_TWO_PI;
  1207. F32 x_delta = 0.f;
  1208. F32 y_delta = 0.f;
  1209. if (x < 0)
  1210. {
  1211. x_delta = 0.f - (F32)x;
  1212. start_theta = F_PI + F_PI_BY_TWO;
  1213. end_theta = F_TWO_PI + F_PI_BY_TWO;
  1214. }
  1215. else if (x > rect.getWidth())
  1216. {
  1217. x_delta = (F32)(x - rect.getWidth());
  1218. start_theta = F_PI_BY_TWO;
  1219. end_theta = F_PI + F_PI_BY_TWO;
  1220. }
  1221. if (y < 0)
  1222. {
  1223. y_delta = 0.f - (F32)y;
  1224. if (x < 0)
  1225. {
  1226. start_theta = 0.f;
  1227. end_theta = F_PI_BY_TWO;
  1228. }
  1229. else if (x > rect.getWidth())
  1230. {
  1231. start_theta = F_PI_BY_TWO;
  1232. end_theta = F_PI;
  1233. }
  1234. else
  1235. {
  1236. start_theta = 0.f;
  1237. end_theta = F_PI;
  1238. }
  1239. }
  1240. else if (y > rect.getHeight())
  1241. {
  1242. y_delta = (F32)(y - rect.getHeight());
  1243. if (x < 0)
  1244. {
  1245. start_theta = F_PI + F_PI_BY_TWO;
  1246. end_theta = F_TWO_PI;
  1247. }
  1248. else if (x > rect.getWidth())
  1249. {
  1250. start_theta = F_PI;
  1251. end_theta = F_PI + F_PI_BY_TWO;
  1252. }
  1253. else
  1254. {
  1255. start_theta = F_PI;
  1256. end_theta = F_TWO_PI;
  1257. }
  1258. }
  1259. F32 distance = llmax(0.1f, sqrtf(x_delta * x_delta + y_delta * y_delta));
  1260. F32 outer_radius = distance +
  1261. (1.f + 9.f * sqrtf(x_delta * y_delta) / distance) *
  1262. (F32)overlap;
  1263. F32 inner_radius = outer_radius - (F32)min_thickness;
  1264. F32 angle_adjust_x = asinf(x_delta / outer_radius);
  1265. F32 angle_adjust_y = asinf(y_delta / outer_radius);
  1266. if (angle_adjust_x)
  1267. {
  1268. if (angle_adjust_y)
  1269. {
  1270. F32 angle_adjust = llmin(angle_adjust_x, angle_adjust_y);
  1271. start_theta += angle_adjust;
  1272. end_theta -= angle_adjust;
  1273. }
  1274. else
  1275. {
  1276. start_theta += angle_adjust_x;
  1277. end_theta -= angle_adjust_x;
  1278. }
  1279. }
  1280. else if (angle_adjust_y)
  1281. {
  1282. start_theta += angle_adjust_y;
  1283. end_theta -= angle_adjust_y;
  1284. }
  1285. gGL.matrixMode(LLRender::MM_MODELVIEW);
  1286. gGL.pushMatrix();
  1287. gGL.translatef((F32)x, (F32)y, 0.f);
  1288. gl_washer_segment_2d(inner_radius, outer_radius, start_theta, end_theta,
  1289. 40, color, color);
  1290. gGL.popMatrix();
  1291. }
  1292. //static
  1293. void LLPanelWorldMap::drawTrackingArrow(const LLRect& rect, S32 x, S32 y,
  1294. const LLColor4& color, S32 arrow_size)
  1295. {
  1296. F32 x_center = (F32)rect.getWidth() * 0.5f;
  1297. F32 y_center = (F32)rect.getHeight() * 0.5f;
  1298. F32 x_clamped = (F32)llclamp(x, 0, rect.getWidth() - arrow_size);
  1299. F32 y_clamped = (F32)llclamp(y, 0, rect.getHeight() - arrow_size);
  1300. F32 slope = (F32)(y - y_center) / (F32)(x - x_center);
  1301. F32 window_ratio = (F32)rect.getHeight() / (F32)rect.getWidth();
  1302. if (fabsf(slope) > window_ratio && y_clamped != (F32)y)
  1303. {
  1304. // Clamp by y
  1305. x_clamped = (y_clamped - y_center) / slope + x_center;
  1306. // Adjust for arrow size
  1307. x_clamped = llclamp(x_clamped , 0.f,
  1308. (F32)(rect.getWidth() - arrow_size));
  1309. }
  1310. else if (x_clamped != (F32)x)
  1311. {
  1312. // Clamp by x
  1313. y_clamped = (x_clamped - x_center) * slope + y_center;
  1314. // Adjust for arrow size
  1315. y_clamped = llclamp(y_clamped, 0.f,
  1316. (F32)(rect.getHeight() - arrow_size));
  1317. }
  1318. S32 half_arrow_size = (S32)(0.5f * arrow_size);
  1319. F32 angle = atan2f(y + half_arrow_size - y_center,
  1320. x + half_arrow_size - x_center);
  1321. sTrackingArrowX = llfloor(x_clamped);
  1322. sTrackingArrowY = llfloor(y_clamped);
  1323. gl_draw_scaled_rotated_image(sTrackingArrowX, sTrackingArrowY, arrow_size,
  1324. arrow_size, RAD_TO_DEG * angle,
  1325. sTrackArrowImage->getImage(), color);
  1326. }
  1327. // Note: 'rotation' is in radians (0 means x = 1, y = 0 on the unit circle)
  1328. void LLPanelWorldMap::setDirectionPos(LLTextBox* text_box, F32 rotation)
  1329. {
  1330. F32 map_half_height = getRect().getHeight() * 0.5f;
  1331. F32 map_half_width = getRect().getWidth() * 0.5f;
  1332. F32 text_half_height = text_box->getRect().getHeight() * 0.5f;
  1333. F32 text_half_width = text_box->getRect().getWidth() * 0.5f;
  1334. F32 radius = llmin(map_half_height - text_half_height,
  1335. map_half_width - text_half_width);
  1336. text_box->setOrigin(ll_round(map_half_width - text_half_width +
  1337. radius * cosf(rotation)),
  1338. ll_round(map_half_height - text_half_height +
  1339. radius * sinf(rotation)));
  1340. }
  1341. void LLPanelWorldMap::updateDirections()
  1342. {
  1343. S32 width = getRect().getWidth();
  1344. S32 height = getRect().getHeight();
  1345. S32 text_height = mTextBoxNorth->getRect().getHeight();
  1346. S32 text_width = mTextBoxNorth->getRect().getWidth();
  1347. constexpr S32 PAD = 2;
  1348. S32 top = height - text_height - PAD;
  1349. S32 left = PAD * 2;
  1350. S32 bottom = PAD;
  1351. S32 right = width - text_width - PAD;
  1352. S32 center_x = width / 2 - text_width / 2;
  1353. S32 center_y = height / 2 - text_height / 2;
  1354. mTextBoxNorth->setOrigin(center_x, top);
  1355. mTextBoxEast->setOrigin(right, center_y);
  1356. mTextBoxSouth->setOrigin(center_x, bottom);
  1357. mTextBoxWest->setOrigin(left, center_y);
  1358. // These have wider text boxes
  1359. text_width = mTextBoxNorthWest->getRect().getWidth();
  1360. right = width - text_width - PAD;
  1361. mTextBoxNorthWest->setOrigin(left, top);
  1362. mTextBoxNorthEast->setOrigin(right, top);
  1363. mTextBoxSouthWest->setOrigin(left, bottom);
  1364. mTextBoxSouthEast->setOrigin(right, bottom);
  1365. }
  1366. void LLPanelWorldMap::reshape(S32 width, S32 height, bool called_from_parent)
  1367. {
  1368. LLView::reshape(width, height, called_from_parent);
  1369. }
  1370. bool LLPanelWorldMap::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID& id,
  1371. bool track)
  1372. {
  1373. if (!gFloaterWorldMapp) return true;
  1374. LLVector3 pos_view = globalPosToView(item.mPosGlobal);
  1375. S32 item_x = ll_round(pos_view.mV[VX]);
  1376. S32 item_y = ll_round(pos_view.mV[VY]);
  1377. if (x < item_x - BIG_DOT_RADIUS) return false;
  1378. if (x > item_x + BIG_DOT_RADIUS) return false;
  1379. if (y < item_y - BIG_DOT_RADIUS) return false;
  1380. if (y > item_y + BIG_DOT_RADIUS) return false;
  1381. LLSimInfo* sim_info = gWorldMap.simInfoFromHandle(item.mRegionHandle);
  1382. if (sim_info && track)
  1383. {
  1384. gFloaterWorldMapp->trackLocation(item.mPosGlobal);
  1385. }
  1386. if (track)
  1387. {
  1388. gFloaterWorldMapp->trackGenericItem(item);
  1389. }
  1390. item.mSelected = true;
  1391. id = item.mID;
  1392. return true;
  1393. }
  1394. // Handle a click, which might be on a dot
  1395. void LLPanelWorldMap::handleClick(S32 x, S32 y, MASK mask, S32& hit_type,
  1396. LLUUID& id)
  1397. {
  1398. if (!gFloaterWorldMapp) return;
  1399. LLVector3d pos_global = viewPosToGlobal(x, y);
  1400. // *HACK: Adjust Z values automatically for liaisons & gods so we swoop
  1401. // down when they click on the map.
  1402. if (gAgent.isGodlike())
  1403. {
  1404. pos_global.mdV[VZ] = 200.0;
  1405. }
  1406. hit_type = 0; // Hit nothing
  1407. gWorldMap.mIsTrackingUnknownLocation = false;
  1408. gWorldMap.mIsTrackingDoubleClick = false;
  1409. gWorldMap.mIsTrackingCommit = false;
  1410. // Clear old selected stuff
  1411. for (LLWorldMap::item_info_list_t::iterator
  1412. it = gWorldMap.mPGEvents.begin(),
  1413. end = gWorldMap.mPGEvents.end();
  1414. it != end; ++it)
  1415. {
  1416. it->mSelected = false;
  1417. }
  1418. for (LLWorldMap::item_info_list_t::iterator
  1419. it = gWorldMap.mMatureEvents.begin(),
  1420. end = gWorldMap.mMatureEvents.end();
  1421. it != end; ++it)
  1422. {
  1423. it->mSelected = false;
  1424. }
  1425. for (LLWorldMap::item_info_list_t::iterator
  1426. it = gWorldMap.mAdultEvents.begin(),
  1427. end = gWorldMap.mAdultEvents.end();
  1428. it != end; ++it)
  1429. {
  1430. it->mSelected = false;
  1431. }
  1432. for (LLWorldMap::item_info_list_t::iterator
  1433. it = gWorldMap.mLandForSale.begin(),
  1434. end = gWorldMap.mLandForSale.end();
  1435. it != end; ++it)
  1436. {
  1437. it->mSelected = false;
  1438. }
  1439. // Select event you clicked on
  1440. if (gSavedSettings.getBool("MapShowPGEvents"))
  1441. {
  1442. for (LLWorldMap::item_info_list_t::iterator
  1443. it = gWorldMap.mPGEvents.begin(),
  1444. end = gWorldMap.mPGEvents.end();
  1445. it != end; ++it)
  1446. {
  1447. LLItemInfo& event = *it;
  1448. if (checkItemHit(x, y, event, id, false))
  1449. {
  1450. hit_type = MAP_ITEM_PG_EVENT;
  1451. mItemPicked = true;
  1452. gFloaterWorldMapp->trackEvent(event);
  1453. return;
  1454. }
  1455. }
  1456. }
  1457. if (gSavedSettings.getBool("MapShowMatureEvents"))
  1458. {
  1459. for (LLWorldMap::item_info_list_t::iterator
  1460. it = gWorldMap.mMatureEvents.begin(),
  1461. end = gWorldMap.mMatureEvents.end();
  1462. it != end; ++it)
  1463. {
  1464. LLItemInfo& event = *it;
  1465. if (checkItemHit(x, y, event, id, false))
  1466. {
  1467. hit_type = MAP_ITEM_MATURE_EVENT;
  1468. mItemPicked = true;
  1469. gFloaterWorldMapp->trackEvent(event);
  1470. return;
  1471. }
  1472. }
  1473. }
  1474. if (gSavedSettings.getBool("MapShowAdultEvents"))
  1475. {
  1476. for (LLWorldMap::item_info_list_t::iterator
  1477. it = gWorldMap.mAdultEvents.begin(),
  1478. end = gWorldMap.mAdultEvents.end();
  1479. it != end; ++it)
  1480. {
  1481. LLItemInfo& event = *it;
  1482. if (checkItemHit(x, y, event, id, false))
  1483. {
  1484. hit_type = MAP_ITEM_ADULT_EVENT;
  1485. mItemPicked = true;
  1486. gFloaterWorldMapp->trackEvent(event);
  1487. return;
  1488. }
  1489. }
  1490. }
  1491. if (gSavedSettings.getBool("MapShowLandForSale"))
  1492. {
  1493. for (LLWorldMap::item_info_list_t::iterator
  1494. it = gWorldMap.mLandForSale.begin(),
  1495. end = gWorldMap.mLandForSale.end();
  1496. it != end; ++it)
  1497. {
  1498. LLItemInfo& land = *it;
  1499. if (checkItemHit(x, y, land, id, true))
  1500. {
  1501. hit_type = MAP_ITEM_LAND_FOR_SALE;
  1502. mItemPicked = true;
  1503. return;
  1504. }
  1505. }
  1506. for (LLWorldMap::item_info_list_t::iterator
  1507. it = gWorldMap.mLandForSaleAdult.begin(),
  1508. end = gWorldMap.mLandForSaleAdult.end();
  1509. it != end; ++it)
  1510. {
  1511. LLItemInfo& land = *it;
  1512. if (checkItemHit(x, y, land, id, true))
  1513. {
  1514. hit_type = MAP_ITEM_LAND_FOR_SALE_ADULT;
  1515. mItemPicked = true;
  1516. return;
  1517. }
  1518. }
  1519. }
  1520. // If we get here, we have not clicked on an icon
  1521. gFloaterWorldMapp->trackLocation(pos_global);
  1522. mItemPicked = false;
  1523. id.setNull();
  1524. }
  1525. bool outside_slop(S32 x, S32 y, S32 start_x, S32 start_y)
  1526. {
  1527. S32 dx = x - start_x;
  1528. S32 dy = y - start_y;
  1529. return dx <= -2 || 2 <= dx || dy <= -2 || 2 <= dy;
  1530. }
  1531. bool LLPanelWorldMap::handleMouseDown(S32 x, S32 y, MASK mask)
  1532. {
  1533. gFocusMgr.setMouseCapture(this);
  1534. mMouseDownPanX = ll_round(sPanX);
  1535. mMouseDownPanY = ll_round(sPanY);
  1536. mMouseDownX = x;
  1537. mMouseDownY = y;
  1538. sHandledLastClick = true;
  1539. return true;
  1540. }
  1541. bool LLPanelWorldMap::handleMouseUp(S32 x, S32 y, MASK mask)
  1542. {
  1543. if (hasMouseCapture())
  1544. {
  1545. if (mPanning)
  1546. {
  1547. // Restore mouse cursor
  1548. S32 local_x, local_y;
  1549. local_x = mMouseDownX + llfloor(sPanX - mMouseDownPanX);
  1550. local_y = mMouseDownY + llfloor(sPanY - mMouseDownPanY);
  1551. LLRect clip_rect = getRect();
  1552. clip_rect.stretch(-8);
  1553. clip_rect.clipPointToRect(mMouseDownX, mMouseDownY, local_x,
  1554. local_y);
  1555. LLUI::setCursorPositionLocal(this, local_x, local_y);
  1556. // Finish the pan
  1557. mPanning = false;
  1558. mMouseDownX = 0;
  1559. mMouseDownY = 0;
  1560. }
  1561. else
  1562. {
  1563. // Ignore whether we hit an event or not
  1564. S32 hit_type = 0;
  1565. LLUUID id;
  1566. handleClick(x, y, mask, hit_type, id);
  1567. }
  1568. gViewerWindowp->showCursor();
  1569. gFocusMgr.setMouseCapture(NULL);
  1570. return true;
  1571. }
  1572. return false;
  1573. }
  1574. U32 LLPanelWorldMap::updateVisibleBlocks()
  1575. {
  1576. if (sMapScale < SIM_MAP_SCALE)
  1577. {
  1578. // We do not care what is loaded if we are zoomed out
  1579. return 0;
  1580. }
  1581. LLVector3d camera_global = gAgent.getCameraPositionGlobal();
  1582. const S32 half_width = 0.5f * getRect().getWidth();
  1583. const S32 half_height = 0.5f * getRect().getHeight();
  1584. // Compute center into sim grid coordinates
  1585. S32 world_center_x = S32(-sPanX / sMapScale +
  1586. camera_global.mdV[0] / REGION_WIDTH_METERS);
  1587. S32 world_center_y = S32(-sPanY / sMapScale +
  1588. camera_global.mdV[1] / REGION_WIDTH_METERS);
  1589. // Find the corresponding 8x8 block
  1590. S32 world_left = world_center_x - S32(half_width / sMapScale) - 1;
  1591. S32 world_right = world_center_x + S32(half_width / sMapScale) + 1;
  1592. S32 world_bottom = world_center_y - S32(half_height / sMapScale) - 1;
  1593. S32 world_top = world_center_y + S32(half_height / sMapScale) + 1;
  1594. return gWorldMap.updateRegions(world_left, world_bottom, world_right,
  1595. world_top);
  1596. }
  1597. bool LLPanelWorldMap::handleHover(S32 x, S32 y, MASK mask)
  1598. {
  1599. if (hasMouseCapture())
  1600. {
  1601. if (mPanning || outside_slop(x, y, mMouseDownX, mMouseDownY))
  1602. {
  1603. // Just started panning, so hide cursor
  1604. if (!mPanning)
  1605. {
  1606. mPanning = true;
  1607. gViewerWindowp->hideCursor();
  1608. }
  1609. F32 delta_x = (F32)(gViewerWindowp->getCurrentMouseDX());
  1610. F32 delta_y = (F32)(gViewerWindowp->getCurrentMouseDY());
  1611. // Set pan to value at start of drag + offset
  1612. sPanX += delta_x;
  1613. sPanY += delta_y;
  1614. sTargetPanX = sPanX;
  1615. sTargetPanY = sPanY;
  1616. gViewerWindowp->moveCursorToCenter();
  1617. }
  1618. // It does not matter, cursor should be hidden
  1619. gViewerWindowp->setCursor(UI_CURSOR_CROSS);
  1620. return true;
  1621. }
  1622. else
  1623. {
  1624. // While we are waiting for data from the tracker, we are busy. JC
  1625. LLVector3d pos_global = gTracker.getTrackedPositionGlobal();
  1626. if (gTracker.isTracking() && pos_global.isExactlyZero())
  1627. {
  1628. gViewerWindowp->setCursor(UI_CURSOR_WAIT);
  1629. }
  1630. else
  1631. {
  1632. gViewerWindowp->setCursor(UI_CURSOR_CROSS);
  1633. }
  1634. LL_DEBUGS("UserInput") << "Hover handled by LLPanelWorldMap"
  1635. << LL_ENDL;
  1636. return true;
  1637. }
  1638. }
  1639. bool LLPanelWorldMap::handleDoubleClick(S32 x, S32 y, MASK mask)
  1640. {
  1641. if (!gFloaterWorldMapp) return true;
  1642. if (sHandledLastClick)
  1643. {
  1644. S32 hit_type = 0;
  1645. LLUUID id;
  1646. handleClick(x, y, mask, hit_type, id);
  1647. switch (hit_type)
  1648. {
  1649. case MAP_ITEM_PG_EVENT:
  1650. case MAP_ITEM_MATURE_EVENT:
  1651. case MAP_ITEM_ADULT_EVENT:
  1652. {
  1653. gFloaterWorldMapp->close();
  1654. // This is an ungainly hack
  1655. std::string uuid_str;
  1656. S32 event_id;
  1657. id.toString(uuid_str);
  1658. uuid_str = uuid_str.substr(28);
  1659. sscanf(uuid_str.c_str(), "%X", &event_id);
  1660. HBFloaterSearch::showEvents(event_id);
  1661. break;
  1662. }
  1663. case MAP_ITEM_LAND_FOR_SALE:
  1664. case MAP_ITEM_LAND_FOR_SALE_ADULT:
  1665. {
  1666. gFloaterWorldMapp->close();
  1667. HBFloaterSearch::showLandForSale(id);
  1668. break;
  1669. }
  1670. case MAP_ITEM_CLASSIFIED:
  1671. {
  1672. gFloaterWorldMapp->close();
  1673. HBFloaterSearch::showClassified(id);
  1674. break;
  1675. }
  1676. default:
  1677. {
  1678. if (gWorldMap.mIsTrackingUnknownLocation)
  1679. {
  1680. gWorldMap.mIsTrackingDoubleClick = true;
  1681. }
  1682. else
  1683. {
  1684. // Teleport if we got a valid location
  1685. LLVector3d pos_global = viewPosToGlobal(x, y);
  1686. LLSimInfo* sim_info =
  1687. gWorldMap.simInfoFromPosGlobal(pos_global);
  1688. if (sim_info && sim_info->mAccess != SIM_ACCESS_DOWN)
  1689. {
  1690. gAgent.teleportViaLocation(pos_global);
  1691. }
  1692. }
  1693. }
  1694. }
  1695. return true;
  1696. }
  1697. return false;
  1698. }