00001
00032 #include "llviewerprecompiledheaders.h"
00033
00034 #include "llworldmapview.h"
00035
00036 #include "indra_constants.h"
00037 #include "llui.h"
00038 #include "linked_lists.h"
00039 #include "llmath.h"
00040 #include "llregionhandle.h"
00041 #include "lleventflags.h"
00042
00043 #include "llagent.h"
00044 #include "llcallingcard.h"
00045 #include "llcolorscheme.h"
00046 #include "llviewercontrol.h"
00047 #include "llcylinder.h"
00048 #include "llfloaterdirectory.h"
00049 #include "llfloatermap.h"
00050 #include "llfloaterworldmap.h"
00051 #include "llfocusmgr.h"
00052 #include "lltextbox.h"
00053 #include "lltextureview.h"
00054 #include "lltracker.h"
00055 #include "llviewercamera.h"
00056 #include "llviewerimage.h"
00057 #include "llviewerimagelist.h"
00058 #include "llviewermenu.h"
00059 #include "llviewerparceloverlay.h"
00060 #include "llviewerregion.h"
00061 #include "llviewerwindow.h"
00062 #include "llworld.h"
00063 #include "llworldmap.h"
00064 #include "viewer.h"
00065
00066 #include "llglheaders.h"
00067
00068 const F32 GODLY_TELEPORT_HEIGHT = 200.f;
00069 const S32 SCROLL_HINT_WIDTH = 65;
00070 const F32 BIG_DOT_RADIUS = 5.f;
00071 BOOL LLWorldMapView::sHandledLastClick = FALSE;
00072
00073 LLPointer<LLViewerImage> LLWorldMapView::sAvatarYouSmallImage = NULL;
00074 LLPointer<LLViewerImage> LLWorldMapView::sAvatarSmallImage = NULL;
00075 LLPointer<LLViewerImage> LLWorldMapView::sAvatarLargeImage = NULL;
00076 LLPointer<LLViewerImage> LLWorldMapView::sAvatarAboveImage = NULL;
00077 LLPointer<LLViewerImage> LLWorldMapView::sAvatarBelowImage = NULL;
00078
00079 LLPointer<LLViewerImage> LLWorldMapView::sTelehubImage = NULL;
00080 LLPointer<LLViewerImage> LLWorldMapView::sInfohubImage = NULL;
00081 LLPointer<LLViewerImage> LLWorldMapView::sHomeImage = NULL;
00082 LLPointer<LLViewerImage> LLWorldMapView::sEventImage = NULL;
00083 LLPointer<LLViewerImage> LLWorldMapView::sEventMatureImage = NULL;
00084
00085 LLPointer<LLViewerImage> LLWorldMapView::sTrackCircleImage = NULL;
00086 LLPointer<LLViewerImage> LLWorldMapView::sTrackArrowImage = NULL;
00087
00088 LLPointer<LLViewerImage> LLWorldMapView::sClassifiedsImage = NULL;
00089 LLPointer<LLViewerImage> LLWorldMapView::sPopularImage = NULL;
00090 LLPointer<LLViewerImage> LLWorldMapView::sForSaleImage = NULL;
00091
00092 F32 LLWorldMapView::sThresholdA = 48.f;
00093 F32 LLWorldMapView::sThresholdB = 96.f;
00094 F32 LLWorldMapView::sPanX = 0.f;
00095 F32 LLWorldMapView::sPanY = 0.f;
00096 F32 LLWorldMapView::sTargetPanX = 0.f;
00097 F32 LLWorldMapView::sTargetPanY = 0.f;
00098 S32 LLWorldMapView::sTrackingArrowX = 0;
00099 S32 LLWorldMapView::sTrackingArrowY = 0;
00100 F32 LLWorldMapView::sPixelsPerMeter = 1.f;
00101 F32 CONE_SIZE = 0.6f;
00102
00103 void LLWorldMapView::initClass()
00104 {
00105 LLUUID image_id;
00106
00107 image_id.set( gViewerArt.getString("map_avatar_you_8.tga") );
00108 sAvatarYouSmallImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
00109
00110 image_id.set( gViewerArt.getString("map_avatar_8.tga") );
00111 sAvatarSmallImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
00112
00113 image_id.set( gViewerArt.getString("map_avatar_16.tga") );
00114 sAvatarLargeImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
00115
00116 image_id.set( gViewerArt.getString("map_avatar_above_8.tga") );
00117 sAvatarAboveImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
00118
00119 image_id.set( gViewerArt.getString("map_avatar_below_8.tga") );
00120 sAvatarBelowImage = gImageList.getImage( image_id, MIPMAP_FALSE, TRUE);
00121
00122 image_id.set( gViewerArt.getString("map_home.tga") );
00123 sHomeImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00124
00125 image_id.set( gViewerArt.getString("map_telehub.tga") );
00126 sTelehubImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00127
00128 image_id.set( gViewerArt.getString("map_infohub.tga") );
00129 sInfohubImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00130
00131 image_id.set( gViewerArt.getString("map_event.tga") );
00132 sEventImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00133
00134 image_id.set( gViewerArt.getString("map_event_mature.tga") );
00135 sEventMatureImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00136
00137 image_id.set( gViewerArt.getString("map_track_16.tga") );
00138 sTrackCircleImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00139
00140 image_id.set( gViewerArt.getString("direction_arrow.tga") );
00141 sTrackArrowImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00142
00143 sTrackArrowImage->bindTexture(0);
00144 sTrackArrowImage->setClamp(TRUE, TRUE);
00145
00146 image_id.set( gViewerArt.getString("icon_top_pick.tga") );
00147 sClassifiedsImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00148
00149 image_id.set( gViewerArt.getString("icon_popular.tga") );
00150 sPopularImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00151
00152 image_id.set( gViewerArt.getString("icon_for_sale.tga") );
00153 sForSaleImage = gImageList.getImage(image_id, MIPMAP_FALSE, TRUE);
00154 }
00155
00156
00157 void LLWorldMapView::cleanupClass()
00158 {
00159 sAvatarYouSmallImage = NULL;
00160 sAvatarSmallImage = NULL;
00161 sAvatarLargeImage = NULL;
00162 sAvatarAboveImage = NULL;
00163 sAvatarBelowImage = NULL;
00164 sTelehubImage = NULL;
00165 sInfohubImage = NULL;
00166 sHomeImage = NULL;
00167 sEventImage = NULL;
00168 sEventMatureImage = NULL;
00169 sTrackCircleImage = NULL;
00170 sTrackArrowImage = NULL;
00171 sClassifiedsImage = NULL;
00172 sPopularImage = NULL;
00173 sForSaleImage = NULL;
00174 }
00175
00176 LLWorldMapView::LLWorldMapView(const std::string& name, const LLRect& rect )
00177 : LLPanel(name, rect, BORDER_NO),
00178 mBackgroundColor( LLColor4( 4.f/255.f, 4.f/255.f, 75.f/255.f, 1.f ) ),
00179 mItemPicked(FALSE),
00180 mPanning( FALSE ),
00181 mMouseDownPanX( 0 ),
00182 mMouseDownPanY( 0 ),
00183 mMouseDownX( 0 ),
00184 mMouseDownY( 0 ),
00185 mSelectIDStart(0)
00186 {
00187 sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS;
00188 clearLastClick();
00189
00190 const S32 DIR_WIDTH = 10;
00191 const S32 DIR_HEIGHT = 10;
00192 LLRect major_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH, 0 );
00193
00194 mTextBoxNorth = new LLTextBox( "N", major_dir_rect );
00195 addChild( mTextBoxNorth );
00196
00197 LLColor4 minor_color( 1.f, 1.f, 1.f, .7f );
00198
00199 mTextBoxEast = new LLTextBox( "E", major_dir_rect );
00200 mTextBoxEast->setColor( minor_color );
00201 addChild( mTextBoxEast );
00202
00203 mTextBoxWest = new LLTextBox( "W", major_dir_rect );
00204 mTextBoxWest->setColor( minor_color );
00205 addChild( mTextBoxWest );
00206
00207 mTextBoxSouth = new LLTextBox( "S", major_dir_rect );
00208 mTextBoxSouth->setColor( minor_color );
00209 addChild( mTextBoxSouth );
00210
00211 LLRect minor_dir_rect( 0, DIR_HEIGHT, DIR_WIDTH * 2, 0 );
00212
00213 mTextBoxSouthEast = new LLTextBox( "SE", minor_dir_rect );
00214 mTextBoxSouthEast->setColor( minor_color );
00215 addChild( mTextBoxSouthEast );
00216
00217 mTextBoxNorthEast = new LLTextBox( "NE", minor_dir_rect );
00218 mTextBoxNorthEast->setColor( minor_color );
00219 addChild( mTextBoxNorthEast );
00220
00221 mTextBoxSouthWest = new LLTextBox( "SW", minor_dir_rect );
00222 mTextBoxSouthWest->setColor( minor_color );
00223 addChild( mTextBoxSouthWest );
00224
00225 mTextBoxNorthWest = new LLTextBox( "NW", minor_dir_rect );
00226 mTextBoxNorthWest->setColor( minor_color );
00227 addChild( mTextBoxNorthWest );
00228 }
00229
00230
00231 LLWorldMapView::~LLWorldMapView()
00232 {
00233 cleanupTextures();
00234 }
00235
00236
00237
00238 void LLWorldMapView::cleanupTextures()
00239 {
00240 }
00241
00242
00243
00244 void LLWorldMapView::setScale( F32 scale )
00245 {
00246 if (scale != gMapScale)
00247 {
00248 F32 old_scale = gMapScale;
00249
00250 gMapScale = scale;
00251 if (gMapScale == 0.f)
00252 {
00253 gMapScale = 0.1f;
00254 }
00255
00256 F32 ratio = (scale / old_scale);
00257 sPanX *= ratio;
00258 sPanY *= ratio;
00259 sTargetPanX = sPanX;
00260 sTargetPanY = sPanY;
00261
00262 sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS;
00263 }
00264 }
00265
00266
00267
00268 void LLWorldMapView::translatePan( S32 delta_x, S32 delta_y )
00269 {
00270 sPanX += delta_x;
00271 sPanY += delta_y;
00272 sTargetPanX = sPanX;
00273 sTargetPanY = sPanY;
00274 }
00275
00276
00277
00278 void LLWorldMapView::setPan( S32 x, S32 y, BOOL snap )
00279 {
00280 sTargetPanX = (F32)x;
00281 sTargetPanY = (F32)y;
00282 if (snap)
00283 {
00284 sPanX = sTargetPanX;
00285 sPanY = sTargetPanY;
00286 }
00287 }
00288
00289
00291
00292
00293 BOOL is_agent_in_region(LLViewerRegion* region, LLSimInfo* info)
00294 {
00295 return ((region && info) && (info->mName == region->getName()));
00296 }
00297
00298
00300
00301 void LLWorldMapView::draw()
00302 {
00303 if (!getVisible() || !gWorldPointer)
00304 {
00305 return;
00306 }
00307
00308 LLTextureView::clearDebugImages();
00309
00310 F64 current_time = LLTimer::getElapsedSeconds();
00311
00312 mVisibleRegions.clear();
00313
00314
00315 sPanX = lerp(sPanX, sTargetPanX, LLCriticalDamp::getInterpolant(0.1f));
00316 sPanY = lerp(sPanY, sTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
00317
00318 const S32 width = mRect.getWidth();
00319 const S32 height = mRect.getHeight();
00320 const S32 half_width = width / 2;
00321 const S32 half_height = height / 2;
00322 LLVector3d camera_global = gAgent.getCameraPositionGlobal();
00323
00324 LLLocalClipRect clip(getLocalRect());
00325 {
00326 LLGLSNoTexture no_texture;
00327
00328 glMatrixMode(GL_MODELVIEW);
00329
00330
00331 glColorMask(FALSE, FALSE, FALSE, TRUE);
00332 glAlphaFunc(GL_GEQUAL, 0.00f);
00333 glBlendFunc(GL_ONE, GL_ZERO);
00334 glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
00335 gl_rect_2d(0, height, width, 0);
00336 }
00337
00338 glAlphaFunc(GL_GEQUAL, 0.01f);
00339 glColorMask(TRUE, TRUE, TRUE, TRUE);
00340 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00341
00342 F32 layer_alpha = 1.f;
00343
00344
00345 for (U32 layer_idx=0; layer_idx<gWorldMap->mMapLayers[gWorldMap->mCurrentMap].size(); ++layer_idx)
00346 {
00347 if (!gWorldMap->mMapLayers[gWorldMap->mCurrentMap][layer_idx].LayerDefined)
00348 {
00349 continue;
00350 }
00351 LLWorldMapLayer *layer = &gWorldMap->mMapLayers[gWorldMap->mCurrentMap][layer_idx];
00352 LLViewerImage *current_image = layer->LayerImage;
00353 #if 1 || LL_RELEASE_FOR_DOWNLOAD
00354 if (current_image->isMissingAsset())
00355 {
00356 continue;
00357 }
00358 #endif
00359
00360 LLVector3d origin_global((F64)layer->LayerExtents.mLeft * REGION_WIDTH_METERS, (F64)layer->LayerExtents.mBottom * REGION_WIDTH_METERS, 0.f);
00361
00362
00363 LLVector3d rel_region_pos = origin_global - camera_global;
00364 S32 relative_x = lltrunc((rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale);
00365 S32 relative_y = lltrunc((rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale);
00366
00367 F32 pix_width = gMapScale*(layer->LayerExtents.getWidth() + 1);
00368 F32 pix_height = gMapScale*(layer->LayerExtents.getHeight() + 1);
00369
00370
00371 F32 bottom = sPanY + half_height + relative_y;
00372 F32 left = sPanX + half_width + relative_x;
00373 F32 top = bottom + pix_height;
00374 F32 right = left + pix_width;
00375 F32 pixel_area = pix_width*pix_height;
00376
00377
00378 if (top < 0.f ||
00379 bottom > height ||
00380 right < 0.f ||
00381 left > width ||
00382 (pixel_area < 4*4))
00383 {
00384 current_image->setBoostLevel(0);
00385 continue;
00386 }
00387
00388 current_image->setBoostLevel(LLViewerImage::BOOST_MAP_LAYER);
00389 current_image->setKnownDrawSize(llround(pix_width), llround(pix_height));
00390
00391 if (!current_image->getHasGLTexture())
00392 {
00393 continue;
00394 }
00395
00396
00397
00398
00399
00400 LLViewerImage::bindTexture(current_image);
00401
00402
00403
00404 glColorMask(TRUE, TRUE, TRUE, FALSE);
00405 glColor4f(1.f, 1.f, 1.f, layer_alpha);
00406
00407 glBegin(GL_QUADS);
00408 glTexCoord2f(0.0f, 1.0f);
00409 glVertex3f(left, top, -1.0f);
00410 glTexCoord2f(0.0f, 0.0f);
00411 glVertex3f(left, bottom, -1.0f);
00412 glTexCoord2f(1.0f, 0.0f);
00413 glVertex3f(right, bottom, -1.0f);
00414 glTexCoord2f(1.0f, 1.0f);
00415 glVertex3f(right, top, -1.0f);
00416 glEnd();
00417
00418
00419 glColorMask(FALSE, FALSE, FALSE, TRUE);
00420 glColor4f(1.f, 1.f, 1.f, 1.f);
00421
00422 glBegin(GL_QUADS);
00423 glTexCoord2f(0.0f, 1.0f);
00424 glVertex2f(left, top);
00425 glTexCoord2f(0.0f, 0.0f);
00426 glVertex2f(left, bottom);
00427 glTexCoord2f(1.0f, 0.0f);
00428 glVertex2f(right, bottom);
00429 glTexCoord2f(1.0f, 1.0f);
00430 glVertex2f(right, top);
00431 glEnd();
00432 }
00433
00434 glAlphaFunc(GL_GEQUAL, 0.01f);
00435 glColorMask(TRUE, TRUE, TRUE, TRUE);
00436
00437 #if 1
00438 F32 sim_alpha = 1.f;
00439
00440
00441 for (LLWorldMap::sim_info_map_t::iterator it = gWorldMap->mSimInfoMap.begin();
00442 it != gWorldMap->mSimInfoMap.end(); ++it)
00443 {
00444 U64 handle = (*it).first;
00445 LLSimInfo* info = (*it).second;
00446
00447 if (info->mCurrentImage.isNull())
00448 {
00449 info->mCurrentImage = gImageList.getImage(info->mMapImageID[gWorldMap->mCurrentMap], MIPMAP_TRUE, FALSE);
00450 }
00451 if (info->mOverlayImage.isNull() && info->mMapImageID[2].notNull())
00452 {
00453 info->mOverlayImage = gImageList.getImage(info->mMapImageID[2], MIPMAP_TRUE, FALSE);
00454 info->mOverlayImage->bind(0);
00455 info->mOverlayImage->setClamp(TRUE, TRUE);
00456 }
00457
00458 LLViewerImage* simimage = info->mCurrentImage;
00459 LLViewerImage* overlayimage = info->mOverlayImage;
00460
00461 if (gMapScale < 8.f)
00462 {
00463 simimage->setBoostLevel(0);
00464 if (overlayimage) overlayimage->setBoostLevel(0);
00465 continue;
00466 }
00467
00468 LLVector3d origin_global = from_region_handle(handle);
00469 LLVector3d camera_global = gAgent.getCameraPositionGlobal();
00470
00471
00472 LLVector3d rel_region_pos = origin_global - camera_global;
00473 S32 relative_x = lltrunc((rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale);
00474 S32 relative_y = lltrunc((rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale);
00475
00476
00477 F32 bottom = sPanY + half_height + relative_y;
00478 F32 left = sPanX + half_width + relative_x;
00479 F32 top = bottom + gMapScale ;
00480 F32 right = left + gMapScale ;
00481
00482
00483
00484
00485 F32 map_scale_cutoff = SIM_MAP_SCALE;
00486 if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) > 0)
00487 {
00488 map_scale_cutoff = SIM_NULL_MAP_SCALE;
00489 }
00490
00491 info->mShowAgentLocations = (gMapScale >= SIM_MAP_AGENT_SCALE);
00492
00493 bool sim_visible =
00494 (gMapScale >= map_scale_cutoff) &&
00495 (simimage->getHasGLTexture());
00496
00497 if (sim_visible)
00498 {
00499
00500 if (info->mAlpha < 0.0f)
00501 info->mAlpha = 1.f;
00502 else
00503 info->mAlpha = lerp(info->mAlpha, 1.f, LLCriticalDamp::getInterpolant(0.15f));
00504 }
00505 else
00506 {
00507
00508 if (info->mAlpha < 0.0f)
00509 info->mAlpha = 0.f;
00510 else
00511 info->mAlpha = lerp(info->mAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f));
00512 }
00513
00514
00515
00516 if (top < 0.f ||
00517 bottom > height ||
00518 right < 0.f ||
00519 left > width )
00520 {
00521 simimage->setBoostLevel(0);
00522 if (overlayimage) overlayimage->setBoostLevel(0);
00523 continue;
00524 }
00525
00526 mVisibleRegions.push_back(handle);
00527
00528 if (current_time - info->mAgentsUpdateTime > AGENTS_UPDATE_TIME)
00529 {
00530 gWorldMap->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, info->mHandle);
00531 info->mAgentsUpdateTime = current_time;
00532 }
00533
00534
00535 LLVector3d center_global = origin_global;
00536 center_global.mdV[VX] += 128.0;
00537 center_global.mdV[VY] += 128.0;
00538
00539 S32 draw_size = llround(gMapScale);
00540 simimage->setBoostLevel(LLViewerImage::BOOST_MAP);
00541 simimage->setKnownDrawSize(draw_size, draw_size);
00542
00543 if (overlayimage)
00544 {
00545 overlayimage->setBoostLevel(LLViewerImage::BOOST_MAP);
00546 overlayimage->setKnownDrawSize(draw_size, draw_size);
00547 }
00548
00549
00550
00551 if (sim_visible && info->mAlpha > 0.001f)
00552 {
00553
00554
00555 LLGLSUIDefault gls_ui;
00556 LLViewerImage::bindTexture(simimage);
00557
00558 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00559 F32 alpha = sim_alpha * info->mAlpha;
00560 glColor4f(1.f, 1.0f, 1.0f, alpha);
00561
00562 glBegin(GL_QUADS);
00563 glTexCoord2f(0.f, 1.f);
00564 glVertex3f(left, top, 0.f);
00565 glTexCoord2f(0.f, 0.f);
00566 glVertex3f(left, bottom, 0.f);
00567 glTexCoord2f(1.f, 0.f);
00568 glVertex3f(right, bottom, 0.f);
00569 glTexCoord2f(1.f, 1.f);
00570 glVertex3f(right, top, 0.f);
00571 glEnd();
00572
00573 if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->getHasGLTexture())
00574 {
00575 LLViewerImage::bindTexture(overlayimage);
00576 glColor4f(1.f, 1.f, 1.f, alpha);
00577 glBegin(GL_QUADS);
00578 glTexCoord2f(0.f, 1.f);
00579 glVertex3f(left, top, -0.5f);
00580 glTexCoord2f(0.f, 0.f);
00581 glVertex3f(left, bottom, -0.5f);
00582 glTexCoord2f(1.f, 0.f);
00583 glVertex3f(right, bottom, -0.5f);
00584 glTexCoord2f(1.f, 1.f);
00585 glVertex3f(right, top, -0.5f);
00586 glEnd();
00587 }
00588
00589 if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) == 0)
00590 {
00591
00592 glBlendFunc(GL_ONE, GL_ZERO);
00593 glColorMask(FALSE, FALSE, FALSE, TRUE);
00594 glColor4f(1.f, 1.f, 1.f, 1.f);
00595
00596 LLGLSNoTexture gls_no_texture;
00597 glBegin(GL_QUADS);
00598 glVertex2f(left, top);
00599 glVertex2f(left, bottom);
00600 glVertex2f(right, bottom);
00601 glVertex2f(right, top);
00602 glEnd();
00603
00604 glColorMask(TRUE, TRUE, TRUE, TRUE);
00605 }
00606 }
00607
00608 if (info->mAccess == SIM_ACCESS_DOWN)
00609 {
00610
00611 glBlendFunc(GL_DST_ALPHA, GL_SRC_ALPHA);
00612 glColor4f(0.2f, 0.0f, 0.0f, 0.4f);
00613
00614 LLGLSNoTexture gls_no_texture;
00615 glBegin(GL_QUADS);
00616 glVertex2f(left, top);
00617 glVertex2f(left, bottom);
00618 glVertex2f(right, bottom);
00619 glVertex2f(right, top);
00620 glEnd();
00621 }
00622
00623
00624 if (info->mAccess != SIM_ACCESS_DOWN
00625 && info->mAccess > SIM_ACCESS_PG
00626 && gAgent.isTeen())
00627 {
00628 glBlendFunc(GL_DST_ALPHA, GL_ZERO);
00629
00630 LLGLSNoTexture gls_no_texture;
00631 glColor3f(1.f, 0.f, 0.f);
00632 glBegin(GL_LINES);
00633 glVertex2f(left, top);
00634 glVertex2f(right, bottom);
00635 glVertex2f(left, bottom);
00636 glVertex2f(right, top);
00637 glEnd();
00638 }
00639
00640
00641 LLFontGL* font = LLFontGL::sSansSerifSmall;
00642
00643 char mesg[MAX_STRING];
00644 if (gMapScale < sThresholdA)
00645 {
00646 mesg[0] = '\0';
00647 }
00648 else if (gMapScale < sThresholdB)
00649 {
00650
00651 mesg[0] = '\0';
00652 }
00653 else
00654 {
00655
00656
00657
00658
00659 if (info->mAccess == SIM_ACCESS_DOWN)
00660 {
00661 snprintf(mesg, MAX_STRING, "%s (Offline)", info->mName.c_str());
00662 }
00663 else
00664 {
00665 snprintf(mesg, MAX_STRING, "%s", info->mName.c_str());
00666 }
00667 }
00668
00669 if (mesg[0] != '\0')
00670 {
00671 font->renderUTF8(
00672 mesg, 0,
00673 llfloor(left + 3),
00674 llfloor(bottom + 2),
00675 LLColor4::white,
00676 LLFontGL::LEFT,
00677 LLFontGL::BASELINE,
00678 LLFontGL::DROP_SHADOW);
00679 }
00680 }
00681 #endif
00682
00683
00684 #if 1
00685
00686 LLGLSUIDefault gls_ui;
00687 {
00688 LLGLSNoTexture gls_no_texture;
00689 glAlphaFunc(GL_GEQUAL, 0.0f);
00690 glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
00691 glColor4fv( mBackgroundColor.mV );
00692 gl_rect_2d(0, height, width, 0);
00693 }
00694
00695 glAlphaFunc(GL_GEQUAL, 0.01f);
00696 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00697
00698
00699 if (gSavedSettings.getBOOL("MapShowInfohubs"))
00700 {
00701 drawGenericItems(gWorldMap->mInfohubs, sInfohubImage);
00702 }
00703
00704
00705 if (gSavedSettings.getBOOL("MapShowTelehubs"))
00706 {
00707 drawGenericItems(gWorldMap->mTelehubs, sTelehubImage);
00708 }
00709
00710
00711 LLVector3d home;
00712 if (gAgent.getHomePosGlobal(&home))
00713 {
00714 drawImage(home, sHomeImage);
00715 }
00716
00717 if (gSavedSettings.getBOOL("MapShowLandForSale"))
00718 {
00719 drawGenericItems(gWorldMap->mLandForSale, sForSaleImage);
00720 }
00721
00722 if (gSavedSettings.getBOOL("MapShowClassifieds"))
00723 {
00724 drawGenericItems(gWorldMap->mClassifieds, sClassifiedsImage);
00725 }
00726
00727 if (gSavedSettings.getBOOL("MapShowPopular"))
00728 {
00729 drawGenericItems(gWorldMap->mPopular, sPopularImage);
00730 }
00731
00732 if (gSavedSettings.getBOOL("MapShowEvents"))
00733 {
00734 drawEvents();
00735 }
00736
00737
00738 LLVector3d pos_global = gAgent.getPositionGlobal();
00739 drawImage(pos_global, sAvatarLargeImage);
00740
00741 LLVector3 pos_map = globalPosToView(pos_global);
00742 if (!pointInView(llround(pos_map.mV[VX]), llround(pos_map.mV[VY])))
00743 {
00744 drawTracking(pos_global,
00745 lerp(LLColor4::yellow, LLColor4::orange, 0.4f),
00746 TRUE,
00747 "You are here",
00748 "",
00749 llround(LLFontGL::sSansSerifSmall->getLineHeight()));
00750 }
00751
00752
00753 drawFrustum();
00754
00755
00756
00757 if (gSavedSettings.getBOOL("MapShowPeople"))
00758 {
00759 drawAgents();
00760 }
00761
00762
00763 LLTracker::ETrackingStatus tracking_status = LLTracker::getTrackingStatus();
00764 if ( LLTracker::TRACKING_AVATAR == tracking_status )
00765 {
00766 drawTracking( LLAvatarTracker::instance().getGlobalPos(), gTrackColor, TRUE, LLTracker::getLabel(), "" );
00767 }
00768 else if ( LLTracker::TRACKING_LANDMARK == tracking_status
00769 || LLTracker::TRACKING_LOCATION == tracking_status )
00770 {
00771
00772
00773 LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
00774 if (!pos_global.isExactlyZero())
00775 {
00776 drawTracking( pos_global, gTrackColor, TRUE, LLTracker::getLabel(), LLTracker::getToolTip() );
00777 }
00778 }
00779 else if (gWorldMap->mIsTrackingUnknownLocation)
00780 {
00781 if (gWorldMap->mInvalidLocation)
00782 {
00783
00784 LLColor4 loading_color(0.0, 0.5, 1.0, 1.0);
00785 drawTracking( gWorldMap->mUnknownLocation, loading_color, TRUE, "Invalid Location", "");
00786 }
00787 else
00788 {
00789 double value = fmod(current_time, 2);
00790 value = 0.5 + 0.5*cos(value * 3.14159f);
00791 LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
00792 drawTracking( gWorldMap->mUnknownLocation, loading_color, TRUE, "Loading...", "");
00793 }
00794 }
00795 #endif
00796
00797
00798 LLGLDisable no_scissor(GL_SCISSOR_TEST);
00799
00800 updateDirections();
00801
00802 LLView::draw();
00803
00804 updateVisibleBlocks();
00805 }
00806
00807
00808
00809 void LLWorldMapView::setVisible(BOOL visible)
00810 {
00811 LLPanel::setVisible(visible);
00812 if (!visible && gWorldMap)
00813 {
00814 for (S32 map = 0; map < MAP_SIM_IMAGE_TYPES; map++)
00815 {
00816 for (U32 layer_idx=0; layer_idx<gWorldMap->mMapLayers[map].size(); ++layer_idx)
00817 {
00818 if (gWorldMap->mMapLayers[map][layer_idx].LayerDefined)
00819 {
00820 LLWorldMapLayer *layer = &gWorldMap->mMapLayers[map][layer_idx];
00821 layer->LayerImage->setBoostLevel(0);
00822 }
00823 }
00824 }
00825 for (LLWorldMap::sim_info_map_t::iterator it = gWorldMap->mSimInfoMap.begin();
00826 it != gWorldMap->mSimInfoMap.end(); ++it)
00827 {
00828 LLSimInfo* info = (*it).second;
00829 if (info->mCurrentImage.notNull())
00830 {
00831 info->mCurrentImage->setBoostLevel(0);
00832 }
00833 if (info->mOverlayImage.notNull())
00834 {
00835 info->mOverlayImage->setBoostLevel(0);
00836 }
00837 }
00838 }
00839 }
00840
00841 void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items, LLPointer<LLViewerImage> image)
00842 {
00843 LLWorldMap::item_info_list_t::const_iterator e;
00844 for (e = items.begin(); e != items.end(); ++e)
00845 {
00846 drawGenericItem(*e, image);
00847 }
00848 }
00849
00850 void LLWorldMapView::drawGenericItem(const LLItemInfo& item, LLPointer<LLViewerImage> image)
00851 {
00852 drawImage(item.mPosGlobal, image);
00853 }
00854
00855
00856 void LLWorldMapView::drawImage(const LLVector3d& global_pos, LLPointer<LLViewerImage> image, const LLColor4& color)
00857 {
00858 LLVector3 pos_map = globalPosToView( global_pos );
00859 gl_draw_image(llround(pos_map.mV[VX] - image->getWidth() /2.f),
00860 llround(pos_map.mV[VY] - image->getHeight()/2.f),
00861 image,
00862 color);
00863 }
00864
00865 void LLWorldMapView::drawImageStack(const LLVector3d& global_pos, LLPointer<LLViewerImage> image, U32 count, F32 offset, const LLColor4& color)
00866 {
00867 LLVector3 pos_map = globalPosToView( global_pos );
00868 for(U32 i=0; i<count; i++)
00869 {
00870 gl_draw_image(llround(pos_map.mV[VX] - image->getWidth() /2.f),
00871 llround(pos_map.mV[VY] - image->getHeight()/2.f + i*offset),
00872 image,
00873 color);
00874 }
00875 }
00876
00877
00878 void LLWorldMapView::drawAgents()
00879 {
00880 F32 agents_scale = (gMapScale * 0.9f) / 256.f;
00881
00882 for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
00883 {
00884 U64 handle = *iter;
00885 LLSimInfo* siminfo = gWorldMap->simInfoFromHandle(handle);
00886 if (siminfo && (siminfo->mAccess == SIM_ACCESS_DOWN))
00887 {
00888 continue;
00889 }
00890 LLWorldMap::agent_list_map_t::iterator counts_iter = gWorldMap->mAgentLocationsMap.find(handle);
00891 if (siminfo && siminfo->mShowAgentLocations && counts_iter != gWorldMap->mAgentLocationsMap.end())
00892 {
00893
00894 LLWorldMap::item_info_list_t& agentcounts = counts_iter->second;
00895 S32 sim_agent_count = 0;
00896 for (LLWorldMap::item_info_list_t::iterator iter = agentcounts.begin();
00897 iter != agentcounts.end(); ++iter)
00898 {
00899 const LLItemInfo& info = *iter;
00900 S32 agent_count = info.mExtra;
00901 sim_agent_count += info.mExtra;
00902
00903
00904 drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count, 3.f, gAvatarMapColor);
00905 }
00906 gWorldMap->mNumAgents[handle] = sim_agent_count;
00907 }
00908 else
00909 {
00910
00911 S32 num_agents = gWorldMap->mNumAgents[handle];
00912 if (num_agents > 0)
00913 {
00914 LLVector3d region_center = from_region_handle(handle);
00915 region_center[VX] += REGION_WIDTH_METERS / 2;
00916 region_center[VY] += REGION_WIDTH_METERS / 2;
00917
00918 S32 agent_count = (S32)(((num_agents-1) * agents_scale + (num_agents-1) * 0.1f)+.1f) + 1;
00919 drawImageStack(region_center, sAvatarSmallImage, agent_count, 3.f, gAvatarMapColor);
00920 }
00921 }
00922 }
00923 }
00924
00925
00926 void LLWorldMapView::drawEvents()
00927 {
00928 BOOL show_mature = gSavedSettings.getBOOL("ShowMatureEvents");
00929
00930
00931 LLWorldMap::item_info_list_t::const_iterator e;
00932 for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e)
00933 {
00934 if (!e->mSelected)
00935 {
00936 drawGenericItem(*e, sEventImage);
00937 }
00938 }
00939 if (show_mature)
00940 {
00941 for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e)
00942 {
00943 if (!e->mSelected)
00944 {
00945 drawGenericItem(*e, sEventMatureImage);
00946 }
00947 }
00948 }
00949
00950
00951 for (e = gWorldMap->mPGEvents.begin(); e != gWorldMap->mPGEvents.end(); ++e)
00952 {
00953 if (e->mSelected)
00954 {
00955 drawGenericItem(*e, sEventImage);
00956 }
00957 }
00958 if (show_mature)
00959 {
00960 for (e = gWorldMap->mMatureEvents.begin(); e != gWorldMap->mMatureEvents.end(); ++e)
00961 {
00962 if (e->mSelected)
00963 {
00964 drawGenericItem(*e, sEventMatureImage);
00965 }
00966 }
00967 }
00968 }
00969
00970
00971 void LLWorldMapView::drawFrustum()
00972 {
00973
00974 F32 meters_to_pixels = gMapScale/ REGION_WIDTH_METERS;
00975
00976 F32 horiz_fov = gCamera->getView() * gCamera->getAspect();
00977 F32 far_clip_meters = gCamera->getFar();
00978 F32 far_clip_pixels = far_clip_meters * meters_to_pixels;
00979
00980 F32 half_width_meters = far_clip_meters * tan( horiz_fov / 2 );
00981 F32 half_width_pixels = half_width_meters * meters_to_pixels;
00982
00983 F32 ctr_x = mRect.getWidth() * 0.5f + sPanX;
00984 F32 ctr_y = mRect.getHeight() * 0.5f + sPanY;
00985
00986 LLGLSNoTexture gls_no_texture;
00987
00988
00989 glPushMatrix();
00990 glTranslatef( ctr_x, ctr_y, 0 );
00991 glRotatef( atan2( gCamera->getAtAxis().mV[VX], gCamera->getAtAxis().mV[VY] ) * RAD_TO_DEG, 0.f, 0.f, -1.f);
00992
00993
00994
00995 glBegin( GL_TRIANGLES );
00996 glColor4f(1.f, 1.f, 1.f, 0.25f);
00997 glVertex2f( 0, 0 );
00998
00999 glColor4f(1.f, 1.f, 1.f, 0.02f);
01000 glVertex2f( -half_width_pixels, far_clip_pixels );
01001
01002 glColor4f(1.f, 1.f, 1.f, 0.02f);
01003 glVertex2f( half_width_pixels, far_clip_pixels );
01004 glEnd();
01005 glPopMatrix();
01006 }
01007
01008
01009 LLVector3 LLWorldMapView::globalPosToView( const LLVector3d& global_pos )
01010 {
01011 LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal();
01012 LLVector3 pos_local;
01013 pos_local.setVec(relative_pos_global);
01014
01015 pos_local.mV[VX] *= sPixelsPerMeter;
01016 pos_local.mV[VY] *= sPixelsPerMeter;
01017
01018
01019
01020 pos_local.mV[VX] += mRect.getWidth() / 2 + sPanX;
01021 pos_local.mV[VY] += mRect.getHeight() / 2 + sPanY;
01022
01023 return pos_local;
01024 }
01025
01026
01027 void LLWorldMapView::drawTracking(const LLVector3d& pos_global, const LLColor4& color,
01028 BOOL draw_arrow, LLString label, LLString tooltip, S32 vert_offset )
01029 {
01030 LLVector3 pos_local = globalPosToView( pos_global );
01031 S32 x = llround( pos_local.mV[VX] );
01032 S32 y = llround( pos_local.mV[VY] );
01033 LLFontGL* font = LLFontGL::sSansSerifSmall;
01034 S32 text_x = x;
01035 S32 text_y = (S32)(y - sTrackCircleImage->getHeight()/2 - font->getLineHeight());
01036
01037 BOOL is_in_window = true;
01038
01039 if( x < 0
01040 || y < 0
01041 || x >= mRect.getWidth()
01042 || y >= mRect.getHeight() )
01043 {
01044 if (draw_arrow)
01045 {
01046 drawTrackingCircle( mRect, x, y, color, 3, 15 );
01047 drawTrackingArrow( mRect, x, y, color );
01048 text_x = sTrackingArrowX;
01049 text_y = sTrackingArrowY;
01050 }
01051 is_in_window = false;
01052 }
01053 else if (LLTracker::getTrackingStatus() == LLTracker::TRACKING_LOCATION &&
01054 LLTracker::getTrackedLocationType() != LLTracker::LOCATION_NOTHING)
01055 {
01056 drawTrackingCircle( mRect, x, y, color, 3, 15 );
01057 }
01058 else
01059 {
01060 drawImage(pos_global, sTrackCircleImage, color);
01061 }
01062
01063
01064 const S32 TEXT_PADDING = DEFAULT_TRACKING_ARROW_SIZE + 2;
01065 S32 half_text_width = llfloor(font->getWidthF32(label) * 0.5f);
01066 text_x = llclamp(text_x, half_text_width + TEXT_PADDING, mRect.getWidth() - half_text_width - TEXT_PADDING);
01067 text_y = llclamp(text_y + vert_offset, TEXT_PADDING + vert_offset, mRect.getHeight() - llround(font->getLineHeight()) - TEXT_PADDING - vert_offset);
01068
01069 if (label != "")
01070 {
01071 font->renderUTF8(
01072 label, 0,
01073 text_x,
01074 text_y,
01075 LLColor4::white, LLFontGL::HCENTER,
01076 LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
01077
01078 if (tooltip != "")
01079 {
01080 text_y -= (S32)font->getLineHeight();
01081
01082 font->renderUTF8(
01083 tooltip, 0,
01084 text_x,
01085 text_y,
01086 LLColor4::white, LLFontGL::HCENTER,
01087 LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
01088 }
01089 }
01090 }
01091
01092
01093 LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
01094 {
01095 x -= llfloor((mRect.getWidth() / 2 + sPanX));
01096 y -= llfloor((mRect.getHeight() / 2 + sPanY));
01097
01098 LLVector3 pos_local( (F32)x, (F32)y, 0.f );
01099
01100 pos_local *= ( REGION_WIDTH_METERS / gMapScale );
01101
01102 LLVector3d pos_global;
01103 pos_global.setVec( pos_local );
01104 pos_global += gAgent.getCameraPositionGlobal();
01105 if(gAgent.isGodlike())
01106 {
01107 pos_global.mdV[VZ] = GODLY_TELEPORT_HEIGHT;
01108 }
01109 else
01110 {
01111 pos_global.mdV[VZ] = gAgent.getPositionAgent().mV[VZ];
01112 }
01113
01114 return pos_global;
01115 }
01116
01117
01118 BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, LLString& msg, LLRect* sticky_rect_screen )
01119 {
01120 if( !getVisible() || !pointInView( x, y ) )
01121 {
01122 return FALSE;
01123 }
01124
01125 LLVector3d pos_global = viewPosToGlobal(x, y);
01126
01127 LLSimInfo* info = gWorldMap->simInfoFromPosGlobal(pos_global);
01128 if (info)
01129 {
01130 LLViewerRegion *region = gAgent.getRegion();
01131
01132 std::string message =
01133 llformat("%s (%s)",
01134 info->mName.c_str(),
01135 LLViewerRegion::accessToString(info->mAccess));
01136
01137 if (info->mAccess != SIM_ACCESS_DOWN)
01138 {
01139 S32 agent_count = gWorldMap->mNumAgents[info->mHandle];
01140 if (region && region->getHandle() == info->mHandle)
01141 {
01142 ++agent_count;
01143 }
01144
01145
01146
01147 if (agent_count > 0)
01148 {
01149 message += llformat("\n%d ", agent_count);
01150
01151 if (agent_count == 1)
01152 {
01153 message += "person";
01154 }
01155 else
01156 {
01157 message += "people";
01158 }
01159 }
01160 }
01161 msg.assign( message );
01162
01163
01164 std::string region_flags = LLViewerRegion::regionFlagsToString(info->mRegionFlags);
01165
01166 if (!region_flags.empty())
01167 {
01168 msg += '\n';
01169 msg += region_flags;
01170 }
01171
01172 S32 SLOP = 4;
01173 localPointToScreen(
01174 x - SLOP, y - SLOP,
01175 &(sticky_rect_screen->mLeft), &(sticky_rect_screen->mBottom) );
01176 sticky_rect_screen->mRight = sticky_rect_screen->mLeft + 2 * SLOP;
01177 sticky_rect_screen->mTop = sticky_rect_screen->mBottom + 2 * SLOP;
01178 }
01179 return TRUE;
01180 }
01181
01182
01183
01184 static void drawDot(F32 x_pixels, F32 y_pixels,
01185 const LLColor4& color,
01186 F32 relative_z,
01187 F32 dot_radius,
01188 LLPointer<LLViewerImage> dot_image)
01189 {
01190 const F32 HEIGHT_THRESHOLD = 7.f;
01191
01192 if(-HEIGHT_THRESHOLD <= relative_z && relative_z <= HEIGHT_THRESHOLD)
01193 {
01194 gl_draw_image( llround(x_pixels) - dot_image->getWidth()/2,
01195 llround(y_pixels) - dot_image->getHeight()/2,
01196 dot_image,
01197 color);
01198 }
01199 else
01200 {
01201 F32 left = x_pixels - dot_radius;
01202 F32 right = x_pixels + dot_radius;
01203 F32 center = (left + right) * 0.5f;
01204 F32 top = y_pixels + dot_radius;
01205 F32 bottom = y_pixels - dot_radius;
01206
01207 LLGLSNoTexture gls_no_texture;
01208 glColor4fv( color.mV );
01209 LLUI::setLineWidth(1.5f);
01210 F32 h_bar = relative_z > HEIGHT_THRESHOLD ? top : bottom;
01211 glBegin( GL_LINES );
01212 glVertex2f(left, h_bar);
01213 glVertex2f(right, h_bar);
01214 glVertex2f(center, top);
01215 glVertex2f(center, bottom);
01216 glEnd();
01217 LLUI::setLineWidth(1.0f);
01218 }
01219 }
01220
01221
01222
01223 void LLWorldMapView::drawAvatar(F32 x_pixels,
01224 F32 y_pixels,
01225 const LLColor4& color,
01226 F32 relative_z,
01227 F32 dot_radius)
01228 {
01229 const F32 HEIGHT_THRESHOLD = 7.f;
01230 LLViewerImage* dot_image = sAvatarSmallImage;
01231 if(relative_z < -HEIGHT_THRESHOLD)
01232 {
01233 dot_image = sAvatarBelowImage;
01234 }
01235 else if(relative_z > HEIGHT_THRESHOLD)
01236 {
01237 dot_image = sAvatarAboveImage;
01238 }
01239 gl_draw_image(
01240 llround(x_pixels) - dot_image->getWidth()/2,
01241 llround(y_pixels) - dot_image->getHeight()/2,
01242 dot_image, color);
01243 }
01244
01245
01246
01247 void LLWorldMapView::drawTrackingDot( F32 x_pixels,
01248 F32 y_pixels,
01249 const LLColor4& color,
01250 F32 relative_z,
01251 F32 dot_radius)
01252 {
01253 drawDot(x_pixels, y_pixels, color, relative_z, dot_radius, sTrackCircleImage);
01254 }
01255
01256
01257
01258
01259 void LLWorldMapView::drawIconName(F32 x_pixels,
01260 F32 y_pixels,
01261 const LLColor4& color,
01262 const std::string& first_line,
01263 const std::string& second_line)
01264 {
01265 const S32 VERT_PAD = 8;
01266 S32 text_x = llround(x_pixels);
01267 S32 text_y = llround(y_pixels
01268 - BIG_DOT_RADIUS
01269 - VERT_PAD);
01270
01271
01272 LLFontGL::sSansSerif->renderUTF8(first_line, 0,
01273 text_x,
01274 text_y,
01275 color,
01276 LLFontGL::HCENTER,
01277 LLFontGL::TOP,
01278 LLFontGL::DROP_SHADOW);
01279
01280 text_y -= llround(LLFontGL::sSansSerif->getLineHeight());
01281
01282
01283 LLFontGL::sSansSerif->renderUTF8(second_line, 0,
01284 text_x,
01285 text_y,
01286 color,
01287 LLFontGL::HCENTER,
01288 LLFontGL::TOP,
01289 LLFontGL::DROP_SHADOW);
01290 }
01291
01292
01293
01294 void LLWorldMapView::drawTrackingCircle( const LLRect& rect, S32 x, S32 y, const LLColor4& color, S32 min_thickness, S32 overlap )
01295 {
01296 F32 start_theta = 0.f;
01297 F32 end_theta = F_TWO_PI;
01298 F32 x_delta = 0.f;
01299 F32 y_delta = 0.f;
01300
01301 if (x < 0)
01302 {
01303 x_delta = 0.f - (F32)x;
01304 start_theta = F_PI + F_PI_BY_TWO;
01305 end_theta = F_TWO_PI + F_PI_BY_TWO;
01306 }
01307 else if (x > rect.getWidth())
01308 {
01309 x_delta = (F32)(x - rect.getWidth());
01310 start_theta = F_PI_BY_TWO;
01311 end_theta = F_PI + F_PI_BY_TWO;
01312 }
01313
01314 if (y < 0)
01315 {
01316 y_delta = 0.f - (F32)y;
01317 if (x < 0)
01318 {
01319 start_theta = 0.f;
01320 end_theta = F_PI_BY_TWO;
01321 }
01322 else if (x > rect.getWidth())
01323 {
01324 start_theta = F_PI_BY_TWO;
01325 end_theta = F_PI;
01326 }
01327 else
01328 {
01329 start_theta = 0.f;
01330 end_theta = F_PI;
01331 }
01332 }
01333 else if (y > rect.getHeight())
01334 {
01335 y_delta = (F32)(y - rect.getHeight());
01336 if (x < 0)
01337 {
01338 start_theta = F_PI + F_PI_BY_TWO;
01339 end_theta = F_TWO_PI;
01340 }
01341 else if (x > rect.getWidth())
01342 {
01343 start_theta = F_PI;
01344 end_theta = F_PI + F_PI_BY_TWO;
01345 }
01346 else
01347 {
01348 start_theta = F_PI;
01349 end_theta = F_TWO_PI;
01350 }
01351 }
01352
01353 F32 distance = sqrtf(x_delta * x_delta + y_delta * y_delta);
01354
01355 distance = llmax(0.1f, distance);
01356
01357 F32 outer_radius = distance + (1.f + (9.f * sqrtf(x_delta * y_delta) / distance)) * (F32)overlap;
01358 F32 inner_radius = outer_radius - (F32)min_thickness;
01359
01360 F32 angle_adjust_x = asin(x_delta / outer_radius);
01361 F32 angle_adjust_y = asin(y_delta / outer_radius);
01362
01363 if (angle_adjust_x)
01364 {
01365 if (angle_adjust_y)
01366 {
01367 F32 angle_adjust = llmin(angle_adjust_x, angle_adjust_y);
01368 start_theta += angle_adjust;
01369 end_theta -= angle_adjust;
01370 }
01371 else
01372 {
01373 start_theta += angle_adjust_x;
01374 end_theta -= angle_adjust_x;
01375 }
01376 }
01377 else if (angle_adjust_y)
01378 {
01379 start_theta += angle_adjust_y;
01380 end_theta -= angle_adjust_y;
01381 }
01382
01383 glMatrixMode(GL_MODELVIEW);
01384 glPushMatrix();
01385 glTranslatef((F32)x, (F32)y, 0.f);
01386 gl_washer_segment_2d(inner_radius, outer_radius, start_theta, end_theta, 40, color, color);
01387 glPopMatrix();
01388
01389 }
01390
01391
01392 void LLWorldMapView::drawTrackingArrow(const LLRect& rect, S32 x, S32 y,
01393 const LLColor4& color,
01394 S32 arrow_size)
01395 {
01396 F32 x_center = (F32)rect.getWidth() / 2.f;
01397 F32 y_center = (F32)rect.getHeight() / 2.f;
01398
01399 F32 x_clamped = (F32)llclamp( x, 0, rect.getWidth() - arrow_size );
01400 F32 y_clamped = (F32)llclamp( y, 0, rect.getHeight() - arrow_size );
01401
01402 F32 slope = (F32)(y - y_center) / (F32)(x - x_center);
01403 F32 window_ratio = (F32)rect.getHeight() / (F32)rect.getWidth();
01404
01405 if (llabs(slope) > window_ratio && y_clamped != (F32)y)
01406 {
01407
01408 x_clamped = (y_clamped - y_center) / slope + x_center;
01409
01410 x_clamped = llclamp(x_clamped , 0.f, (F32)(rect.getWidth() - arrow_size) );
01411 }
01412 else if (x_clamped != (F32)x)
01413 {
01414
01415 y_clamped = (x_clamped - x_center) * slope + y_center;
01416
01417 y_clamped = llclamp( y_clamped, 0.f, (F32)(rect.getHeight() - arrow_size) );
01418 }
01419
01420
01421
01422
01423
01424 S32 half_arrow_size = (S32) (0.5f * arrow_size);
01425
01426 F32 angle = atan2( y + half_arrow_size - y_center, x + half_arrow_size - x_center);
01427
01428 sTrackingArrowX = llfloor(x_clamped);
01429 sTrackingArrowY = llfloor(y_clamped);
01430
01431 gl_draw_scaled_rotated_image(
01432 sTrackingArrowX,
01433 sTrackingArrowY,
01434 arrow_size, arrow_size,
01435 RAD_TO_DEG * angle,
01436 sTrackArrowImage,
01437 color);
01438 }
01439
01440 void LLWorldMapView::setDirectionPos( LLTextBox* text_box, F32 rotation )
01441 {
01442
01443
01444
01445
01446 F32 map_half_height = mRect.getHeight() * 0.5f;
01447 F32 map_half_width = mRect.getWidth() * 0.5f;
01448 F32 text_half_height = text_box->getRect().getHeight() * 0.5f;
01449 F32 text_half_width = text_box->getRect().getWidth() * 0.5f;
01450 F32 radius = llmin( map_half_height - text_half_height, map_half_width - text_half_width );
01451
01452 text_box->setOrigin(
01453 llround(map_half_width - text_half_width + radius * cos( rotation )),
01454 llround(map_half_height - text_half_height + radius * sin( rotation )) );
01455 }
01456
01457
01458 void LLWorldMapView::updateDirections()
01459 {
01460 S32 width = mRect.getWidth();
01461 S32 height = mRect.getHeight();
01462
01463 S32 text_height = mTextBoxNorth->getRect().getHeight();
01464 S32 text_width = mTextBoxNorth->getRect().getWidth();
01465
01466 const S32 PAD = 2;
01467 S32 top = height - text_height - PAD;
01468 S32 left = PAD*2;
01469 S32 bottom = PAD;
01470 S32 right = width - text_width - PAD;
01471 S32 center_x = width/2 - text_width/2;
01472 S32 center_y = height/2 - text_height/2;
01473
01474 mTextBoxNorth->setOrigin( center_x, top );
01475 mTextBoxEast->setOrigin( right, center_y );
01476 mTextBoxSouth->setOrigin( center_x, bottom );
01477 mTextBoxWest->setOrigin( left, center_y );
01478
01479
01480 text_width = mTextBoxNorthWest->getRect().getWidth();
01481 right = width - text_width - PAD;
01482
01483 mTextBoxNorthWest->setOrigin(left, top);
01484 mTextBoxNorthEast->setOrigin(right, top);
01485 mTextBoxSouthWest->setOrigin(left, bottom);
01486 mTextBoxSouthEast->setOrigin(right, bottom);
01487
01488
01489
01490
01491 }
01492
01493
01494 void LLWorldMapView::reshape( S32 width, S32 height, BOOL called_from_parent )
01495 {
01496 LLView::reshape( width, height, called_from_parent );
01497 }
01498
01499 bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track)
01500 {
01501 LLVector3 pos_view = globalPosToView(item.mPosGlobal);
01502 S32 item_x = llround(pos_view.mV[VX]);
01503 S32 item_y = llround(pos_view.mV[VY]);
01504
01505 if (x < item_x - BIG_DOT_RADIUS) return false;
01506 if (x > item_x + BIG_DOT_RADIUS) return false;
01507 if (y < item_y - BIG_DOT_RADIUS) return false;
01508 if (y > item_y + BIG_DOT_RADIUS) return false;
01509
01510 LLSimInfo* sim_info = gWorldMap->simInfoFromHandle(item.mRegionHandle);
01511 if (sim_info)
01512 {
01513 if (track)
01514 {
01515 gFloaterWorldMap->trackLocation(item.mPosGlobal);
01516 }
01517 }
01518
01519 if (track)
01520 {
01521 gFloaterWorldMap->trackGenericItem(item);
01522 }
01523
01524 item.mSelected = TRUE;
01525 *id = item.mID;
01526
01527 return true;
01528 }
01529
01530
01531 void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask,
01532 S32* hit_type,
01533 LLUUID* id)
01534 {
01535 LLVector3d pos_global = viewPosToGlobal(x, y);
01536
01537
01538
01539
01540
01541 if(gAgent.isGodlike())
01542 {
01543 pos_global.mdV[VZ] = 200.0;
01544 }
01545
01546 *hit_type = 0;
01547
01548 gWorldMap->mIsTrackingUnknownLocation = FALSE;
01549 gWorldMap->mIsTrackingDoubleClick = FALSE;
01550 gWorldMap->mIsTrackingCommit = FALSE;
01551
01552 LLWorldMap::item_info_list_t::iterator it;
01553
01554
01555 for (it = gWorldMap->mPGEvents.begin(); it != gWorldMap->mPGEvents.end(); ++it)
01556 {
01557 (*it).mSelected = FALSE;
01558 }
01559 for (it = gWorldMap->mMatureEvents.begin(); it != gWorldMap->mMatureEvents.end(); ++it)
01560 {
01561 (*it).mSelected = FALSE;
01562 }
01563 for (it = gWorldMap->mPopular.begin(); it != gWorldMap->mPopular.end(); ++it)
01564 {
01565 (*it).mSelected = FALSE;
01566 }
01567 for (it = gWorldMap->mLandForSale.begin(); it != gWorldMap->mLandForSale.end(); ++it)
01568 {
01569 (*it).mSelected = FALSE;
01570 }
01571 for (it = gWorldMap->mClassifieds.begin(); it != gWorldMap->mClassifieds.end(); ++it)
01572 {
01573 (*it).mSelected = FALSE;
01574 }
01575
01576
01577 if (gSavedSettings.getBOOL("MapShowEvents"))
01578 {
01579 for (it = gWorldMap->mPGEvents.begin(); it != gWorldMap->mPGEvents.end(); ++it)
01580 {
01581 LLItemInfo& event = *it;
01582
01583 if (checkItemHit(x, y, event, id, false))
01584 {
01585 *hit_type = MAP_ITEM_PG_EVENT;
01586 mItemPicked = TRUE;
01587 gFloaterWorldMap->trackEvent(event);
01588 return;
01589 }
01590 }
01591 if (gSavedSettings.getBOOL("ShowMatureEvents"))
01592 {
01593 for (it = gWorldMap->mMatureEvents.begin(); it != gWorldMap->mMatureEvents.end(); ++it)
01594 {
01595 LLItemInfo& event = *it;
01596
01597 if (checkItemHit(x, y, event, id, false))
01598 {
01599 *hit_type = MAP_ITEM_MATURE_EVENT;
01600 mItemPicked = TRUE;
01601 gFloaterWorldMap->trackEvent(event);
01602 return;
01603 }
01604 }
01605 }
01606 }
01607
01608 if (gSavedSettings.getBOOL("MapShowPopular"))
01609 {
01610 for (it = gWorldMap->mPopular.begin(); it != gWorldMap->mPopular.end(); ++it)
01611 {
01612 LLItemInfo& popular = *it;
01613
01614 if (checkItemHit(x, y, popular, id, true))
01615 {
01616 *hit_type = MAP_ITEM_POPULAR;
01617 mItemPicked = TRUE;
01618 return;
01619 }
01620 }
01621 }
01622
01623 if (gSavedSettings.getBOOL("MapShowLandForSale"))
01624 {
01625 for (it = gWorldMap->mLandForSale.begin(); it != gWorldMap->mLandForSale.end(); ++it)
01626 {
01627 LLItemInfo& land = *it;
01628
01629 if (checkItemHit(x, y, land, id, true))
01630 {
01631 *hit_type = MAP_ITEM_LAND_FOR_SALE;
01632 mItemPicked = TRUE;
01633 return;
01634 }
01635 }
01636 }
01637
01638 if (gSavedSettings.getBOOL("MapShowClassifieds"))
01639 {
01640 for (it = gWorldMap->mClassifieds.begin(); it != gWorldMap->mClassifieds.end(); ++it)
01641 {
01642 LLItemInfo& classified = *it;
01643
01644 if (checkItemHit(x, y, classified, id, true))
01645 {
01646 *hit_type = MAP_ITEM_CLASSIFIED;
01647 mItemPicked = TRUE;
01648 return;
01649 }
01650 }
01651 }
01652
01653
01654
01655 gFloaterWorldMap->trackLocation(pos_global);
01656 mItemPicked = FALSE;
01657
01658 *id = LLUUID::null;
01659 return;
01660 }
01661
01662
01663 BOOL outside_slop(S32 x, S32 y, S32 start_x, S32 start_y)
01664 {
01665 S32 dx = x - start_x;
01666 S32 dy = y - start_y;
01667
01668 return (dx <= -2 || 2 <= dx || dy <= -2 || 2 <= dy);
01669 }
01670
01671 BOOL LLWorldMapView::handleMouseDown( S32 x, S32 y, MASK mask )
01672 {
01673 gFocusMgr.setMouseCapture( this );
01674
01675 mMouseDownPanX = llround(sPanX);
01676 mMouseDownPanY = llround(sPanY);
01677 mMouseDownX = x;
01678 mMouseDownY = y;
01679 sHandledLastClick = TRUE;
01680 return TRUE;
01681 }
01682
01683 BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask )
01684 {
01685 if (hasMouseCapture())
01686 {
01687 if (mPanning)
01688 {
01689
01690 S32 local_x, local_y;
01691 local_x = mMouseDownX + llfloor(sPanX - mMouseDownPanX);
01692 local_y = mMouseDownY + llfloor(sPanY - mMouseDownPanY);
01693 LLRect clip_rect = mRect;
01694 clip_rect.stretch(-8);
01695 clip_rect.clipPointToRect(mMouseDownX, mMouseDownY, local_x, local_y);
01696 LLUI::setCursorPositionLocal(this, local_x, local_y);
01697
01698
01699 mPanning = FALSE;
01700
01701 mMouseDownX = 0;
01702 mMouseDownY = 0;
01703 }
01704 else
01705 {
01706
01707 S32 hit_type;
01708 LLUUID id;
01709 handleClick(x, y, mask, &hit_type, &id);
01710 }
01711 gViewerWindow->showCursor();
01712 gFocusMgr.setMouseCapture( NULL );
01713 return TRUE;
01714 }
01715 return FALSE;
01716 }
01717
01718 void LLWorldMapView::updateBlock(S32 block_x, S32 block_y)
01719 {
01720 S32 offset = block_x | (block_y * MAP_BLOCK_RES);
01721 if (!gWorldMap->mMapBlockLoaded[gWorldMap->mCurrentMap][offset])
01722 {
01723
01724 gWorldMap->sendMapBlockRequest(block_x << 3, block_y << 3, (block_x << 3) + 7, (block_y << 3) + 7);
01725 gWorldMap->mMapBlockLoaded[gWorldMap->mCurrentMap][offset] = TRUE;
01726 }
01727 }
01728
01729 void LLWorldMapView::updateVisibleBlocks()
01730 {
01731 if (gMapScale < SIM_MAP_SCALE)
01732 {
01733
01734 return;
01735 }
01736
01737 LLVector3d camera_global = gAgent.getCameraPositionGlobal();
01738
01739
01740 S32 world_center_x = S32((-sPanX / gMapScale) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
01741 S32 world_center_y = S32((-sPanY / gMapScale) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
01742
01743
01744 S32 world_block_x = world_center_x >> 3;
01745 S32 world_block_y = world_center_y >> 3;
01746
01747 for (S32 block_x = llmax(world_block_x-1, 0); block_x <= llmin(world_block_x+1, MAP_BLOCK_RES-1); ++block_x)
01748 {
01749 for (S32 block_y = llmax(world_block_y-1, 0); block_y <= llmin(world_block_y+1, MAP_BLOCK_RES-1); ++block_y)
01750 {
01751 updateBlock(block_x, block_y);
01752 }
01753 }
01754 }
01755
01756 BOOL LLWorldMapView::handleHover( S32 x, S32 y, MASK mask )
01757 {
01758 if (hasMouseCapture())
01759 {
01760 if (mPanning || outside_slop(x, y, mMouseDownX, mMouseDownY))
01761 {
01762
01763 if (!mPanning)
01764 {
01765 mPanning = TRUE;
01766 gViewerWindow->hideCursor();
01767 }
01768
01769 F32 delta_x = (F32)(gViewerWindow->getCurrentMouseDX());
01770 F32 delta_y = (F32)(gViewerWindow->getCurrentMouseDY());
01771
01772
01773 sPanX += delta_x;
01774 sPanY += delta_y;
01775 sTargetPanX = sPanX;
01776 sTargetPanY = sPanY;
01777
01778 gViewerWindow->moveCursorToCenter();
01779 }
01780
01781
01782 gViewerWindow->setCursor(UI_CURSOR_CROSS );
01783 return TRUE;
01784 }
01785 else
01786 {
01787
01788 LLVector3d pos_global = LLTracker::getTrackedPositionGlobal();
01789 if (LLTracker::isTracking(NULL)
01790 && pos_global.isExactlyZero())
01791 {
01792 gViewerWindow->setCursor( UI_CURSOR_WAIT );
01793 }
01794 else
01795 {
01796 gViewerWindow->setCursor( UI_CURSOR_CROSS );
01797 }
01798 lldebugst(LLERR_USER_INPUT) << "hover handled by LLWorldMapView" << llendl;
01799 return TRUE;
01800 }
01801 }
01802
01803
01804 BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask )
01805 {
01806 if( sHandledLastClick )
01807 {
01808 S32 hit_type;
01809 LLUUID id;
01810 handleClick(x, y, mask, &hit_type, &id);
01811
01812 switch (hit_type)
01813 {
01814 case MAP_ITEM_PG_EVENT:
01815 case MAP_ITEM_MATURE_EVENT:
01816 {
01817 gFloaterWorldMap->close();
01818
01819 char uuid_str[38];
01820 S32 event_id;
01821 id.toString(uuid_str);
01822 sscanf(&uuid_str[28], "%X", &event_id);
01823 LLFloaterDirectory::showEvents(event_id);
01824 break;
01825 }
01826 case MAP_ITEM_POPULAR:
01827 {
01828 gFloaterWorldMap->close();
01829 LLFloaterDirectory::showPopular(id);
01830 break;
01831 }
01832 case MAP_ITEM_LAND_FOR_SALE:
01833 {
01834 gFloaterWorldMap->close();
01835 LLFloaterDirectory::showLandForSale(id);
01836 break;
01837 }
01838 case MAP_ITEM_CLASSIFIED:
01839 {
01840 gFloaterWorldMap->close();
01841 LLFloaterDirectory::showClassified(id);
01842 break;
01843 }
01844 default:
01845 {
01846 if (gWorldMap->mIsTrackingUnknownLocation)
01847 {
01848 gWorldMap->mIsTrackingDoubleClick = TRUE;
01849 }
01850 else
01851 {
01852
01853 LLVector3d pos_global = viewPosToGlobal(x,y);
01854 LLSimInfo* sim_info = gWorldMap->simInfoFromPosGlobal(pos_global);
01855 if (sim_info && sim_info->mAccess != SIM_ACCESS_DOWN)
01856 {
01857 gAgent.teleportViaLocation( pos_global );
01858 }
01859 }
01860 }
01861 };
01862
01863 return TRUE;
01864 }
01865 return FALSE;
01866 }