llworldmapview.cpp

Go to the documentation of this file.
00001 
00032 #include "llviewerprecompiledheaders.h"
00033 
00034 #include "llworldmapview.h"
00035 
00036 #include "indra_constants.h"
00037 #include "llui.h"
00038 #include "llmath.h"             // clampf()
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"                                // Only for constants!
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 // Updates for agent locations.
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 // static
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 // static
00216 void LLWorldMapView::cleanupTextures()
00217 {
00218 }
00219 
00220 
00221 // static
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 // static
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 // static
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 // HELPERS
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         // animate pan if necessary
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                 // Clear the background alpha to 0
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         // Draw one image per layer
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; // better to draw nothing than the missing asset image
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                 // Find x and y position relative to camera's center.
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                 // When the view isn't panned, 0,0 = center of rectangle
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                 // discard layers that are outside the rectangle
00352                 // and discard small layers
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; // better to draw nothing than the default image
00369                 }
00370 
00371 //              LLTextureView::addDebugImage(current_image);
00372                 
00373                 // Draw using the texture.  If we don't clamp we get artifact at
00374                 // the edge.
00375                 LLViewerImage::bindTexture(current_image);
00376 
00377                 // Draw map image into RGB
00378                 //gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
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                 // draw an alpha of 1 where the sims are visible
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         // Draw one image per region, centered on the camera position.
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                 // Find x and y position relative to camera's center.
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                 // When the view isn't panned, 0,0 = center of rectangle
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                 // Switch to world map texture (if available for this region) if either:
00461                 // 1. Tiles are zoomed out small enough, or
00462                 // 2. Sim's texture has not been loaded yet
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                         // Fade in
00478                         if (info->mAlpha < 0.0f)
00479                                 info->mAlpha = 1.f; // don't fade initially
00480                         else
00481                                 info->mAlpha = lerp(info->mAlpha, 1.f, LLCriticalDamp::getInterpolant(0.15f));
00482                 }
00483                 else
00484                 {
00485                         // Fade out
00486                         if (info->mAlpha < 0.0f)
00487                                 info->mAlpha = 0.f; // don't fade initially
00488                         else
00489                                 info->mAlpha = lerp(info->mAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f));
00490                 }
00491 
00492                 // discard regions that are outside the rectangle
00493                 // and discard small regions
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                 // See if the agents need updating
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                 // Bias the priority escalation for images nearer
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 //              LLTextureView::addDebugImage(simimage);
00528 
00529                 if (sim_visible && info->mAlpha > 0.001f)
00530                 {
00531                         // Draw using the texture.  If we don't clamp we get artifact at
00532                         // the edge.
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                                 // draw an alpha of 1 where the sims are visible (except NULL sims)
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                         // Draw a transparent red square over down sims
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                 // If this is mature, and you are not, draw a line across it
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                 // Draw the region name in the lower left corner
00621                 LLFontGL* font = LLFontGL::sSansSerifSmall;
00622 
00623                 char mesg[MAX_STRING];          /* Flawfinder: ignore */
00624                 if (gMapScale < sThresholdA)
00625                 {
00626                         mesg[0] = '\0';
00627                 }
00628                 else if (gMapScale < sThresholdB)
00629                 {
00630                         //sprintf(mesg, "%d", info->mAgents);
00631                         mesg[0] = '\0';
00632                 }
00633                 else
00634                 {
00635                         //sprintf(mesg, "%d / %s (%s)",
00636                         //                      info->mAgents,
00637                         //                      info->mName.c_str(),
00638                         //                      LLViewerRegion::accessToShortString(info->mAccess) );
00639                         if (info->mAccess == SIM_ACCESS_DOWN)
00640                         {
00641                                 snprintf(mesg, MAX_STRING, "%s (Offline)", info->mName.c_str());                /* Flawfinder: ignore */
00642                         }
00643                         else
00644                         {
00645                                 snprintf(mesg, MAX_STRING, "%s", info->mName.c_str());          /* Flawfinder: ignore */
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         // Draw background rectangle
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         // Infohubs
00679         if (gSavedSettings.getBOOL("MapShowInfohubs"))   //(gMapScale >= sThresholdB)
00680         {
00681                 drawGenericItems(LLWorldMap::getInstance()->mInfohubs, sInfohubImage);
00682         }
00683 
00684         // Telehubs
00685         if (gSavedSettings.getBOOL("MapShowTelehubs"))   //(gMapScale >= sThresholdB)
00686         {
00687                 drawGenericItems(LLWorldMap::getInstance()->mTelehubs, sTelehubImage);
00688         }
00689 
00690         // Home Sweet Home
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         // Now draw your avatar after all that other stuff.
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())); // offset vertically by one line, to avoid overlap with target tracking
00725         }
00726 
00727         // Show your viewing angle
00728         drawFrustum();
00729 
00730         // Draw icons for the avatars in each region.
00731         // Drawn after your avatar so you can see nearby people.
00732         if (gSavedSettings.getBOOL("MapShowPeople"))
00733         {
00734                 drawAgents();
00735         }
00736 
00737         // Always draw tracking information
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                 // While fetching landmarks, will have 0,0,0 location for a while,
00747                 // so don't draw. JC
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                         // We know this location to be invalid
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         // turn off the scissor
00773         LLGLDisable no_scissor(GL_SCISSOR_TEST);
00774         
00775         updateDirections();
00776 
00777         LLView::draw();
00778 
00779         updateVisibleBlocks();
00780 } // end draw()
00781 
00782 
00783 //virtual
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                         // Show Individual agents (or little stacks where real agents are)
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                                 // Here's how we'd choose the color if info.mID were available but it's not being sent:
00876                                 //LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? gFriendMapColor : gAvatarMapColor;
00877                                 drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count, 3.f, gAvatarMapColor);
00878                         }
00879                         LLWorldMap::getInstance()->mNumAgents[handle] = sim_agent_count; // override mNumAgents for this sim
00880                 }
00881                 else
00882                 {
00883                         // Show agent 'stack' at center of sim
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                                 // Reduce the stack size as you zoom out - always display at lease one agent where there is one or more
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     // First the non-selected events
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     // Then the selected events
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         // Draw frustum
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         // Since we don't rotate the map, we have to rotate the frustum.
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                 // Draw triangle with more alpha in far pixels to make it 
00967                 // fade out in distance.
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);  // convert to floats from doubles
00987 
00988         pos_local.mV[VX] *= sPixelsPerMeter;
00989         pos_local.mV[VY] *= sPixelsPerMeter;
00990         // leave Z component in meters
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         // clamp text position to on-screen
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 // If you change this, then you need to change LLTracker::getTrackedPositionGlobal() as well
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; // Godly height should always be 200.
01081         }
01082         else
01083         {
01084                 pos_global.mdV[VZ] = gAgent.getPositionAgent().mV[VZ]; // Want agent's height, not camera's
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; // Bump by 1 if we're here
01111                         }
01112 
01113                         // We may not have an agent count when the map is really
01114                         // zoomed out, so don't display anything about the count. JC
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                 // Optionally show region flags
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 // Pass relative Z of 0 to draw at same level.
01151 // static
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; // horizontal bar Y
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 // Pass relative Z of 0 to draw at same level.
01189 // static
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 // Pass relative Z of 0 to draw at same level.
01213 // static
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 // Pass relative Z of 0 to draw at same level.
01225 // static
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         // render text
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         // render text
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 //static 
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 // static
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                 // clamp by y 
01375                 x_clamped = (y_clamped - y_center) / slope + x_center;
01376                 // adjust for arrow size
01377                 x_clamped  = llclamp(x_clamped , 0.f, (F32)(rect.getWidth() - arrow_size) );
01378         }
01379         else if (x_clamped != (F32)x)
01380         {
01381                 // clamp by x
01382                 y_clamped = (x_clamped - x_center) * slope + y_center;
01383                 // adjust for arrow size 
01384                 y_clamped = llclamp( y_clamped, 0.f, (F32)(rect.getHeight() - arrow_size) );
01385         }
01386 
01387         // *FIX: deal with non-square window properly.
01388         // I do not understand what this comment means -- is it actually
01389         // broken or is it correctly dealing with non-square
01390         // windows. Phoenix 2007-01-03.
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         // Rotation is in radians.
01410         // Rotation of 0 means x = 1, y = 0 on the unit circle.
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         // These have wider text boxes
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 //      S32 hint_width = mTextBoxScrollHint->getRect().getWidth();
01456 //      mTextBoxScrollHint->setOrigin( width - hint_width - text_width - 2 * PAD, 
01457 //                      PAD * 2 + text_height );
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 // Handle a click, which might be on a dot
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         // *HACK: Adjust Z values automatically for liaisons & gods so
01505         // we swoop down when they click on the map. Sadly, the P2P
01506         // branch does not pay attention to this value; however, the
01507         // Distributed Messaging branch honors it.
01508         if(gAgent.isGodlike())
01509         {
01510                 pos_global.mdV[VZ] = 200.0;
01511         }
01512 
01513         *hit_type = 0; // hit nothing
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         // clear old selected stuff
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         // Select event you clicked on
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         // If we get here, we haven't clicked on an icon
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                         // restore mouse cursor
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                         // finish the pan
01647                         mPanning = FALSE;
01648                         
01649                         mMouseDownX = 0;
01650                         mMouseDownY = 0;
01651                 }
01652                 else
01653                 {
01654                         // ignore whether we hit an event or not
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 //              llinfos << "Loading Block (" << block_x << "," << block_y << ")" << llendl;
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                 // We don't care what is loaded if we're zoomed out
01682                 return;
01683         }
01684         // check if we've loaded the 9 potentially visible zones
01685         LLVector3d camera_global = gAgent.getCameraPositionGlobal();
01686 
01687         // Convert pan to sim coordinates
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         // Find the corresponding 8x8 block
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                         // just started panning, so hide cursor
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                         // Set pan to value at start of drag + offset
01721                         sPanX += delta_x;
01722                         sPanY += delta_y;
01723                         sTargetPanX = sPanX;
01724                         sTargetPanY = sPanY;
01725 
01726                         gViewerWindow->moveCursorToCenter();
01727                 }
01728 
01729                 // doesn't matter, cursor should be hidden
01730                 gViewerWindow->setCursor(UI_CURSOR_CROSS );
01731                 return TRUE;
01732         }
01733         else
01734         {
01735                 // While we're waiting for data from the tracker, we're busy. JC
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                                 // This is an ungainly hack
01767                                 char uuid_str[38];              /* Flawfinder: ignore */
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                                         // Teleport if we got a valid location
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 }

Generated on Fri May 16 08:34:27 2008 for SecondLife by  doxygen 1.5.5