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