aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llworldmapview.cpp
diff options
context:
space:
mode:
authorJacek Antonelli2008-08-15 23:44:46 -0500
committerJacek Antonelli2008-08-15 23:44:46 -0500
commit38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4 (patch)
treeadca584755d22ca041a2dbfc35d4eca01f70b32c /linden/indra/newview/llworldmapview.cpp
parentREADME.txt (diff)
downloadmeta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.zip
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.gz
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.bz2
meta-impy-38d6d37f2d982fa959e9e8a4a3f7e1ccfad7b5d4.tar.xz
Second Life viewer sources 1.13.2.12
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llworldmapview.cpp1962
1 files changed, 1962 insertions, 0 deletions
diff --git a/linden/indra/newview/llworldmapview.cpp b/linden/indra/newview/llworldmapview.cpp
new file mode 100644
index 0000000..83e10d9
--- /dev/null
+++ b/linden/indra/newview/llworldmapview.cpp
@@ -0,0 +1,1962 @@
1/**
2 * @file llworldmapview.cpp
3 * @brief LLWorldMapView class implementation
4 *
5 * Copyright (c) 2001-2007, Linden Research, Inc.
6 *
7 * The source code in this file ("Source Code") is provided by Linden Lab
8 * to you under the terms of the GNU General Public License, version 2.0
9 * ("GPL"), unless you have obtained a separate licensing agreement
10 * ("Other License"), formally executed by you and Linden Lab. Terms of
11 * the GPL can be found in doc/GPL-license.txt in this distribution, or
12 * online at http://secondlife.com/developers/opensource/gplv2
13 *
14 * There are special exceptions to the terms and conditions of the GPL as
15 * it is applied to this Source Code. View the full text of the exception
16 * in the file doc/FLOSS-exception.txt in this software distribution, or
17 * online at http://secondlife.com/developers/opensource/flossexception
18 *
19 * By copying, modifying or distributing this software, you acknowledge
20 * that you have read and understood your obligations described above,
21 * and agree to abide by those obligations.
22 *
23 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
24 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
25 * COMPLETENESS OR PERFORMANCE.
26 */
27
28#include "llviewerprecompiledheaders.h"
29
30#include "llworldmapview.h"
31
32#include "indra_constants.h"
33#include "llui.h"
34#include "linked_lists.h"
35#include "llmath.h" // clampf()
36#include "llregionhandle.h"
37#include "lleventflags.h"
38
39#include "llagent.h"
40#include "llcallingcard.h"
41#include "llcolorscheme.h"
42#include "llviewercontrol.h"
43#include "llcylinder.h"
44#include "llfloaterdirectory.h"
45#include "llfloatermap.h"
46#include "llfloaterworldmap.h"
47#include "llfocusmgr.h"
48#include "lltextbox.h"
49#include "lltextureview.h"
50#include "lltracker.h"
51#include "llviewercamera.h"
52#include "llviewerimage.h"
53#include "llviewerimagelist.h"
54#include "llviewerparceloverlay.h"
55#include "llviewerregion.h"
56#include "llviewerwindow.h"
57#include "llworld.h"
58#include "llworldmap.h"
59#include "viewer.h" // Only for constants!
60
61#include "llglheaders.h"
62
63const F32 GODLY_TELEPORT_HEIGHT = 200.f;
64const S32 SCROLL_HINT_WIDTH = 65;
65const F32 BIG_DOT_RADIUS = 5.f;
66BOOL LLWorldMapView::sHandledLastClick = FALSE;
67
68LLPointer<LLViewerImage> LLWorldMapView::sAvatarYouSmallImage = NULL;
69LLPointer<LLViewerImage> LLWorldMapView::sAvatarSmallImage = NULL;
70LLPointer<LLViewerImage> LLWorldMapView::sAvatarLargeImage = NULL;
71
72LLPointer<LLViewerImage> LLWorldMapView::sTelehubImage = NULL;
73LLPointer<LLViewerImage> LLWorldMapView::sInfohubImage = NULL;
74LLPointer<LLViewerImage> LLWorldMapView::sHomeImage = NULL;
75LLPointer<LLViewerImage> LLWorldMapView::sEventImage = NULL;
76LLPointer<LLViewerImage> LLWorldMapView::sEventMatureImage = NULL;
77
78LLPointer<LLViewerImage> LLWorldMapView::sTrackCircleImage = NULL;
79LLPointer<LLViewerImage> LLWorldMapView::sTrackArrowImage = NULL;
80
81LLPointer<LLViewerImage> LLWorldMapView::sClassifiedsImage = NULL;
82LLPointer<LLViewerImage> LLWorldMapView::sPopularImage = NULL;
83LLPointer<LLViewerImage> LLWorldMapView::sForSaleImage = NULL;
84
85F32 LLWorldMapView::sThresholdA = 48.f;
86F32 LLWorldMapView::sThresholdB = 96.f;
87F32 LLWorldMapView::sPanX = 0.f;
88F32 LLWorldMapView::sPanY = 0.f;
89F32 LLWorldMapView::sTargetPanX = 0.f;
90F32 LLWorldMapView::sTargetPanY = 0.f;
91S32 LLWorldMapView::sTrackingArrowX = 0;
92S32 LLWorldMapView::sTrackingArrowY = 0;
93F32 LLWorldMapView::sPixelsPerMeter = 1.f;
94F32 CONE_SIZE = 0.6f;
95
96void LLWorldMapView::initClass()
97{
98 LLUUID image_id;
99
100 image_id.set( gViewerArt.getString("map_avatar_you_8.tga") );
101 sAvatarYouSmallImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
102
103 image_id.set( gViewerArt.getString("map_avatar_8.tga") );
104 sAvatarSmallImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
105
106 image_id.set( gViewerArt.getString("map_avatar_16.tga") );
107 sAvatarLargeImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
108
109 image_id.set( gViewerArt.getString("map_home.tga") );
110 sHomeImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
111
112 image_id.set( gViewerArt.getString("map_telehub.tga") );
113 sTelehubImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
114
115 image_id.set( gViewerArt.getString("map_infohub.tga") );
116 sInfohubImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
117
118 image_id.set( gViewerArt.getString("map_event.tga") );
119 sEventImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
120
121 image_id.set( gViewerArt.getString("map_event_mature.tga") );
122 sEventMatureImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
123
124 image_id.set( gViewerArt.getString("map_track_16.tga") );
125 sTrackCircleImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
126
127 image_id.set( gViewerArt.getString("direction_arrow.tga") );
128 sTrackArrowImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
129 // Make sure tracker arrow doesn't wrap
130 sTrackArrowImage->bindTexture(0);
131 sTrackArrowImage->setClamp(TRUE, TRUE);
132
133 image_id.set( gViewerArt.getString("icon_top_pick.tga") );
134 sClassifiedsImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
135
136 image_id.set( gViewerArt.getString("icon_popular.tga") );
137 sPopularImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
138
139 image_id.set( gViewerArt.getString("icon_for_sale.tga") );
140 sForSaleImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
141}
142
143// static
144void LLWorldMapView::cleanupClass()
145{
146 sAvatarYouSmallImage = NULL;
147 sAvatarSmallImage = NULL;
148 sAvatarLargeImage = NULL;
149 sTelehubImage = NULL;
150 sInfohubImage = NULL;
151 sHomeImage = NULL;
152 sEventImage = NULL;
153 sEventMatureImage = NULL;
154 sTrackCircleImage = NULL;
155 sTrackArrowImage = NULL;
156 sClassifiedsImage = NULL;
157 sPopularImage = NULL;
158 sForSaleImage = NULL;
159}
160
161LLWorldMapView::LLWorldMapView(const std::string& name, const LLRect& rect )
162: LLPanel(name, rect, BORDER_NO),
163 mBackgroundColor( LLColor4( 4.f/255.f, 4.f/255.f, 75.f/255.f, 1.f ) ),
164 mItemPicked(FALSE),
165 mPanning( FALSE ),
166 mMouseDownPanX( 0 ),
167 mMouseDownPanY( 0 ),
168 mMouseDownX( 0 ),
169 mMouseDownY( 0 ),
170 mSelectIDStart(0),
171 mAgentCountsUpdateTime(0)
172{
173 sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS;
174 clearLastClick();
175
176 const S32 DIR_WIDTH = 10;
177 const S32 DIR_HEIGHT = 10;
178 LLRect major_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH, 0 );
179
180 mTextBoxNorth = new LLTextBox( "N", major_dir_rect );
181 mTextBoxNorth->setDropshadowVisible( TRUE );
182 addChild( mTextBoxNorth );
183
184 LLColor4 minor_color( 1.f, 1.f, 1.f, .7f );
185
186 mTextBoxEast = new LLTextBox( "E", major_dir_rect );
187 mTextBoxEast->setColor( minor_color );
188 addChild( mTextBoxEast );
189
190 mTextBoxWest = new LLTextBox( "W", major_dir_rect );
191 mTextBoxWest->setColor( minor_color );
192 addChild( mTextBoxWest );
193
194 mTextBoxSouth = new LLTextBox( "S", major_dir_rect );
195 mTextBoxSouth->setColor( minor_color );
196 addChild( mTextBoxSouth );
197
198 LLRect minor_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH * 2, 0 );
199
200 mTextBoxSouthEast = new LLTextBox( "SE", minor_dir_rect );
201 mTextBoxSouthEast->setColor( minor_color );
202 addChild( mTextBoxSouthEast );
203
204 mTextBoxNorthEast = new LLTextBox( "NE", minor_dir_rect );
205 mTextBoxNorthEast->setColor( minor_color );
206 addChild( mTextBoxNorthEast );
207
208 mTextBoxSouthWest = new LLTextBox( "SW", minor_dir_rect );
209 mTextBoxSouthWest->setColor( minor_color );
210 addChild( mTextBoxSouthWest );
211
212 mTextBoxNorthWest = new LLTextBox( "NW", minor_dir_rect );
213 mTextBoxNorthWest->setColor( minor_color );
214 addChild( mTextBoxNorthWest );
215}
216
217
218LLWorldMapView::~LLWorldMapView()
219{
220 cleanupTextures();
221}
222
223
224// static
225void LLWorldMapView::cleanupTextures()
226{
227}
228
229
230// static
231void LLWorldMapView::setScale( F32 scale )
232{
233 if (scale != gMapScale)
234 {
235 F32 old_scale = gMapScale;
236
237 gMapScale = scale;
238 if (gMapScale == 0.f)
239 {
240 gMapScale = 0.1f;
241 }
242
243 F32 ratio = (scale / old_scale);
244 sPanX *= ratio;
245 sPanY *= ratio;
246 sTargetPanX = sPanX;
247 sTargetPanY = sPanY;
248
249 sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS;
250 }
251}
252
253
254// static
255void LLWorldMapView::translatePan( S32 delta_x, S32 delta_y )
256{
257 sPanX += delta_x;
258 sPanY += delta_y;
259 sTargetPanX = sPanX;
260 sTargetPanY = sPanY;
261}
262
263
264// static
265void LLWorldMapView::setPan( S32 x, S32 y, BOOL snap )
266{
267 sTargetPanX = (F32)x;
268 sTargetPanY = (F32)y;
269 if (snap)
270 {
271 sPanX = sTargetPanX;
272 sPanY = sTargetPanY;
273 }
274}
275
276
277///////////////////////////////////////////////////////////////////////////////////
278
279// dumb helper function
280BOOL is_agent_in_region(LLViewerRegion* region, LLSimInfo* info)
281{
282 if((region && info)
283 && (info->mName == region->getName()))
284 {
285 return TRUE;
286 }
287 return FALSE;
288}
289
290void LLWorldMapView::draw()
291{
292 if (!getVisible() || !gWorldPointer)
293 {
294 return;
295 }
296
297 LLTextureView::clearDebugImages();
298
299 F64 current_time = LLTimer::getElapsedSeconds();
300
301 if (current_time - mAgentCountsUpdateTime > AGENT_COUNTS_UPDATE_TIME)
302 {
303 gWorldMap->sendItemRequest(MAP_ITEM_AGENT_COUNT);
304 mAgentCountsUpdateTime = current_time;
305 }
306
307 mVisibleRegions.clear();
308
309 // animate pan if necessary
310 sPanX = lerp(sPanX, sTargetPanX, LLCriticalDamp::getInterpolant(0.1f));
311 sPanY = lerp(sPanY, sTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
312
313 LLVector3d pos_global;
314 LLVector3 pos_map;
315
316 const S32 width = mRect.getWidth();
317 const S32 height = mRect.getHeight();
318 const S32 half_width = width / 2;
319 const S32 half_height = height / 2;
320 LLVector3d camera_global = gAgent.getCameraPositionGlobal();
321
322 LLGLEnable scissor_test(GL_SCISSOR_TEST);
323 LLUI::setScissorRegionLocal(LLRect(0, height, width, 0));
324 {
325 LLGLSNoTexture no_texture;
326
327
328 glMatrixMode(GL_MODELVIEW);
329
330 // Clear the background alpha to 0
331 glColorMask(FALSE, FALSE, FALSE, TRUE);
332 glAlphaFunc(GL_GEQUAL, 0.00f);
333 glBlendFunc(GL_ONE, GL_ZERO);
334 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
335 gl_rect_2d(0, height, width, 0);
336 }
337
338 glAlphaFunc(GL_GEQUAL, 0.01f);
339 glColorMask(TRUE, TRUE, TRUE, TRUE);
340 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
341
342 F32 layer_alpha = 1.f;
343
344 // Draw one image per layer
345 for (U32 layer_idx=0; layer_idx<gWorldMap->mMapLayers[gWorldMap->mCurrentMap].size(); ++layer_idx)
346 {
347 if (!gWorldMap->mMapLayers[gWorldMap->mCurrentMap][layer_idx].LayerDefined)
348 {
349 continue;
350 }
351 LLWorldMapLayer *layer = &gWorldMap->mMapLayers[gWorldMap->mCurrentMap][layer_idx];
352 LLViewerImage *current_image = layer->LayerImage;
353#if 1 || LL_RELEASE_FOR_DOWNLOAD
354 if (current_image->isMissingAsset())
355 {
356 continue; // better to draw nothing than the missing asset image
357 }
358#endif
359
360 LLVector3d origin_global((F64)layer->LayerExtents.mLeft * REGION_WIDTH_METERS, (F64)layer->LayerExtents.mBottom * REGION_WIDTH_METERS, 0.f);
361
362 // Find x and y position relative to camera's center.
363 LLVector3d rel_region_pos = origin_global - camera_global;
364 S32 relative_x = lltrunc((rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale);
365 S32 relative_y = lltrunc((rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale);
366
367 F32 pix_width = gMapScale*(layer->LayerExtents.getWidth() + 1);
368 F32 pix_height = gMapScale*(layer->LayerExtents.getHeight() + 1);
369
370 // When the view isn't panned, 0,0 = center of rectangle
371 F32 bottom = sPanY + half_height + relative_y;
372 F32 left = sPanX + half_width + relative_x;
373 F32 top = bottom + pix_height;
374 F32 right = left + pix_width;
375 F32 pixel_area = pix_width*pix_height;
376 // discard layers that are outside the rectangle
377 // and discard small layers
378 if (top < 0.f ||
379 bottom > height ||
380 right < 0.f ||
381 left > width ||
382 (pixel_area < 4*4))
383 {
384 current_image->setBoostLevel(0);
385 continue;
386 }
387
388 current_image->setBoostLevel(LLViewerImage::BOOST_MAP_LAYER);
389 current_image->setKnownDrawSize(llround(pix_width), llround(pix_height));
390
391#if 1 || LL_RELEASE_FOR_DOWNLOAD
392 if (!current_image->getHasGLTexture())
393 {
394 continue; // better to draw nothing than the default image
395 }
396#endif
397
398 LLTextureView::addDebugImage(current_image);
399
400 // Draw using the texture. If we don't clamp we get artifact at
401 // the edge.
402 LLViewerImage::bindTexture(current_image);
403
404 // Draw map image into RGB
405 //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
406 glColorMask(TRUE, TRUE, TRUE, FALSE);
407 glColor4f(1.f, 1.f, 1.f, layer_alpha);
408
409 glBegin(GL_QUADS);
410 glTexCoord2f(0.0f, 1.0f);
411 glVertex3f(left, top, -1.0f);
412 glTexCoord2f(0.0f, 0.0f);
413 glVertex3f(left, bottom, -1.0f);
414 glTexCoord2f(1.0f, 0.0f);
415 glVertex3f(right, bottom, -1.0f);
416 glTexCoord2f(1.0f, 1.0f);
417 glVertex3f(right, top, -1.0f);
418 glEnd();
419
420 // draw an alpha of 1 where the sims are visible
421 glColorMask(FALSE, FALSE, FALSE, TRUE);
422 glColor4f(1.f, 1.f, 1.f, 1.f);
423
424 glBegin(GL_QUADS);
425 glTexCoord2f(0.0f, 1.0f);
426 glVertex2f(left, top);
427 glTexCoord2f(0.0f, 0.0f);
428 glVertex2f(left, bottom);
429 glTexCoord2f(1.0f, 0.0f);
430 glVertex2f(right, bottom);
431 glTexCoord2f(1.0f, 1.0f);
432 glVertex2f(right, top);
433 glEnd();
434 }
435
436 glAlphaFunc(GL_GEQUAL, 0.01f);
437 glColorMask(TRUE, TRUE, TRUE, TRUE);
438
439#if 1
440 F32 sim_alpha = 1.f;
441
442 // Draw one image per region, centered on the camera position.
443 for (LLWorldMap::sim_info_map_t::iterator it = gWorldMap->mSimInfoMap.begin();
444 it != gWorldMap->mSimInfoMap.end(); ++it)
445 {
446 U64 handle = (*it).first;
447 LLSimInfo* info = (*it).second;
448
449 if (info->mCurrentImage.isNull())
450 {
451 info->mCurrentImage = gImageList.getImage(info->mMapImageID[gWorldMap->mCurrentMap], MIPMAP_TRUE, FALSE);
452 }
453 if (info->mOverlayImage.isNull() && info->mMapImageID[2].notNull())
454 {
455 info->mOverlayImage = gImageList.getImage(info->mMapImageID[2], MIPMAP_TRUE, FALSE);
456 info->mOverlayImage->bind(0);
457 info->mOverlayImage->setClamp(TRUE, TRUE);
458 }
459
460 LLViewerImage* simimage = info->mCurrentImage;
461 LLViewerImage* overlayimage = info->mOverlayImage;
462
463 if (gMapScale < 8.f)
464 {
465 simimage->setBoostLevel(0);
466 if (overlayimage) overlayimage->setBoostLevel(0);
467 continue;
468 }
469
470 LLVector3d origin_global = from_region_handle(handle);
471 LLVector3d camera_global = gAgent.getCameraPositionGlobal();
472
473 // Find x and y position relative to camera's center.
474 LLVector3d rel_region_pos = origin_global - camera_global;
475 S32 relative_x = lltrunc((rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale);
476 S32 relative_y = lltrunc((rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale);
477
478 // When the view isn't panned, 0,0 = center of rectangle
479 F32 bottom = sPanY + half_height + relative_y;
480 F32 left = sPanX + half_width + relative_x;
481 F32 top = bottom + gMapScale ;
482 F32 right = left + gMapScale ;
483
484 // Switch to world map texture (if available for this region) if either:
485 // 1. Tiles are zoomed out small enough, or
486 // 2. Sim's texture has not been loaded yet
487 F32 map_scale_cutoff = SIM_MAP_SCALE;
488 if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) > 0)
489 {
490 map_scale_cutoff = SIM_NULL_MAP_SCALE;
491 }
492
493 info->mShowAgentLocations = (gMapScale >= SIM_MAP_AGENT_SCALE);
494
495 bool sim_visible =
496 (gMapScale >= map_scale_cutoff) &&
497 (simimage->getHasGLTexture());
498
499 if (sim_visible)
500 {
501 // Fade in
502 if (info->mAlpha < 0.0f)
503 info->mAlpha = 1.f; // don't fade initially
504 else
505 info->mAlpha = lerp(info->mAlpha, 1.f, LLCriticalDamp::getInterpolant(0.15f));
506 }
507 else
508 {
509 // Fade out
510 if (info->mAlpha < 0.0f)
511 info->mAlpha = 0.f; // don't fade initially
512 else
513 info->mAlpha = lerp(info->mAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f));
514 }
515
516 // discard regions that are outside the rectangle
517 // and discard small regions
518 if (top < 0.f ||
519 bottom > height ||
520 right < 0.f ||
521 left > width )
522 {
523 simimage->setBoostLevel(0);
524 if (overlayimage) overlayimage->setBoostLevel(0);
525 continue;
526 }
527
528 mVisibleRegions.push_back(handle);
529 // See if the agents need updating
530 if (current_time - info->mAgentsUpdateTime > AGENTS_UPDATE_TIME)
531 {
532 gWorldMap->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, info->mHandle);
533 info->mAgentsUpdateTime = current_time;
534 }
535
536 // Bias the priority escalation for images nearer
537 LLVector3d center_global = origin_global;
538 center_global.mdV[VX] += 128.0;
539 center_global.mdV[VY] += 128.0;
540
541 S32 draw_size = llround(gMapScale);
542 simimage->setBoostLevel(LLViewerImage::BOOST_MAP);
543 simimage->setKnownDrawSize(draw_size, draw_size);
544
545 if (overlayimage)
546 {
547 overlayimage->setBoostLevel(LLViewerImage::BOOST_MAP);
548 overlayimage->setKnownDrawSize(draw_size, draw_size);
549 }
550
551 LLTextureView::addDebugImage(simimage);
552
553 if (sim_visible && info->mAlpha > 0.001f)
554 {
555 // Draw using the texture. If we don't clamp we get artifact at
556 // the edge.
557 LLGLSUIDefault gls_ui;
558 LLViewerImage::bindTexture(simimage);
559
560 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
561 F32 alpha = sim_alpha * info->mAlpha;
562 glColor4f(1.f, 1.0f, 1.0f, alpha);
563
564 glBegin(GL_QUADS);
565 glTexCoord2f(0.f, 1.f);
566 glVertex3f(left, top, 0.f);
567 glTexCoord2f(0.f, 0.f);
568 glVertex3f(left, bottom, 0.f);
569 glTexCoord2f(1.f, 0.f);
570 glVertex3f(right, bottom, 0.f);
571 glTexCoord2f(1.f, 1.f);
572 glVertex3f(right, top, 0.f);
573 glEnd();
574
575 if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->getHasGLTexture())
576 {
577 LLViewerImage::bindTexture(overlayimage);
578 glColor4f(1.f, 1.f, 1.f, alpha);
579 glBegin(GL_QUADS);
580 glTexCoord2f(0.f, 1.f);
581 glVertex3f(left, top, -0.5f);
582 glTexCoord2f(0.f, 0.f);
583 glVertex3f(left, bottom, -0.5f);
584 glTexCoord2f(1.f, 0.f);
585 glVertex3f(right, bottom, -0.5f);
586 glTexCoord2f(1.f, 1.f);
587 glVertex3f(right, top, -0.5f);
588 glEnd();
589 }
590
591 if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) == 0)
592 {
593 // draw an alpha of 1 where the sims are visible (except NULL sims)
594 glBlendFunc(GL_ONE, GL_ZERO);
595 glColorMask(FALSE, FALSE, FALSE, TRUE);
596 glColor4f(1.f, 1.f, 1.f, 1.f);
597
598 LLGLSNoTexture gls_no_texture;
599 glBegin(GL_QUADS);
600 glVertex2f(left, top);
601 glVertex2f(left, bottom);
602 glVertex2f(right, bottom);
603 glVertex2f(right, top);
604 glEnd();
605
606 glColorMask(TRUE, TRUE, TRUE, TRUE);
607 }
608 }
609
610 if (info->mAccess == SIM_ACCESS_DOWN)
611 {
612 // Draw a transparent red square over down sims
613 glBlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA);
614 glColor4f(0.2f, 0.0f, 0.0f, 0.4f);
615
616 LLGLSNoTexture gls_no_texture;
617 glBegin(GL_QUADS);
618 glVertex2f(left, top);
619 glVertex2f(left, bottom);
620 glVertex2f(right, bottom);
621 glVertex2f(right, top);
622 glEnd();
623 }
624
625 // If this is mature, and you are not, draw a line across it
626 if (info->mAccess != SIM_ACCESS_DOWN && info->mAccess > gAgent.mAccess)
627 {
628 glBlendFunc(GL_DST_ALPHA, GL_ZERO);
629
630 LLGLSNoTexture gls_no_texture;
631 glColor3f(1.f, 0.f, 0.f);
632 glBegin(GL_LINES);
633 glVertex2f(left, top);
634 glVertex2f(right, bottom);
635 glVertex2f(left, bottom);
636 glVertex2f(right, top);
637 glEnd();
638 }
639
640 // Draw the region name in the lower left corner
641 LLFontGL* font = LLFontGL::sSansSerifSmall;
642
643 char mesg[MAX_STRING];
644 if (gMapScale < sThresholdA)
645 {
646 mesg[0] = '\0';
647 }
648 else if (gMapScale < sThresholdB)
649 {
650 //sprintf(mesg, "%d", info->mAgents);
651 mesg[0] = '\0';
652 }
653 else
654 {
655 //sprintf(mesg, "%d / %s (%s)",
656 // info->mAgents,
657 // info->mName.c_str(),
658 // LLViewerRegion::accessToShortString(info->mAccess) );
659 if (info->mAccess == SIM_ACCESS_DOWN)
660 {
661 sprintf(mesg, "%s (Offline)", info->mName.c_str());
662 }
663 else
664 {
665 sprintf(mesg, "%s", info->mName.c_str());
666 }
667 }
668
669 if (mesg[0] != '\0')
670 {
671 font->renderUTF8(
672 mesg, 0,
673 llfloor(left + 3),
674 llfloor(bottom + 2),
675 LLColor4::white,
676 LLFontGL::LEFT,
677 LLFontGL::BASELINE,
678 LLFontGL::DROP_SHADOW);
679 }
680 }
681#endif
682
683
684#if 1
685 // Draw background rectangle
686 LLGLSUIDefault gls_ui;
687 {
688 LLGLSNoTexture gls_no_texture;
689 glAlphaFunc(GL_GEQUAL, 0.0f);
690 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
691 glColor4fv( mBackgroundColor.mV );
692 gl_rect_2d(0, height, width, 0);
693 }
694
695 glAlphaFunc(GL_GEQUAL, 0.01f);
696 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
697
698 // Infohubs
699 // Draw under avatar so you can find yourself.
700 if (gSavedSettings.getBOOL("MapShowInfohubs")) //(gMapScale >= sThresholdB)
701 {
702 S32 infohub_icon_size = (S32)sInfohubImage->getWidth();
703 for (U32 infohub=0; infohub<gWorldMap->mInfohubs.size(); ++infohub)
704 {
705 LLItemInfo *infohub_info = &gWorldMap->mInfohubs[infohub];
706
707 pos_map = globalPosToView(infohub_info->mPosGlobal);
708 gl_draw_image(llround(pos_map.mV[VX])-infohub_icon_size/2,
709 llround(pos_map.mV[VY])-infohub_icon_size/2,
710 sInfohubImage,
711 LLColor4::white);
712 }
713 }
714
715 // Telehubs
716 // Draw under avatar so you can find yourself.
717 if (gSavedSettings.getBOOL("MapShowTelehubs")) //(gMapScale >= sThresholdB)
718 {
719 S32 telehub_icon_size = (S32)sTelehubImage->getWidth();
720 for (U32 telehub=0; telehub<gWorldMap->mTelehubs.size(); ++telehub)
721 {
722 LLItemInfo *telehub_info = &gWorldMap->mTelehubs[telehub];
723
724 pos_map = globalPosToView(telehub_info->mPosGlobal);
725 gl_draw_image(llround(pos_map.mV[VX])-telehub_icon_size/2,
726 llround(pos_map.mV[VY])-telehub_icon_size/2,
727 sTelehubImage,
728 LLColor4::white);
729 }
730 }
731
732 // Home
733 // Always Draw
734 if (1) //(gMapScale >= sThresholdB)
735 {
736 S32 home_icon_size = (S32)sHomeImage->getWidth();
737 if (gAgent.getHomePosGlobal(&pos_global))
738 {
739 pos_map = globalPosToView(pos_global);
740 gl_draw_image(llround(pos_map.mV[VX])-home_icon_size/2,
741 llround(pos_map.mV[VY])-home_icon_size/2,
742 sHomeImage,
743 LLColor4::white);
744 }
745 }
746
747 // Draw all these under the avatar, so you can find yourself
748
749 if (gSavedSettings.getBOOL("MapShowLandForSale"))
750 {
751 drawGenericItems(gWorldMap->mLandForSale, sForSaleImage);
752 }
753
754 if (gSavedSettings.getBOOL("MapShowClassifieds"))
755 {
756 drawGenericItems(gWorldMap->mClassifieds, sClassifiedsImage);
757 }
758
759 if (gSavedSettings.getBOOL("MapShowPopular"))
760 {
761 drawGenericItems(gWorldMap->mPopular, sPopularImage);
762 }
763
764 if (gSavedSettings.getBOOL("MapShowEvents"))
765 {
766 drawEvents();
767 }
768
769 // Your avatar.
770 // Draw avatar position, always, and underneath other avatars
771 pos_global = gAgent.getPositionGlobal();
772 pos_map = globalPosToView(pos_global);
773 gl_draw_image(llround(pos_map.mV[VX])-8,
774 llround(pos_map.mV[VY])-8,
775 sAvatarLargeImage,
776 LLColor4::white);
777
778 if (!pointInView(llround(pos_map.mV[VX]), llround(pos_map.mV[VY])))
779 {
780 drawTracking(pos_global,
781 lerp(LLColor4::yellow, LLColor4::orange, 0.4f),
782 TRUE,
783 "You are here",
784 "",
785 llround(LLFontGL::sSansSerifSmall->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking
786 }
787
788 drawFrustum();
789
790 // Draw icons for the avatars in each region.
791 // Draw after avatar so you can see nearby people.
792 if (gSavedSettings.getBOOL("MapShowPeople"))
793 {
794 drawAgents();
795 }
796
797 //-----------------------------------------------------------------------
798
799 // Always draw tracking information
800 LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
801 if ( LLTracker::TRACKING_AVATAR == tracking_status )
802 {
803 drawTracking( LLAvatarTracker::instance().getGlobalPos(), gTrackColor, TRUE, LLTracker::getLabel(), "" );
804 }
805 else if ( LLTracker::TRACKING_LANDMARK == tracking_status
806 || LLTracker::TRACKING_LOCATION == tracking_status )
807 {
808 // While fetching landmarks, will have 0,0,0 location for a while,
809 // so don't draw. JC
810 LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
811 if (!pos_global.isExactlyZero())
812 {
813 drawTracking( pos_global, gTrackColor, TRUE, LLTracker::getLabel(), LLTracker::getToolTip() );
814 }
815 }
816 else if (gWorldMap->mIsTrackingUnknownLocation)
817 {
818 if (gWorldMap->mInvalidLocation)
819 {
820 // We know this location to be invalid
821 LLColor4 loading_color(0.0, 0.5, 1.0, 1.0);
822 drawTracking( gWorldMap->mUnknownLocation, loading_color, TRUE, "Invalid Location", "");
823 }
824 else
825 {
826 double value = fmod(current_time, 2);
827 value = 0.5 + 0.5*cos(value * 3.14159f);
828 LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
829 drawTracking( gWorldMap->mUnknownLocation, loading_color, TRUE, "Loading...", "");
830 }
831 }
832#endif
833
834 // turn off the scissor
835 LLGLDisable no_scissor(GL_SCISSOR_TEST);
836
837 updateDirections();
838
839 LLView::draw();
840
841 updateVisibleBlocks();
842}
843
844void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items, LLPointer<LLViewerImage> image)
845{
846 LLWorldMap::item_info_list_t::const_iterator e;
847 for (e = items.begin(); e != items.end(); ++e)
848 {
849 const LLItemInfo& info = *e;
850
851 drawGenericItem(info, image);
852 }
853}
854
855void LLWorldMapView::drawGenericItem(const LLItemInfo& item, LLPointer<LLViewerImage> image)
856{
857 S32 half_width = image->getWidth()/2;
858 S32 half_height = image->getHeight()/2;
859
860 LLVector3 pos_map = globalPosToView( item.mPosGlobal );
861 gl_draw_image(llround(pos_map.mV[VX]) - half_width,
862 llround(pos_map.mV[VY]) - half_height,
863 image,
864 LLColor4::white);
865}
866
867void LLWorldMapView::drawAgents()
868{
869 //S32 half_width = sPopularImage->getWidth()/2;
870 //S32 half_height = sPopularImage->getHeight()/2;
871
872 F32 agents_scale = (gMapScale * 0.9f) / 256.f;
873
874 for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
875 {
876 U64 handle = *iter;
877 LLSimInfo* siminfo = gWorldMap->simInfoFromHandle(handle);
878 if (siminfo && (siminfo->mAccess == SIM_ACCESS_DOWN))
879 {
880 continue;
881 }
882 LLWorldMap::agent_list_map_t::iterator countsiter = gWorldMap->mAgentLocationsMap.find(handle);
883 if (siminfo && siminfo->mShowAgentLocations && countsiter != gWorldMap->mAgentLocationsMap.end())
884 {
885 // Show Individual agents
886 LLWorldMap::item_info_list_t& agentcounts = countsiter->second;
887 S32 sim_agent_count = 0;
888 for (LLWorldMap::item_info_list_t::iterator iter = agentcounts.begin();
889 iter != agentcounts.end(); ++iter)
890 {
891 const LLItemInfo& info = *iter;
892 LLVector3 pos_map = globalPosToView( info.mPosGlobal );
893 S32 agent_count = info.mExtra;
894 if (agent_count > 0)
895 {
896 sim_agent_count += agent_count;
897 F32 y = 0;
898 for (S32 cur_agent = 0; cur_agent < agent_count; cur_agent++)
899 {
900 gl_draw_image(llround(pos_map.mV[VX]) - 4,
901 llround(pos_map.mV[VY] + y) - 4,
902 sAvatarSmallImage,
903 LLColor4::white );
904 // move up a bit
905 y += 3.f;
906 }
907 }
908 }
909 gWorldMap->mNumAgents[handle] = sim_agent_count; // override mNumAgents for this sim
910 }
911 else
912 {
913 // Show agent 'stack' at center of sim
914 S32 num_agents = gWorldMap->mNumAgents[handle];
915 if (num_agents > 0)
916 {
917 LLVector3d region_pos = from_region_handle(handle);
918 region_pos[VX] += REGION_WIDTH_METERS * .5f;
919 region_pos[VY] += REGION_WIDTH_METERS * .5f;
920 LLVector3 pos_map = globalPosToView(region_pos);
921 // Reduce the stack size as you zoom out - always display at lease one agent where there is one or more
922 S32 agent_count = (S32)(((num_agents-1) * agents_scale + (num_agents-1) * 0.1f)+.1f) + 1;
923 S32 y = 0;
924 S32 cur_agent;
925 for (cur_agent = 0; cur_agent < agent_count; cur_agent++)
926 {
927 gl_draw_image(
928 llround(pos_map.mV[VX]) - 4,
929 llround(pos_map.mV[VY]) + y - 4,
930 sAvatarSmallImage,
931 LLColor4::white );
932 // move up a bit
933 y += 3;
934 }
935 }
936 }
937 }
938}
939
940
941void LLWorldMapView::drawEvents()
942{
943 BOOL show_mature = gSavedSettings.getBOOL("ShowMatureEvents");
944
945 // Non-selected events
946 // Draw under avatar so you can find yourself.
947 LLWorldMap::item_info_list_t::const_iterator e;
948 for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e)
949 {
950 const LLItemInfo& event = *e;
951
952 // Draw, but without relative-Z icons
953 if (!event.mSelected)
954 {
955 LLVector3 pos_map = globalPosToView( event.mPosGlobal );
956 gl_draw_image(llround(pos_map.mV[VX]) - sEventImage->getWidth()/2,
957 llround(pos_map.mV[VY]) - sEventImage->getHeight()/2,
958 sEventImage,
959 LLColor4::white);
960 }
961 }
962 if (show_mature)
963 {
964 for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e)
965 {
966 const LLItemInfo& event = *e;
967
968 // Draw, but without relative-Z icons
969 if (!event.mSelected)
970 {
971 LLVector3 pos_map = globalPosToView( event.mPosGlobal );
972 gl_draw_image(llround(pos_map.mV[VX]) - sEventMatureImage->getWidth()/2,
973 llround(pos_map.mV[VY]) - sEventMatureImage->getHeight()/2,
974 sEventMatureImage,
975 LLColor4::white);
976 }
977 }
978 }
979
980 // Selected events
981 // Draw under avatar so you can find yourself.
982 for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e)
983 {
984 const LLItemInfo& event = *e;
985
986 // Draw, but without relative-Z icons
987 if (event.mSelected)
988 {
989 LLVector3 pos_map = globalPosToView( event.mPosGlobal );
990 gl_draw_image(llround(pos_map.mV[VX]) - sEventImage->getWidth()/2,
991 llround(pos_map.mV[VY]) - sEventImage->getHeight()/2,
992 sEventImage,
993 LLColor4::white);
994
995 //drawIconName(
996 // pos_map.mV[VX],
997 // pos_map.mV[VY],
998 // gEventColor,
999 // event.mToolTip.c_str(),
1000 // event.mName.c_str() );
1001 }
1002 }
1003 if (show_mature)
1004 {
1005 for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e)
1006 {
1007 const LLItemInfo& event = *e;
1008
1009 // Draw, but without relative-Z icons
1010 if (event.mSelected)
1011 {
1012 LLVector3 pos_map = globalPosToView( event.mPosGlobal );
1013 gl_draw_image(llround(pos_map.mV[VX]) - sEventMatureImage->getWidth()/2,
1014 llround(pos_map.mV[VY]) - sEventMatureImage->getHeight()/2,
1015 sEventMatureImage,
1016 LLColor4::white);
1017
1018 //drawIconName(
1019 // pos_map.mV[VX],
1020 // pos_map.mV[VY],
1021 // gEventColor,
1022 // event.mToolTip.c_str(),
1023 // event.mName.c_str() );
1024 }
1025 }
1026 }
1027}
1028
1029void LLWorldMapView::drawDots()
1030{
1031
1032}
1033
1034
1035void LLWorldMapView::drawFrustum()
1036{
1037 // Draw frustum
1038 F32 meters_to_pixels = gMapScale/ REGION_WIDTH_METERS;
1039
1040 F32 horiz_fov = gCamera->getView() * gCamera->getAspect();
1041 F32 far_clip_meters = gCamera->getFar();
1042 F32 far_clip_pixels = far_clip_meters * meters_to_pixels;
1043
1044 F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 );
1045 F32 half_width_pixels = half_width_meters * meters_to_pixels;
1046
1047 F32 ctr_x = mRect.getWidth() * 0.5f + sPanX;
1048 F32 ctr_y = mRect.getHeight() * 0.5f + sPanY;
1049
1050 LLGLSNoTexture gls_no_texture;
1051
1052 // Since we don't rotate the map, we have to rotate the frustum.
1053 glPushMatrix();
1054 glTranslatef( ctr_x, ctr_y, 0 );
1055 glRotatef( atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
1056
1057 // Draw triangle with more alpha in far pixels to make it
1058 // fade out in distance.
1059 glBegin( GL_TRIANGLES );
1060 glColor4f(1.f, 1.f, 1.f, 0.25f);
1061 glVertex2f( 0, 0 );
1062
1063 glColor4f(1.f, 1.f, 1.f, 0.02f);
1064 glVertex2f( -half_width_pixels, far_clip_pixels );
1065
1066 glColor4f(1.f, 1.f, 1.f, 0.02f);
1067 glVertex2f( half_width_pixels, far_clip_pixels );
1068 glEnd();
1069 glPopMatrix();
1070}
1071
1072
1073LLVector3 LLWorldMapView::globalPosToView( const LLVector3d& global_pos )
1074{
1075 LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal();
1076 LLVector3 pos_local;
1077 pos_local.setVec(relative_pos_global); // convert to floats from doubles
1078
1079 pos_local.mV[VX] *= sPixelsPerMeter;
1080 pos_local.mV[VY] *= sPixelsPerMeter;
1081 // leave Z component in meters
1082
1083
1084 pos_local.mV[VX] += mRect.getWidth() / 2 + sPanX;
1085 pos_local.mV[VY] += mRect.getHeight() / 2 + sPanY;
1086
1087 return pos_local;
1088}
1089
1090
1091void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& color,
1092 BOOL draw_arrow, LLString label, LLString tooltip, S32 vert_offset )
1093{
1094 LLVector3 pos_local = globalPosToView( pos_global );
1095 S32 x = llround( pos_local.mV[VX] );
1096 S32 y = llround( pos_local.mV[VY] );
1097 LLFontGL* font = LLFontGL::sSansSerifSmall;
1098 S32 text_x = x;
1099 S32 text_y = (S32)(y - sTrackCircleImage->getHeight()/2 - font->getLineHeight());
1100
1101 BOOL is_in_window = true;
1102
1103 if( x < 0
1104 || y < 0
1105 || x >= mRect.getWidth()
1106 || y >= mRect.getHeight() )
1107 {
1108 if (draw_arrow)
1109 {
1110 drawTrackingCircle( mRect, x, y, color, 3, 15 );
1111 drawTrackingArrow( mRect, x, y, color );
1112 text_x = sTrackingArrowX;
1113 text_y = sTrackingArrowY;
1114 }
1115 is_in_window = false;
1116 }
1117 else if (LLTracker::getTrackingStatus() == LLTracker::TRACKING_LOCATION &&
1118 LLTracker::getTrackedLocationType() != LLTracker::LOCATION_NOTHING)
1119 {
1120 drawTrackingCircle( mRect, x, y, color, 3, 15 );
1121 }
1122 else
1123 {
1124 // Draw, but without relative Z
1125 gl_draw_image(x - sTrackCircleImage->getWidth()/2,
1126 y - sTrackCircleImage->getHeight()/2,
1127 sTrackCircleImage,
1128 color);
1129 }
1130
1131 // clamp text position to on-screen
1132 const S32 TEXT_PADDING = DEFAULT_TRACKING_ARROW_SIZE + 2;
1133 S32 half_text_width = llfloor(font->getWidthF32(label) * 0.5f);
1134 text_x = llclamp(text_x, half_text_width + TEXT_PADDING, mRect.getWidth() - half_text_width - TEXT_PADDING);
1135 text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, mRect.getHeight() - llround(font->getLineHeight()) - TEXT_PADDING - vert_offset);
1136
1137 if (label != "")
1138 {
1139 font->renderUTF8(
1140 label, 0,
1141 text_x,
1142 text_y,
1143 LLColor4::white, LLFontGL::HCENTER,
1144 LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
1145
1146 if (tooltip != "")
1147 {
1148 text_y -= (S32)font->getLineHeight();
1149
1150 font->renderUTF8(
1151 tooltip, 0,
1152 text_x,
1153 text_y,
1154 LLColor4::white, LLFontGL::HCENTER,
1155 LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
1156 }
1157 }
1158}
1159
1160// If you change this, then you need to change LLTracker::getTrackedPositionGlobal() as well
1161LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
1162{
1163 x -= llfloor((mRect.getWidth() / 2 + sPanX));
1164 y -= llfloor((mRect.getHeight() / 2 + sPanY));
1165
1166 LLVector3 pos_local( (F32)x, (F32)y, 0.f );
1167
1168 pos_local *= ( REGION_WIDTH_METERS / gMapScale );
1169
1170 LLVector3d pos_global;
1171 pos_global.setVec( pos_local );
1172 pos_global += gAgent.getCameraPositionGlobal();
1173 if(gAgent.isGodlike())
1174 {
1175 pos_global.mdV[VZ] = GODLY_TELEPORT_HEIGHT; // Godly height should always be 200.
1176 }
1177 else
1178 {
1179 pos_global.mdV[VZ] = gAgent.getPositionAgent().mV[VZ]; // Want agent's height, not camera's
1180 }
1181
1182 return pos_global;
1183}
1184
1185
1186BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen )
1187{
1188 if( !getVisible() || !pointInView( x, y ) )
1189 {
1190 return FALSE;
1191 }
1192
1193 LLVector3d pos_global = viewPosToGlobal(x, y);
1194
1195 LLSimInfo* info = gWorldMap->simInfoFromPosGlobal(pos_global);
1196 if (info)
1197 {
1198 LLViewerRegion *region = gAgent.getRegion();
1199
1200 std::string message =
1201 llformat("%s (%s)",
1202 info->mName.c_str(),
1203 LLViewerRegion::accessToString(info->mAccess));
1204
1205 if (info->mAccess != SIM_ACCESS_DOWN)
1206 {
1207 S32 agent_count = gWorldMap->mNumAgents[info->mHandle];
1208 if (region && region->getHandle() == info->mHandle)
1209 {
1210 ++agent_count; // Bump by 1 if we're here
1211 }
1212
1213 // We may not have an agent count when the map is really
1214 // zoomed out, so don't display anything about the count. JC
1215 if (agent_count > 0)
1216 {
1217 message += llformat("\n%d ", agent_count);
1218
1219 if (agent_count == 1)
1220 {
1221 message += "person";
1222 }
1223 else
1224 {
1225 message += "people";
1226 }
1227 }
1228 }
1229 msg.assign( message );
1230
1231 // Optionally show region flags
1232 std::string region_flags = LLViewerRegion::regionFlagsToString(info->mRegionFlags);
1233
1234 if (!region_flags.empty())
1235 {
1236 msg += '\n';
1237 msg += region_flags;
1238 }
1239
1240 S32 SLOP = 4;
1241 localPointToScreen(
1242 x - SLOP, y - SLOP,
1243 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
1244 sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
1245 sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
1246 }
1247 return TRUE;
1248}
1249
1250// Pass relative Z of 0 to draw at same level.
1251// static
1252void LLWorldMapView::drawAvatar(F32 x_pixels,
1253 F32 y_pixels,
1254 const LLColor4& color,
1255 F32 relative_z,
1256 F32 dot_radius)
1257{
1258 F32 left = x_pixels - dot_radius;
1259 F32 right = x_pixels + dot_radius;
1260 F32 center = (left + right) * 0.5f;
1261 F32 top = y_pixels + dot_radius;
1262 F32 bottom = y_pixels - dot_radius;
1263
1264 const F32 HEIGHT_THRESHOLD = 7.f;
1265
1266 if (relative_z > HEIGHT_THRESHOLD)
1267 {
1268 LLGLSNoTexture gls_no_texture;
1269 glColor4fv( color.mV );
1270 LLUI::setLineWidth(1.5f);
1271 glBegin( GL_LINES );
1272 glVertex2f(left, top);
1273 glVertex2f(right, top);
1274 glVertex2f(center, top);
1275 glVertex2f(center, bottom);
1276 glEnd();
1277 LLUI::setLineWidth(1.0f);
1278 }
1279 else if (relative_z > -HEIGHT_THRESHOLD)
1280 {
1281 gl_draw_image( llround(x_pixels) - sAvatarSmallImage->getWidth()/2,
1282 llround(y_pixels) - sAvatarSmallImage->getHeight()/2,
1283 sAvatarSmallImage,
1284 color);
1285 }
1286 else
1287 {
1288 LLGLSNoTexture gls_no_texture;
1289 glColor4fv( color.mV );
1290 LLUI::setLineWidth(1.5f);
1291 glBegin( GL_LINES );
1292 glVertex2f(center, top);
1293 glVertex2f(center, bottom);
1294 glVertex2f(left, bottom);
1295 glVertex2f(right, bottom);
1296 glEnd();
1297 LLUI::setLineWidth(1.0f);
1298 }
1299}
1300
1301// Pass relative Z of 0 to draw at same level.
1302// static
1303void LLWorldMapView::drawTrackingDot( F32 x_pixels,
1304 F32 y_pixels,
1305 const LLColor4& color,
1306 F32 relative_z,
1307 F32 dot_radius)
1308{
1309 F32 left = x_pixels - dot_radius;
1310 F32 right = x_pixels + dot_radius;
1311 F32 center = (left + right) * 0.5f;
1312 F32 top = y_pixels + dot_radius;
1313 F32 bottom = y_pixels - dot_radius;
1314
1315 const F32 HEIGHT_THRESHOLD = 7.f;
1316
1317 if (relative_z > HEIGHT_THRESHOLD)
1318 {
1319 LLGLSNoTexture gls_no_texture;
1320 glColor4fv( color.mV );
1321 LLUI::setLineWidth(1.5f);
1322 glBegin( GL_LINES );
1323 glVertex2f(left, top);
1324 glVertex2f(right, top);
1325 glVertex2f(center, top);
1326 glVertex2f(center, bottom);
1327 glEnd();
1328 LLUI::setLineWidth(1.0f);
1329 }
1330 else if (relative_z > -HEIGHT_THRESHOLD)
1331 {
1332 gl_draw_image( llround(x_pixels) - sAvatarSmallImage->getWidth()/2,
1333 llround(y_pixels) - sAvatarSmallImage->getHeight()/2,
1334 sTrackCircleImage,
1335 color);
1336 }
1337 else
1338 {
1339 LLGLSNoTexture gls_no_texture;
1340 glColor4fv( color.mV );
1341 LLUI::setLineWidth(1.5f);
1342 glBegin( GL_LINES );
1343 glVertex2f(center, top);
1344 glVertex2f(center, bottom);
1345 glVertex2f(left, bottom);
1346 glVertex2f(right, bottom);
1347 glEnd();
1348 LLUI::setLineWidth(1.0f);
1349 }
1350}
1351
1352
1353// Pass relative Z of 0 to draw at same level.
1354// static
1355void LLWorldMapView::drawIconName(F32 x_pixels,
1356 F32 y_pixels,
1357 const LLColor4& color,
1358 const std::string& first_line,
1359 const std::string& second_line)
1360{
1361 const S32 VERT_PAD = 8;
1362 S32 text_x = llround(x_pixels);
1363 S32 text_y = llround(y_pixels
1364 - BIG_DOT_RADIUS
1365 - VERT_PAD);
1366
1367 // render text
1368 LLFontGL::sSansSerif->renderUTF8(first_line, 0,
1369 text_x,
1370 text_y,
1371 color,
1372 LLFontGL::HCENTER,
1373 LLFontGL::TOP,
1374 LLFontGL::DROP_SHADOW);
1375
1376 text_y -= llround(LLFontGL::sSansSerif->getLineHeight());
1377
1378 // render text
1379 LLFontGL::sSansSerif->renderUTF8(second_line, 0,
1380 text_x,
1381 text_y,
1382 color,
1383 LLFontGL::HCENTER,
1384 LLFontGL::TOP,
1385 LLFontGL::DROP_SHADOW);
1386}
1387
1388
1389//static
1390void LLWorldMapView::drawTrackingCircle( const LLRect& rect, S32 x, S32 y, const LLColor4& color, S32 min_thickness, S32 overlap )
1391{
1392 F32 start_theta = 0.f;
1393 F32 end_theta = F_TWO_PI;
1394 F32 x_delta = 0.f;
1395 F32 y_delta = 0.f;
1396
1397 if (x < 0)
1398 {
1399 x_delta = 0.f - (F32)x;
1400 start_theta = F_PI + F_PI_BY_TWO;
1401 end_theta = F_TWO_PI + F_PI_BY_TWO;
1402 }
1403 else if (x > rect.getWidth())
1404 {
1405 x_delta = (F32)(x - rect.getWidth());
1406 start_theta = F_PI_BY_TWO;
1407 end_theta = F_PI + F_PI_BY_TWO;
1408 }
1409
1410 if (y < 0)
1411 {
1412 y_delta = 0.f - (F32)y;
1413 if (x < 0)
1414 {
1415 start_theta = 0.f;
1416 end_theta = F_PI_BY_TWO;
1417 }
1418 else if (x > rect.getWidth())
1419 {
1420 start_theta = F_PI_BY_TWO;
1421 end_theta = F_PI;
1422 }
1423 else
1424 {
1425 start_theta = 0.f;
1426 end_theta = F_PI;
1427 }
1428 }
1429 else if (y > rect.getHeight())
1430 {
1431 y_delta = (F32)(y - rect.getHeight());
1432 if (x < 0)
1433 {
1434 start_theta = F_PI + F_PI_BY_TWO;
1435 end_theta = F_TWO_PI;
1436 }
1437 else if (x > rect.getWidth())
1438 {
1439 start_theta = F_PI;
1440 end_theta = F_PI + F_PI_BY_TWO;
1441 }
1442 else
1443 {
1444 start_theta = F_PI;
1445 end_theta = F_TWO_PI;
1446 }
1447 }
1448
1449 F32 distance = sqrtf(x_delta * x_delta + y_delta * y_delta);
1450
1451 distance = llmax(0.1f, distance);
1452
1453 F32 outer_radius = distance + (1.f + (9.f * sqrtf(x_delta * y_delta) / distance)) * (F32)overlap;
1454 F32 inner_radius = outer_radius - (F32)min_thickness;
1455
1456 F32 angle_adjust_x = asin(x_delta / outer_radius);
1457 F32 angle_adjust_y = asin(y_delta / outer_radius);
1458
1459 if (angle_adjust_x)
1460 {
1461 if (angle_adjust_y)
1462 {
1463 F32 angle_adjust = llmin(angle_adjust_x, angle_adjust_y);
1464 start_theta += angle_adjust;
1465 end_theta -= angle_adjust;
1466 }
1467 else
1468 {
1469 start_theta += angle_adjust_x;
1470 end_theta -= angle_adjust_x;
1471 }
1472 }
1473 else if (angle_adjust_y)
1474 {
1475 start_theta += angle_adjust_y;
1476 end_theta -= angle_adjust_y;
1477 }
1478
1479 glMatrixMode(GL_MODELVIEW);
1480 glPushMatrix();
1481 glTranslatef((F32)x, (F32)y, 0.f);
1482 gl_washer_segment_2d(inner_radius, outer_radius, start_theta, end_theta, 40, color, color);
1483 glPopMatrix();
1484
1485}
1486
1487// static
1488void LLWorldMapView::drawTrackingArrow(const LLRect& rect, S32 x, S32 y,
1489 const LLColor4& color,
1490 S32 arrow_size)
1491{
1492 F32 x_center = (F32)rect.getWidth() / 2.f;
1493 F32 y_center = (F32)rect.getHeight() / 2.f;
1494
1495 F32 x_clamped = (F32)llclamp( x, 0, rect.getWidth() - arrow_size );
1496 F32 y_clamped = (F32)llclamp( y, 0, rect.getHeight() - arrow_size );
1497
1498 F32 slope = (F32)(y - y_center) / (F32)(x - x_center);
1499 F32 window_ratio = (F32)rect.getHeight() / (F32)rect.getWidth();
1500
1501 if (llabs(slope) > window_ratio && y_clamped != (F32)y)
1502 {
1503 // clamp by y
1504 x_clamped = (y_clamped - y_center) / slope + x_center;
1505 // adjust for arrow size
1506 x_clamped = llclamp(x_clamped , 0.f, (F32)(rect.getWidth() - arrow_size) );
1507 }
1508 else if (x_clamped != (F32)x)
1509 {
1510 // clamp by x
1511 y_clamped = (x_clamped - x_center) * slope + y_center;
1512 // adjust for arrow size
1513 y_clamped = llclamp( y_clamped, 0.f, (F32)(rect.getHeight() - arrow_size) );
1514 }
1515
1516 // *FIX: deal with non-square window properly.
1517 // I do not understand what this comment means -- is it actually
1518 // broken or is it correctly dealing with non-square
1519 // windows. Phoenix 2007-01-03.
1520 S32 half_arrow_size = (S32) (0.5f * arrow_size);
1521
1522 F32 angle = atan2( y + half_arrow_size - y_center, x + half_arrow_size - x_center);
1523
1524 sTrackingArrowX = llfloor(x_clamped);
1525 sTrackingArrowY = llfloor(y_clamped);
1526
1527 gl_draw_scaled_rotated_image(
1528 sTrackingArrowX,
1529 sTrackingArrowY,
1530 arrow_size, arrow_size,
1531 RAD_TO_DEG * angle,
1532 sTrackArrowImage,
1533 color);
1534}
1535
1536void LLWorldMapView::setDirectionPos( LLTextBox* text_box, F32 rotation )
1537{
1538 // Rotation is in radians.
1539 // Rotation of 0 means x = 1, y = 0 on the unit circle.
1540
1541
1542 F32 map_half_height = mRect.getHeight() * 0.5f;
1543 F32 map_half_width = mRect.getWidth() * 0.5f;
1544 F32 text_half_height = text_box->getRect().getHeight() * 0.5f;
1545 F32 text_half_width = text_box->getRect().getWidth() * 0.5f;
1546 F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width );
1547
1548 text_box->setOrigin(
1549 llround(map_half_width - text_half_width + radius * cos( rotation )),
1550 llround(map_half_height - text_half_height + radius * sin( rotation )) );
1551}
1552
1553
1554void LLWorldMapView::updateDirections()
1555{
1556 S32 width = mRect.getWidth();
1557 S32 height = mRect.getHeight();
1558
1559 S32 text_height = mTextBoxNorth->getRect().getHeight();
1560 S32 text_width = mTextBoxNorth->getRect().getWidth();
1561
1562 const S32 PAD = 2;
1563 S32 top = height - text_height - PAD;
1564 S32 left = PAD*2;
1565 S32 bottom = PAD;
1566 S32 right = width - text_width - PAD;
1567 S32 center_x = width/2 - text_width/2;
1568 S32 center_y = height/2 - text_height/2;
1569
1570 mTextBoxNorth->setOrigin( center_x, top );
1571 mTextBoxEast->setOrigin( right, center_y );
1572 mTextBoxSouth->setOrigin( center_x, bottom );
1573 mTextBoxWest->setOrigin( left, center_y );
1574
1575 // These have wider text boxes
1576 text_width = mTextBoxNorthWest->getRect().getWidth();
1577 right = width - text_width - PAD;
1578
1579 mTextBoxNorthWest->setOrigin(left, top);
1580 mTextBoxNorthEast->setOrigin(right, top);
1581 mTextBoxSouthWest->setOrigin(left, bottom);
1582 mTextBoxSouthEast->setOrigin(right, bottom);
1583
1584// S32 hint_width = mTextBoxScrollHint->getRect().getWidth();
1585// mTextBoxScrollHint->setOrigin( width - hint_width - text_width - 2 * PAD,
1586// PAD * 2 + text_height );
1587}
1588
1589
1590void LLWorldMapView::reshape( S32 width, S32 height, BOOL called_from_parent )
1591{
1592 LLView::reshape( width, height, called_from_parent );
1593}
1594
1595bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track)
1596{
1597 LLVector3 pos_view = globalPosToView(item.mPosGlobal);
1598 S32 item_x = llround(pos_view.mV[VX]);
1599 S32 item_y = llround(pos_view.mV[VY]);
1600
1601 if (x < item_x - BIG_DOT_RADIUS) return false;
1602 if (x > item_x + BIG_DOT_RADIUS) return false;
1603 if (y < item_y - BIG_DOT_RADIUS) return false;
1604 if (y > item_y + BIG_DOT_RADIUS) return false;
1605
1606 LLSimInfo* sim_info = gWorldMap->simInfoFromHandle(item.mRegionHandle);
1607 if (sim_info)
1608 {
1609 if (track)
1610 {
1611 gFloaterWorldMap->trackLocation(item.mPosGlobal);
1612 }
1613 }
1614
1615 if (track)
1616 {
1617 gFloaterWorldMap->trackGenericItem(item);
1618 }
1619
1620 item.mSelected = TRUE;
1621 *id = item.mID;
1622
1623 return true;
1624}
1625
1626// Handle a click, which might be on a dot
1627void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask,
1628 S32* hit_type,
1629 LLUUID* id)
1630{
1631 LLVector3d pos_global = viewPosToGlobal(x, y);
1632
1633 // *HACK: Adjust Z values automatically for liaisons & gods so
1634 // we swoop down when they click on the map. Sadly, the P2P
1635 // branch does not pay attention to this value; however, the
1636 // Distributed Messaging branch honors kt.
1637 if(gAgent.isGodlike())
1638 {
1639 pos_global.mdV[VZ] = 200.0;
1640 }
1641
1642 *hit_type = 0; // hit nothing
1643
1644 gWorldMap->mIsTrackingUnknownLocation = FALSE;
1645 gWorldMap->mIsTrackingDoubleClick = FALSE;
1646 gWorldMap->mIsTrackingCommit = FALSE;
1647
1648 LLWorldMap::item_info_list_t::iterator it;
1649
1650 // clear old selected stuff
1651 for (it = gWorldMap->mPGEvents.begin(); it != gWorldMap->mPGEvents.end(); ++it)
1652 {
1653 (*it).mSelected = FALSE;
1654 }
1655 for (it = gWorldMap->mMatureEvents.begin(); it != gWorldMap->mMatureEvents.end(); ++it)
1656 {
1657 (*it).mSelected = FALSE;
1658 }
1659 for (it = gWorldMap->mPopular.begin(); it != gWorldMap->mPopular.end(); ++it)
1660 {
1661 (*it).mSelected = FALSE;
1662 }
1663 for (it = gWorldMap->mLandForSale.begin(); it != gWorldMap->mLandForSale.end(); ++it)
1664 {
1665 (*it).mSelected = FALSE;
1666 }
1667 for (it = gWorldMap->mClassifieds.begin(); it != gWorldMap->mClassifieds.end(); ++it)
1668 {
1669 (*it).mSelected = FALSE;
1670 }
1671
1672 // Select event you clicked on
1673 if (gSavedSettings.getBOOL("MapShowEvents"))
1674 {
1675 for (it = gWorldMap->mPGEvents.begin(); it != gWorldMap->mPGEvents.end(); ++it)
1676 {
1677 LLItemInfo& event = *it;
1678
1679 if (checkItemHit(x, y, event, id, false))
1680 {
1681 *hit_type = MAP_ITEM_PG_EVENT;
1682 mItemPicked = TRUE;
1683 gFloaterWorldMap->trackEvent(event);
1684 return;
1685 }
1686 }
1687 if (gSavedSettings.getBOOL("ShowMatureEvents"))
1688 {
1689 for (it = gWorldMap->mMatureEvents.begin(); it != gWorldMap->mMatureEvents.end(); ++it)
1690 {
1691 LLItemInfo& event = *it;
1692
1693 if (checkItemHit(x, y, event, id, false))
1694 {
1695 *hit_type = MAP_ITEM_MATURE_EVENT;
1696 mItemPicked = TRUE;
1697 gFloaterWorldMap->trackEvent(event);
1698 return;
1699 }
1700 }
1701 }
1702 }
1703
1704 if (gSavedSettings.getBOOL("MapShowPopular"))
1705 {
1706 for (it = gWorldMap->mPopular.begin(); it != gWorldMap->mPopular.end(); ++it)
1707 {
1708 LLItemInfo& popular = *it;
1709
1710 if (checkItemHit(x, y, popular, id, true))
1711 {
1712 *hit_type = MAP_ITEM_POPULAR;
1713 mItemPicked = TRUE;
1714 return;
1715 }
1716 }
1717 }
1718
1719 if (gSavedSettings.getBOOL("MapShowLandForSale"))
1720 {
1721 for (it = gWorldMap->mLandForSale.begin(); it != gWorldMap->mLandForSale.end(); ++it)
1722 {
1723 LLItemInfo& land = *it;
1724
1725 if (checkItemHit(x, y, land, id, true))
1726 {
1727 *hit_type = MAP_ITEM_LAND_FOR_SALE;
1728 mItemPicked = TRUE;
1729 return;
1730 }
1731 }
1732 }
1733
1734 if (gSavedSettings.getBOOL("MapShowClassifieds"))
1735 {
1736 for (it = gWorldMap->mClassifieds.begin(); it != gWorldMap->mClassifieds.end(); ++it)
1737 {
1738 LLItemInfo& classified = *it;
1739
1740 if (checkItemHit(x, y, classified, id, true))
1741 {
1742 *hit_type = MAP_ITEM_CLASSIFIED;
1743 mItemPicked = TRUE;
1744 return;
1745 }
1746 }
1747 }
1748
1749 // If we get here, we haven't clicked on an icon
1750
1751 gFloaterWorldMap->trackLocation(pos_global);
1752 mItemPicked = FALSE;
1753
1754 *id = LLUUID::null;
1755 return;
1756}
1757
1758
1759BOOL outside_slop(S32 x, S32 y, S32 start_x, S32 start_y)
1760{
1761 S32 dx = x - start_x;
1762 S32 dy = y - start_y;
1763
1764 return (dx <= -2 || 2 <= dx || dy <= -2 || 2 <= dy);
1765}
1766
1767BOOL LLWorldMapView::handleMouseDown( S32 x, S32 y, MASK mask )
1768{
1769 gFocusMgr.setMouseCapture( this, NULL );
1770
1771 mMouseDownPanX = llround(sPanX);
1772 mMouseDownPanY = llround(sPanY);
1773 mMouseDownX = x;
1774 mMouseDownY = y;
1775 sHandledLastClick = TRUE;
1776 return TRUE;
1777}
1778
1779BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask )
1780{
1781 if (this == gFocusMgr.getMouseCapture())
1782 {
1783 if (mPanning)
1784 {
1785 // restore mouse cursor
1786 S32 local_x, local_y;
1787 local_x = mMouseDownX + llfloor(sPanX - mMouseDownPanX);
1788 local_y = mMouseDownY + llfloor(sPanY - mMouseDownPanY);
1789 LLRect clip_rect = mRect;
1790 clip_rect.stretch(-8);
1791 clip_rect.clipPointToRect(mMouseDownX, mMouseDownY, local_x, local_y);
1792 LLUI::setCursorPositionLocal(this, local_x, local_y);
1793
1794 // finish the pan
1795 mPanning = FALSE;
1796
1797 mMouseDownX = 0;
1798 mMouseDownY = 0;
1799 }
1800 else
1801 {
1802 // ignore whether we hit an event or not
1803 S32 hit_type;
1804 LLUUID id;
1805 handleClick(x, y, mask, &hit_type, &id);
1806 }
1807 gViewerWindow->showCursor();
1808 gFocusMgr.setMouseCapture( NULL, NULL );
1809 return TRUE;
1810 }
1811 return FALSE;
1812}
1813
1814void LLWorldMapView::updateBlock(S32 block_x, S32 block_y)
1815{
1816 S32 offset = block_x | (block_y * MAP_BLOCK_RES);
1817 if (!gWorldMap->mMapBlockLoaded[gWorldMap->mCurrentMap][offset])
1818 {
1819// llinfos << "Loading Block (" << block_x << "," << block_y << ")" << llendl;
1820 gWorldMap->sendMapBlockRequest(block_x << 3, block_y << 3, (block_x << 3) + 7, (block_y << 3) + 7);
1821 gWorldMap->mMapBlockLoaded[gWorldMap->mCurrentMap][offset] = TRUE;
1822 }
1823}
1824
1825void LLWorldMapView::updateVisibleBlocks()
1826{
1827 if (gMapScale < SIM_MAP_SCALE)
1828 {
1829 // We don't care what is loaded if we're zoomed out
1830 return;
1831 }
1832 // check if we've loaded the 9 potentially visible zones
1833 LLVector3d camera_global = gAgent.getCameraPositionGlobal();
1834
1835 // Convert pan to sim coordinates
1836 S32 world_center_x = S32((-sPanX / gMapScale) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
1837 S32 world_center_y = S32((-sPanY / gMapScale) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
1838
1839 // Find the corresponding 8x8 block
1840 S32 world_block_x = world_center_x >> 3;
1841 S32 world_block_y = world_center_y >> 3;
1842
1843 for (S32 block_x = llmax(world_block_x-1, 0); block_x <= llmin(world_block_x+1, MAP_BLOCK_RES-1); ++block_x)
1844 {
1845 for (S32 block_y = llmax(world_block_y-1, 0); block_y <= llmin(world_block_y+1, MAP_BLOCK_RES-1); ++block_y)
1846 {
1847 updateBlock(block_x, block_y);
1848 }
1849 }
1850}
1851
1852BOOL LLWorldMapView::handleHover( S32 x, S32 y, MASK mask )
1853{
1854 if (this == gFocusMgr.getMouseCapture())
1855 {
1856 if (mPanning || outside_slop(x, y, mMouseDownX, mMouseDownY))
1857 {
1858 // just started panning, so hide cursor
1859 if (!mPanning)
1860 {
1861 mPanning = TRUE;
1862 gViewerWindow->hideCursor();
1863 }
1864
1865 F32 delta_x = (F32)(gViewerWindow->getCurrentMouseDX());
1866 F32 delta_y = (F32)(gViewerWindow->getCurrentMouseDY());
1867
1868 // Set pan to value at start of drag + offset
1869 sPanX += delta_x;
1870 sPanY += delta_y;
1871 sTargetPanX = sPanX;
1872 sTargetPanY = sPanY;
1873
1874 gViewerWindow->moveCursorToCenter();
1875 }
1876
1877 // doesn't matter, cursor should be hidden
1878 gViewerWindow->setCursor(UI_CURSOR_CROSS );
1879 return TRUE;
1880 }
1881 else
1882 {
1883 // While we're waiting for data from the tracker, we're busy. JC
1884 LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
1885 if (LLTracker::isTracking(NULL)
1886 && pos_global.isExactlyZero())
1887 {
1888 gViewerWindow->setCursor( UI_CURSOR_WAIT );
1889 }
1890 else
1891 {
1892 gViewerWindow->setCursor( UI_CURSOR_CROSS );
1893 }
1894 lldebugst(LLERR_USER_INPUT) << "hover handled by LLWorldMapView" << llendl;
1895 return TRUE;
1896 }
1897}
1898
1899
1900BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask )
1901{
1902 if( sHandledLastClick )
1903 {
1904 S32 hit_type;
1905 LLUUID id;
1906 handleClick(x, y, mask, &hit_type, &id);
1907
1908 switch (hit_type)
1909 {
1910 case MAP_ITEM_PG_EVENT:
1911 case MAP_ITEM_MATURE_EVENT:
1912 {
1913 gFloaterWorldMap->close();
1914 // This is an ungainly hack
1915 char uuid_str[38];
1916 S32 event_id;
1917 id.toString(uuid_str);
1918 sscanf(&uuid_str[28], "%X", &event_id);
1919 LLFloaterDirectory::showEvents(event_id);
1920 break;
1921 }
1922 case MAP_ITEM_POPULAR:
1923 {
1924 gFloaterWorldMap->close();
1925 LLFloaterDirectory::showPopular(id);
1926 break;
1927 }
1928 case MAP_ITEM_LAND_FOR_SALE:
1929 {
1930 gFloaterWorldMap->close();
1931 LLFloaterDirectory::showLandForSale(id);
1932 break;
1933 }
1934 case MAP_ITEM_CLASSIFIED:
1935 {
1936 gFloaterWorldMap->close();
1937 LLFloaterDirectory::showClassified(id);
1938 break;
1939 }
1940 default:
1941 {
1942 if (gWorldMap->mIsTrackingUnknownLocation)
1943 {
1944 gWorldMap->mIsTrackingDoubleClick = TRUE;
1945 }
1946 else
1947 {
1948 // Teleport if we got a valid location
1949 LLVector3d pos_global = viewPosToGlobal(x,y);
1950 LLSimInfo* sim_info = gWorldMap->simInfoFromPosGlobal(pos_global);
1951 if (sim_info && sim_info->mAccess != SIM_ACCESS_DOWN)
1952 {
1953 gAgent.teleportViaLocation( pos_global );
1954 }
1955 }
1956 }
1957 };
1958
1959 return TRUE;
1960 }
1961 return FALSE;
1962}