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

Generated on Thu Jul 1 06:09:47 2010 for Second Life Viewer by  doxygen 1.4.7