diff options
Diffstat (limited to 'indra/newview/llworldmapview.cpp')
-rw-r--r-- | indra/newview/llworldmapview.cpp | 1243 |
1 files changed, 537 insertions, 706 deletions
diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 823db027ee..60b1e59645 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -46,7 +46,6 @@ #include "llagent.h" #include "llcallingcard.h" #include "llviewercontrol.h" -#include "llcylinder.h" #include "llfloatermap.h" #include "llfloaterworldmap.h" #include "llfocusmgr.h" @@ -57,25 +56,29 @@ #include "llviewercamera.h" #include "llviewertexture.h" #include "llviewertexturelist.h" -#include "llviewermenu.h" -#include "llviewerparceloverlay.h" #include "llviewerregion.h" #include "llviewerwindow.h" -#include "llworldmap.h" -#include "lltexturefetch.h" -#include "llappviewer.h" // Only for constants! #include "lltrans.h" #include "llglheaders.h" +// Basically a C++ implementation of the OCEAN_COLOR defined in mapstitcher.py +// Please ensure consistency between those 2 files (TODO: would be better to get that color from an asset source...) +// # Constants +// OCEAN_COLOR = "#1D475F" +const F32 OCEAN_RED = (F32)(0x1D)/255.f; +const F32 OCEAN_GREEN = (F32)(0x47)/255.f; +const F32 OCEAN_BLUE = (F32)(0x5F)/255.f; + const F32 GODLY_TELEPORT_HEIGHT = 200.f; const S32 SCROLL_HINT_WIDTH = 65; const F32 BIG_DOT_RADIUS = 5.f; BOOL LLWorldMapView::sHandledLastClick = FALSE; -LLUIImagePtr LLWorldMapView::sAvatarYouSmallImage = NULL; LLUIImagePtr LLWorldMapView::sAvatarSmallImage = NULL; -LLUIImagePtr LLWorldMapView::sAvatarLargeImage = NULL; +LLUIImagePtr LLWorldMapView::sAvatarYouImage = NULL; +LLUIImagePtr LLWorldMapView::sAvatarYouLargeImage = NULL; +LLUIImagePtr LLWorldMapView::sAvatarLevelImage = NULL; LLUIImagePtr LLWorldMapView::sAvatarAboveImage = NULL; LLUIImagePtr LLWorldMapView::sAvatarBelowImage = NULL; @@ -93,35 +96,34 @@ LLUIImagePtr LLWorldMapView::sClassifiedsImage = NULL; LLUIImagePtr LLWorldMapView::sForSaleImage = NULL; LLUIImagePtr LLWorldMapView::sForSaleAdultImage = NULL; -F32 LLWorldMapView::sThresholdA = 48.f; -F32 LLWorldMapView::sThresholdB = 96.f; F32 LLWorldMapView::sPanX = 0.f; F32 LLWorldMapView::sPanY = 0.f; F32 LLWorldMapView::sTargetPanX = 0.f; F32 LLWorldMapView::sTargetPanY = 0.f; S32 LLWorldMapView::sTrackingArrowX = 0; S32 LLWorldMapView::sTrackingArrowY = 0; -F32 LLWorldMapView::sPixelsPerMeter = 1.f; -F32 CONE_SIZE = 0.6f; +bool LLWorldMapView::sVisibleTilesLoaded = false; +F32 LLWorldMapView::sMapScale = 128.f; std::map<std::string,std::string> LLWorldMapView::sStringsMap; -#define SIM_NULL_MAP_SCALE 1 // width in pixels, where we start drawing "null" sims -#define SIM_MAP_AGENT_SCALE 2 // width in pixels, where we start drawing agents -#define SIM_MAP_SCALE 1 // width in pixels, where we start drawing sim tiles - -// Updates for agent locations. -#define AGENTS_UPDATE_TIME 60.0 // in seconds +// Fetch and draw info thresholds +const F32 DRAW_TEXT_THRESHOLD = 96.f; // Don't draw text under that resolution value (res = width region in meters) +const S32 DRAW_SIMINFO_THRESHOLD = 3; // Max level for which we load or display sim level information (level in LLWorldMipmap sense) +const S32 DRAW_LANDFORSALE_THRESHOLD = 2; // Max level for which we load or display land for sale picture data (level in LLWorldMipmap sense) +// When on, draw an outline for each mipmap tile gotten from S3 +#define DEBUG_DRAW_TILE 0 void LLWorldMapView::initClass() { - sAvatarYouSmallImage = LLUI::getUIImage("map_avatar_you_8.tga"); - sAvatarSmallImage = LLUI::getUIImage("map_avatar_8.tga"); - sAvatarLargeImage = LLUI::getUIImage("map_avatar_16.tga"); - sAvatarAboveImage = LLUI::getUIImage("map_avatar_above_8.tga"); - sAvatarBelowImage = LLUI::getUIImage("map_avatar_below_8.tga"); + sAvatarSmallImage = LLUI::getUIImage("map_avatar_8.tga"); + sAvatarYouImage = LLUI::getUIImage("map_avatar_16.tga"); + sAvatarYouLargeImage = LLUI::getUIImage("map_avatar_you_32.tga"); + sAvatarLevelImage = LLUI::getUIImage("map_avatar_32.tga"); + sAvatarAboveImage = LLUI::getUIImage("map_avatar_above_32.tga"); + sAvatarBelowImage = LLUI::getUIImage("map_avatar_below_32.tga"); sHomeImage = LLUI::getUIImage("map_home.tga"); sTelehubImage = LLUI::getUIImage("map_telehub.tga"); @@ -145,9 +147,10 @@ void LLWorldMapView::initClass() // static void LLWorldMapView::cleanupClass() { - sAvatarYouSmallImage = NULL; sAvatarSmallImage = NULL; - sAvatarLargeImage = NULL; + sAvatarYouImage = NULL; + sAvatarYouLargeImage = NULL; + sAvatarLevelImage = NULL; sAvatarAboveImage = NULL; sAvatarBelowImage = NULL; @@ -167,7 +170,7 @@ void LLWorldMapView::cleanupClass() LLWorldMapView::LLWorldMapView() : LLPanel(), - mBackgroundColor( LLColor4( 4.f/255.f, 4.f/255.f, 75.f/255.f, 1.f ) ), + mBackgroundColor( LLColor4( OCEAN_RED, OCEAN_GREEN, OCEAN_BLUE, 1.f ) ), mItemPicked(FALSE), mPanning( FALSE ), mMouseDownPanX( 0 ), @@ -176,7 +179,8 @@ LLWorldMapView::LLWorldMapView() mMouseDownY( 0 ), mSelectIDStart(0) { - sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS; + //LL_INFOS("World Map") << "Creating the Map -> LLWorldMapView::LLWorldMapView()" << LL_ENDL; + clearLastClick(); } @@ -215,6 +219,7 @@ BOOL LLWorldMapView::postBuild() LLWorldMapView::~LLWorldMapView() { + //LL_INFOS("World Map") << "Destroying the map -> LLWorldMapView::~LLWorldMapView()" << LL_ENDL; cleanupTextures(); } @@ -228,14 +233,14 @@ void LLWorldMapView::cleanupTextures() // static void LLWorldMapView::setScale( F32 scale ) { - if (scale != gMapScale) + if (scale != sMapScale) { - F32 old_scale = gMapScale; + F32 old_scale = sMapScale; - gMapScale = scale; - if (gMapScale == 0.f) + sMapScale = scale; + if (sMapScale <= 0.f) { - gMapScale = 0.1f; + sMapScale = 0.1f; } F32 ratio = (scale / old_scale); @@ -243,8 +248,7 @@ void LLWorldMapView::setScale( F32 scale ) sPanY *= ratio; sTargetPanX = sPanX; sTargetPanY = sPanY; - - sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS; + sVisibleTilesLoaded = false; } } @@ -256,6 +260,7 @@ void LLWorldMapView::translatePan( S32 delta_x, S32 delta_y ) sPanY += delta_y; sTargetPanX = sPanX; sTargetPanY = sPanY; + sVisibleTilesLoaded = false; } @@ -269,18 +274,22 @@ void LLWorldMapView::setPan( S32 x, S32 y, BOOL snap ) sPanX = sTargetPanX; sPanY = sTargetPanY; } + sVisibleTilesLoaded = false; } +bool LLWorldMapView::showRegionInfo() +{ + return (LLWorldMipmap::scaleToLevel(sMapScale) <= DRAW_SIMINFO_THRESHOLD ? true : false); +} /////////////////////////////////////////////////////////////////////////////////// // HELPERS BOOL is_agent_in_region(LLViewerRegion* region, LLSimInfo* info) { - return ((region && info) && (info->mName == region->getName())); + return (region && info && info->isName(region->getName())); } - /////////////////////////////////////////////////////////////////////////////////// void LLWorldMapView::draw() @@ -292,7 +301,7 @@ void LLWorldMapView::draw() F64 current_time = LLTimer::getElapsedSeconds(); mVisibleRegions.clear(); - + // animate pan if necessary sPanX = lerp(sPanX, sTargetPanX, LLCriticalDamp::getInterpolant(0.1f)); sPanY = lerp(sPanY, sTargetPanY, LLCriticalDamp::getInterpolant(0.1f)); @@ -303,10 +312,12 @@ void LLWorldMapView::draw() const F32 half_height = F32(height) / 2.0f; LLVector3d camera_global = gAgent.getCameraPositionGlobal(); + S32 level = LLWorldMipmap::scaleToLevel(sMapScale); + LLLocalClipRect clip(getLocalRect()); { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - + glMatrixMode(GL_MODELVIEW); // Clear the background alpha to 0 @@ -319,307 +330,59 @@ void LLWorldMapView::draw() } gGL.flush(); + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.setColorMask(true, true); - gGL.setSceneBlendType(LLRender::BT_ALPHA); - - F32 layer_alpha = 1.f; - - // Draw one image per layer - for (U32 layer_idx=0; layer_idx<LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap].size(); ++layer_idx) - { - if (!LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap][layer_idx].LayerDefined) - { - continue; - } - LLWorldMapLayer *layer = &LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap][layer_idx]; - LLViewerFetchedTexture *current_image = layer->LayerImage; - - if (current_image->isMissingAsset()) - { - continue; // better to draw nothing than the missing asset image - } - - LLVector3d origin_global((F64)layer->LayerExtents.mLeft * REGION_WIDTH_METERS, (F64)layer->LayerExtents.mBottom * REGION_WIDTH_METERS, 0.f); - - // Find x and y position relative to camera's center. - LLVector3d rel_region_pos = origin_global - camera_global; - F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale; - F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale; - - F32 pix_width = gMapScale*(layer->LayerExtents.getWidth() + 1); - F32 pix_height = gMapScale*(layer->LayerExtents.getHeight() + 1); - - // When the view isn't panned, 0,0 = center of rectangle - F32 bottom = sPanY + half_height + relative_y; - F32 left = sPanX + half_width + relative_x; - F32 top = bottom + pix_height; - F32 right = left + pix_width; - F32 pixel_area = pix_width*pix_height; - // discard layers that are outside the rectangle - // and discard small layers - if (top < 0.f || - bottom > height || - right < 0.f || - left > width || - (pixel_area < 4*4)) - { - current_image->setBoostLevel(0); - continue; - } - - current_image->setBoostLevel(LLViewerTexture::BOOST_MAP); - current_image->setKnownDrawSize(llround(pix_width * LLUI::sGLScaleFactor.mV[VX]), llround(pix_height * LLUI::sGLScaleFactor.mV[VY])); - - if (!current_image->hasGLTexture()) - { - continue; // better to draw nothing than the default image - } - -// LLTextureView::addDebugImage(current_image); - - // Draw using the texture. If we don't clamp we get artifact at - // the edge. - gGL.getTexUnit(0)->bind(current_image); - - // Draw map image into RGB - //gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - gGL.flush(); - gGL.setColorMask(true, false); - gGL.color4f(1.f, 1.f, 1.f, layer_alpha); - - gGL.begin(LLRender::QUADS); - gGL.texCoord2f(0.0f, 1.0f); - gGL.vertex3f(left, top, -1.0f); - gGL.texCoord2f(0.0f, 0.0f); - gGL.vertex3f(left, bottom, -1.0f); - gGL.texCoord2f(1.0f, 0.0f); - gGL.vertex3f(right, bottom, -1.0f); - gGL.texCoord2f(1.0f, 1.0f); - gGL.vertex3f(right, top, -1.0f); - gGL.end(); - - // draw an alpha of 1 where the sims are visible - gGL.flush(); - gGL.setColorMask(false, true); - gGL.color4f(1.f, 1.f, 1.f, 1.f); - - gGL.begin(LLRender::QUADS); - gGL.texCoord2f(0.0f, 1.0f); - gGL.vertex2f(left, top); - gGL.texCoord2f(0.0f, 0.0f); - gGL.vertex2f(left, bottom); - gGL.texCoord2f(1.0f, 0.0f); - gGL.vertex2f(right, bottom); - gGL.texCoord2f(1.0f, 1.0f); - gGL.vertex2f(right, top); - gGL.end(); - } +#if 1 + // Draw the image tiles + drawMipmap(width, height); gGL.flush(); + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.setColorMask(true, true); - // there used to be an #if 1 here, but it was uncommented; perhaps marking a block of code? - F32 sim_alpha = 1.f; - - // Draw one image per region, centered on the camera position. - const S32 MAX_SIMULTANEOUS_TEX = 100; - const S32 MAX_REQUEST_PER_TICK = 5; - const S32 MIN_REQUEST_PER_TICK = 1; - S32 textures_requested_this_tick = 0; - - for (LLWorldMap::sim_info_map_t::iterator it = LLWorldMap::getInstance()->mSimInfoMap.begin(); - it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it) + // Draw per sim overlayed information (names, mature, offline...) + for (LLWorldMap::sim_info_map_t::const_iterator it = LLWorldMap::getInstance()->getRegionMap().begin(); + it != LLWorldMap::getInstance()->getRegionMap().end(); ++it) { - U64 handle = (*it).first; - LLSimInfo* info = (*it).second; + U64 handle = it->first; + LLSimInfo* info = it->second; - LLViewerFetchedTexture* simimage = info->mCurrentImage; - LLViewerFetchedTexture* overlayimage = info->mOverlayImage; - - if (gMapScale < SIM_MAP_SCALE) - { - if (simimage != NULL) simimage->setBoostLevel(0); - if (overlayimage != NULL) overlayimage->setBoostLevel(0); - continue; - } - LLVector3d origin_global = from_region_handle(handle); - LLVector3d camera_global = gAgent.getCameraPositionGlobal(); // Find x and y position relative to camera's center. LLVector3d rel_region_pos = origin_global - camera_global; - F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale; - F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale; + F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * sMapScale; + F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * sMapScale; + // Coordinates of the sim in pixels in the UI panel // When the view isn't panned, 0,0 = center of rectangle - F32 bottom = sPanY + half_height + relative_y; - F32 left = sPanX + half_width + relative_x; - F32 top = bottom + gMapScale ; - F32 right = left + gMapScale ; - - // Switch to world map texture (if available for this region) if either: - // 1. Tiles are zoomed out small enough, or - // 2. Sim's texture has not been loaded yet - F32 map_scale_cutoff = SIM_MAP_SCALE; - if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) > 0) - { - map_scale_cutoff = SIM_NULL_MAP_SCALE; - } - - info->mShowAgentLocations = (gMapScale >= SIM_MAP_AGENT_SCALE); - - bool sim_visible = - (gMapScale >= map_scale_cutoff) && - (simimage != NULL) && - (simimage->hasGLTexture()); - - if (sim_visible) - { - // Fade in - if (info->mAlpha < 0.0f) - info->mAlpha = 1.f; // don't fade initially - else - info->mAlpha = lerp(info->mAlpha, 1.f, LLCriticalDamp::getInterpolant(0.15f)); - } - else - { - // Fade out - if (info->mAlpha < 0.0f) - info->mAlpha = 0.f; // don't fade initially - else - info->mAlpha = lerp(info->mAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f)); - } - - // discard regions that are outside the rectangle - // and discard small regions - if (top < 0.f || - bottom > height || - right < 0.f || - left > width ) + F32 bottom = sPanY + half_height + relative_y; + F32 left = sPanX + half_width + relative_x; + F32 top = bottom + sMapScale ; + F32 right = left + sMapScale ; + + // Discard if region is outside the screen rectangle (not visible on screen) + if ((top < 0.f) || (bottom > height) || + (right < 0.f) || (left > width) ) { - if (simimage != NULL) simimage->setBoostLevel(0); - if (overlayimage != NULL) overlayimage->setBoostLevel(0); + // Drop the "land for sale" fetching priority since it's outside the view rectangle + info->dropImagePriority(); continue; } - if (info->mCurrentImage.isNull()) - { - if ((textures_requested_this_tick < MIN_REQUEST_PER_TICK) || - ((LLAppViewer::getTextureFetch()->getNumRequests() < MAX_SIMULTANEOUS_TEX) && - (textures_requested_this_tick < MAX_REQUEST_PER_TICK))) - { - textures_requested_this_tick++; - info->mCurrentImage = LLViewerTextureManager::getFetchedTexture(info->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); - info->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP); - simimage = info->mCurrentImage; - gGL.getTexUnit(0)->bind(simimage); - } - } - if (info->mOverlayImage.isNull() && info->mMapImageID[2].notNull()) - { - if ((textures_requested_this_tick < MIN_REQUEST_PER_TICK) || - ((LLAppViewer::getTextureFetch()->getNumRequests() < MAX_SIMULTANEOUS_TEX) && - (textures_requested_this_tick < MAX_REQUEST_PER_TICK))) - { - textures_requested_this_tick++; - info->mOverlayImage = LLViewerTextureManager::getFetchedTexture(info->mMapImageID[2], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE); - info->mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP); - overlayimage = info->mOverlayImage; - gGL.getTexUnit(0)->bind(overlayimage); - } - } + // This list is used by other methods to know which regions are indeed displayed on screen mVisibleRegions.push_back(handle); - // See if the agents need updating - if (current_time - info->mAgentsUpdateTime > AGENTS_UPDATE_TIME) - { - LLWorldMap::getInstance()->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, info->mHandle); - info->mAgentsUpdateTime = current_time; - } - - // Bias the priority escalation for images nearer - LLVector3d center_global = origin_global; - center_global.mdV[VX] += 128.0; - center_global.mdV[VY] += 128.0; - - S32 draw_size = llround(gMapScale); - if (simimage != NULL) - { - simimage->setBoostLevel(LLViewerTexture::BOOST_MAP); - simimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY])); - } - - if (overlayimage != NULL) - { - overlayimage->setBoostLevel(LLViewerTexture::BOOST_MAP); - overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY])); - } - -// LLTextureView::addDebugImage(simimage); - if (sim_visible && info->mAlpha > 0.001f) + // Update the agent count for that region if we're not too zoomed out already + if (level <= DRAW_SIMINFO_THRESHOLD) { - // Draw using the texture. If we don't clamp we get artifact at - // the edge. - LLGLSUIDefault gls_ui; - if (simimage != NULL) - gGL.getTexUnit(0)->bind(simimage); - - gGL.setSceneBlendType(LLRender::BT_ALPHA); - F32 alpha = sim_alpha * info->mAlpha; - gGL.color4f(1.f, 1.0f, 1.0f, alpha); - - gGL.begin(LLRender::QUADS); - gGL.texCoord2f(0.f, 1.f); - gGL.vertex3f(left, top, 0.f); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex3f(left, bottom, 0.f); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex3f(right, bottom, 0.f); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex3f(right, top, 0.f); - gGL.end(); - - if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->hasGLTexture()) - { - gGL.getTexUnit(0)->bind(overlayimage); - gGL.color4f(1.f, 1.f, 1.f, alpha); - gGL.begin(LLRender::QUADS); - gGL.texCoord2f(0.f, 1.f); - gGL.vertex3f(left, top, -0.5f); - gGL.texCoord2f(0.f, 0.f); - gGL.vertex3f(left, bottom, -0.5f); - gGL.texCoord2f(1.f, 0.f); - gGL.vertex3f(right, bottom, -0.5f); - gGL.texCoord2f(1.f, 1.f); - gGL.vertex3f(right, top, -0.5f); - gGL.end(); - } - - if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) == 0) - { - // draw an alpha of 1 where the sims are visible (except NULL sims) - gGL.flush(); - gGL.setSceneBlendType(LLRender::BT_REPLACE); - gGL.setColorMask(false, true); - gGL.color4f(1.f, 1.f, 1.f, 1.f); - - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - gGL.begin(LLRender::QUADS); - gGL.vertex2f(left, top); - gGL.vertex2f(left, bottom); - gGL.vertex2f(right, bottom); - gGL.vertex2f(right, top); - gGL.end(); - - gGL.flush(); - gGL.setColorMask(true, true); - } + info->updateAgentCount(current_time); } - if (info->mAccess == SIM_ACCESS_DOWN) + if (info->isDown()) { // Draw a transparent red square over down sims gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_SOURCE_ALPHA); @@ -633,18 +396,15 @@ void LLWorldMapView::draw() gGL.vertex2f(right, top); gGL.end(); } - - // As part of the AO project, we no longer want to draw access indicators; - // it's too complicated to get all the rules straight and will only + // As part of the AO project, we no longer want to draw access indicators; + // it's too complicated to get all the rules straight and will only // cause confusion. /********************** - // If this is mature, and you are not, draw a line across it - if (info->mAccess != SIM_ACCESS_DOWN - && info->mAccess > SIM_ACCESS_PG - && gAgent.isTeen()) + else if (!info->isPG() && gAgent.isTeen()) { + // If this is a mature region, and you are not, draw a line across it gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); - + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color3f(1.f, 0.f, 0.f); gGL.begin(LLRender::LINES); @@ -655,68 +415,67 @@ void LLWorldMapView::draw() gGL.end(); } **********************/ - - // Draw the region name in the lower left corner - LLFontGL* font = LLFontGL::getFontSansSerifSmall(); - - std::string mesg; - if (gMapScale < sThresholdA) + else if (gSavedSettings.getBOOL("MapShowLandForSale") && (level <= DRAW_LANDFORSALE_THRESHOLD)) { + // Draw the overlay image "Land for Sale / Land for Auction" + LLViewerFetchedTexture* overlayimage = info->getLandForSaleImage(); + if (overlayimage) + { + // Inform the fetch mechanism of the size we need + S32 draw_size = llround(sMapScale); + overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY])); + // Draw something whenever we have enough info + if (overlayimage->hasGLTexture()) + { + gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); + gGL.getTexUnit(0)->bind(overlayimage); + gGL.color4f(1.f, 1.f, 1.f, 1.f); + gGL.begin(LLRender::QUADS); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3f(left, top, -0.5f); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex3f(left, bottom, -0.5f); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3f(right, bottom, -0.5f); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex3f(right, top, -0.5f); + gGL.end(); + } + } } - else if (gMapScale < sThresholdB) + else { - // mesg = llformat( info->mAgents); + // If we're not displaying the "land for sale", drop its fetching priority + info->dropImagePriority(); } - else + + // Draw the region name in the lower left corner + if (sMapScale >= DRAW_TEXT_THRESHOLD) { - //mesg = llformat("%d / %s (%s)", - // info->mAgents, - // info->mName.c_str(), - // LLViewerRegion::accessToShortString(info->mAccess).c_str() ); - if (info->mAccess == SIM_ACCESS_DOWN) + LLFontGL* font = LLFontGL::getFontSansSerifSmall(); + std::string mesg; + if (info->isDown()) { - mesg = llformat( "%s (%s)", info->mName.c_str(), sStringsMap["offline"].c_str()); + mesg = llformat( "%s (%s)", info->getName().c_str(), sStringsMap["offline"].c_str()); } else { - mesg = info->mName; + mesg = info->getName(); } - } - - if (!mesg.empty()) - { - font->renderUTF8( - mesg, 0, - llfloor(left + 3), - llfloor(bottom + 2), - LLColor4::white, - LLFontGL::LEFT, - LLFontGL::BASELINE, - LLFontGL::NORMAL, - LLFontGL::DROP_SHADOW); - - // If map texture is still loading, - // display "Loading" placeholder text. - if ((simimage != NULL) && - simimage->getDiscardLevel() != 1 && - simimage->getDiscardLevel() != 0) + if (!mesg.empty()) { font->renderUTF8( - sStringsMap["loading"], 0, - llfloor(left + 18), - llfloor(top - 25), + mesg, 0, + llfloor(left + 3), llfloor(bottom + 2), LLColor4::white, - LLFontGL::LEFT, - LLFontGL::BASELINE, - LLFontGL::NORMAL, - LLFontGL::DROP_SHADOW); + LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW); } } } - // #endif used to be here + #endif - // there used to be an #if 1 here, but it was uncommented; perhaps marking a block of code? + #if 1 // Draw background rectangle LLGLSUIDefault gls_ui; { @@ -726,69 +485,49 @@ void LLWorldMapView::draw() gGL.color4fv( mBackgroundColor.mV ); gl_rect_2d(0, height, width, 0); } - + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.setSceneBlendType(LLRender::BT_ALPHA); - // Infohubs - if (gSavedSettings.getBOOL("MapShowInfohubs")) //(gMapScale >= sThresholdB) + // Draw item infos if we're not zoomed out too much and there's something to draw + if ((level <= DRAW_SIMINFO_THRESHOLD) && (gSavedSettings.getBOOL("MapShowInfohubs") || + gSavedSettings.getBOOL("MapShowTelehubs") || + gSavedSettings.getBOOL("MapShowLandForSale") || + gSavedSettings.getBOOL("MapShowEvents") || + gSavedSettings.getBOOL("ShowMatureEvents") || + gSavedSettings.getBOOL("ShowAdultEvents"))) { - drawGenericItems(LLWorldMap::getInstance()->mInfohubs, sInfohubImage); + drawItems(); } - // Telehubs - if (gSavedSettings.getBOOL("MapShowTelehubs")) //(gMapScale >= sThresholdB) - { - drawGenericItems(LLWorldMap::getInstance()->mTelehubs, sTelehubImage); - } - - // Home Sweet Home + // Draw the Home location (always) LLVector3d home; if (gAgent.getHomePosGlobal(&home)) { drawImage(home, sHomeImage); } - if (gSavedSettings.getBOOL("MapShowLandForSale")) - { - drawGenericItems(LLWorldMap::getInstance()->mLandForSale, sForSaleImage); - // for 1.23, we're showing normal land and adult land in the same UI; you don't - // get a choice about which ones you want. If you're currently asking for adult - // content and land you'll get the adult land. - if (gAgent.canAccessAdult()) - { - drawGenericItems(LLWorldMap::getInstance()->mLandForSaleAdult, sForSaleAdultImage); - } - } - - if (gSavedSettings.getBOOL("MapShowEvents") || - gSavedSettings.getBOOL("ShowMatureEvents") || - gSavedSettings.getBOOL("ShowAdultEvents") ) - { - drawEvents(); - } - - // Now draw your avatar after all that other stuff. + // Draw the current agent after all that other stuff. LLVector3d pos_global = gAgent.getPositionGlobal(); - drawImage(pos_global, sAvatarLargeImage); + drawImage(pos_global, sAvatarYouImage); LLVector3 pos_map = globalPosToView(pos_global); if (!pointInView(llround(pos_map.mV[VX]), llround(pos_map.mV[VY]))) { - drawTracking(pos_global, - lerp(LLColor4::yellow, LLColor4::orange, 0.4f), - TRUE, - "You are here", - "", - llround(LLFontGL::getFontSansSerifSmall()->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking + drawTracking(pos_global, + lerp(LLColor4::yellow, LLColor4::orange, 0.4f), + TRUE, + "You are here", + "", + llround(LLFontGL::getFontSansSerifSmall()->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking } - // Show your viewing angle + // Draw the current agent viewing angle drawFrustum(); // Draw icons for the avatars in each region. - // Drawn after your avatar so you can see nearby people. - if (gSavedSettings.getBOOL("MapShowPeople")) + // Drawn this after the current agent avatar so one can see nearby people + if (gSavedSettings.getBOOL("MapShowPeople") && (level <= DRAW_SIMINFO_THRESHOLD)) { drawAgents(); } @@ -798,9 +537,9 @@ void LLWorldMapView::draw() if ( LLTracker::TRACKING_AVATAR == tracking_status ) { drawTracking( LLAvatarTracker::instance().getGlobalPos(), map_track_color, TRUE, LLTracker::getLabel(), "" ); - } - else if ( LLTracker::TRACKING_LANDMARK == tracking_status - || LLTracker::TRACKING_LOCATION == tracking_status ) + } + else if ( LLTracker::TRACKING_LANDMARK == tracking_status + || LLTracker::TRACKING_LOCATION == tracking_status ) { // While fetching landmarks, will have 0,0,0 location for a while, // so don't draw. JC @@ -810,31 +549,33 @@ void LLWorldMapView::draw() drawTracking( pos_global, map_track_color, TRUE, LLTracker::getLabel(), LLTracker::getToolTip() ); } } - else if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation) + else if (LLWorldMap::getInstance()->isTracking()) { - if (LLWorldMap::getInstance()->mInvalidLocation) + if (LLWorldMap::getInstance()->isTrackingInvalidLocation()) { - // We know this location to be invalid + // We know this location to be invalid, draw a blue circle LLColor4 loading_color(0.0, 0.5, 1.0, 1.0); - drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, getString("InvalidLocation"), ""); + drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, getString("InvalidLocation"), ""); } else { + // We don't know yet what that location is, draw a throbing blue circle double value = fmod(current_time, 2); - value = 0.5 + 0.5*cos(value * 3.14159f); + value = 0.5 + 0.5*cos(value * F_PI); LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0); - drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, getString("Loading"), ""); + drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, getString("Loading"), ""); } } - // #endif used to be here - + #endif + // turn off the scissor LLGLDisable no_scissor(GL_SCISSOR_TEST); - + updateDirections(); LLView::draw(); + // Get sim info for all sims in view updateVisibleBlocks(); } // end draw() @@ -845,36 +586,182 @@ void LLWorldMapView::setVisible(BOOL visible) LLPanel::setVisible(visible); if (!visible) { - for (S32 map = 0; map < MAP_SIM_IMAGE_TYPES; map++) + // Drop the download of tiles and images priority to nil if we hide the map + LLWorldMap::getInstance()->dropImagePriorities(); + } +} + +void LLWorldMapView::drawMipmap(S32 width, S32 height) +{ + // Compute the level of the mipmap to use for the current scale level + S32 level = LLWorldMipmap::scaleToLevel(sMapScale); + // Set the tile boost level so that unused tiles get to 0 + LLWorldMap::getInstance()->equalizeBoostLevels(); + + // Render whatever we already have loaded if we haven't the current level + // complete and use it as a background (scaled up or scaled down) + if (!sVisibleTilesLoaded) + { + // Note: the (load = false) parameter avoids missing tiles to be fetched (i.e. we render what we have, no more) + // Check all the lower res levels and render them in reverse order (worse to best) + // We need to traverse all the levels as the user can zoom in very fast + for (S32 l = LLWorldMipmap::MAP_LEVELS; l > level; l--) { - for (U32 layer_idx=0; layer_idx<LLWorldMap::getInstance()->mMapLayers[map].size(); ++layer_idx) - { - if (LLWorldMap::getInstance()->mMapLayers[map][layer_idx].LayerDefined) - { - LLWorldMapLayer *layer = &LLWorldMap::getInstance()->mMapLayers[map][layer_idx]; - layer->LayerImage->setBoostLevel(0); - } - } + drawMipmapLevel(width, height, l, false); } - for (LLWorldMap::sim_info_map_t::iterator it = LLWorldMap::getInstance()->mSimInfoMap.begin(); - it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it) + // Skip the current level, as we'll do it anyway here under... + + // Just go one level down in res as it can really get too much stuff + // when zooming out and too small to see anyway... + if (level > 1) { - LLSimInfo* info = (*it).second; - if (info->mCurrentImage.notNull()) + drawMipmapLevel(width, height, level - 1, false); + } + } + else + { + //LL_INFOS("World Map") << "Render complete, don't draw background..." << LL_ENDL; + } + + // Render the current level + sVisibleTilesLoaded = drawMipmapLevel(width, height, level); + + return; +} + +// Return true if all the tiles required to render that level have been fetched or are truly missing +bool LLWorldMapView::drawMipmapLevel(S32 width, S32 height, S32 level, bool load) +{ + // Check input level + llassert (level > 0); + if (level <= 0) + return false; + + // Count tiles hit and completed + S32 completed_tiles = 0; + S32 total_tiles = 0; + + // Size in meters (global) of each tile of that level + S32 tile_width = LLWorldMipmap::MAP_TILE_SIZE * (1 << (level - 1)); + // Dimension of the screen in meter at that scale + LLVector3d pos_SW = viewPosToGlobal(0, 0); + LLVector3d pos_NE = viewPosToGlobal(width, height); + // Add external band of tiles on the outskirt so to hit the partially displayed tiles right and top + pos_NE[VX] += tile_width; + pos_NE[VY] += tile_width; + + // Iterate through the tiles on screen: we just need to ask for one tile every tile_width meters + U32 grid_x, grid_y; + for (F64 index_y = pos_SW[VY]; index_y < pos_NE[VY]; index_y += tile_width) + { + for (F64 index_x = pos_SW[VX]; index_x < pos_NE[VX]; index_x += tile_width) + { + // Compute the world coordinates of the current point + LLVector3d pos_global(index_x, index_y, pos_SW[VZ]); + // Convert to the mipmap level coordinates for that point (i.e. which tile to we hit) + LLWorldMipmap::globalToMipmap(pos_global[VX], pos_global[VY], level, &grid_x, &grid_y); + // Get the tile. Note: NULL means that the image does not exist (so it's considered "complete" as far as fetching is concerned) + LLPointer<LLViewerFetchedTexture> simimage = LLWorldMap::getInstance()->getObjectsTile(grid_x, grid_y, level, load); + if (simimage) { - info->mCurrentImage->setBoostLevel(0); + // Checks that the image has a valid texture + if (simimage->hasGLTexture()) + { + // Increment the number of completly fetched tiles + completed_tiles++; + + // Convert those coordinates (SW corner of the mipmap tile) into world (meters) coordinates + pos_global[VX] = grid_x * REGION_WIDTH_METERS; + pos_global[VY] = grid_y * REGION_WIDTH_METERS; + // Now to screen coordinates for SW corner of that tile + LLVector3 pos_screen = globalPosToView (pos_global); + F32 left = pos_screen[VX]; + F32 bottom = pos_screen[VY]; + // Compute the NE corner coordinates of the tile now + pos_global[VX] += tile_width; + pos_global[VY] += tile_width; + pos_screen = globalPosToView (pos_global); + F32 right = pos_screen[VX]; + F32 top = pos_screen[VY]; + + // Draw the tile + LLGLSUIDefault gls_ui; + gGL.getTexUnit(0)->bind(simimage.get()); + simimage->setAddressMode(LLTexUnit::TAM_CLAMP); + + gGL.setSceneBlendType(LLRender::BT_ALPHA); + gGL.color4f(1.f, 1.0f, 1.0f, 1.0f); + + gGL.begin(LLRender::QUADS); + gGL.texCoord2f(0.f, 1.f); + gGL.vertex3f(left, top, 0.f); + gGL.texCoord2f(0.f, 0.f); + gGL.vertex3f(left, bottom, 0.f); + gGL.texCoord2f(1.f, 0.f); + gGL.vertex3f(right, bottom, 0.f); + gGL.texCoord2f(1.f, 1.f); + gGL.vertex3f(right, top, 0.f); + gGL.end(); +#if DEBUG_DRAW_TILE + drawTileOutline(level, top, left, bottom, right); +#endif // DEBUG_DRAW_TILE + } + //else + //{ + // Waiting for a tile -> the level is not complete + // LL_INFOS("World Map") << "Unfetched tile. level = " << level << LL_ENDL; + //} } - if (info->mOverlayImage.notNull()) + else { - info->mOverlayImage->setBoostLevel(0); + // Unexistent tiles are counted as "completed" + completed_tiles++; } + // Increment the number of tiles in that level / screen + total_tiles++; } } + return (completed_tiles == total_tiles); +} + +// Draw lines (rectangle outline and cross) to visualize the position of the tile +// Used for debug only +void LLWorldMapView::drawTileOutline(S32 level, F32 top, F32 left, F32 bottom, F32 right) +{ + gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO); + + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + if (level == 1) + gGL.color3f(1.f, 0.f, 0.f); // red + else if (level == 2) + gGL.color3f(0.f, 1.f, 0.f); // green + else if (level == 3) + gGL.color3f(0.f, 0.f, 1.f); // blue + else if (level == 4) + gGL.color3f(1.f, 1.f, 0.f); // yellow + else if (level == 5) + gGL.color3f(1.f, 0.f, 1.f); // magenta + else if (level == 6) + gGL.color3f(0.f, 1.f, 1.f); // cyan + else if (level == 7) + gGL.color3f(1.f, 1.f, 1.f); // white + else + gGL.color3f(0.f, 0.f, 0.f); // black + gGL.begin(LLRender::LINE_STRIP); + gGL.vertex2f(left, top); + gGL.vertex2f(right, bottom); + gGL.vertex2f(left, bottom); + gGL.vertex2f(right, top); + gGL.vertex2f(left, top); + gGL.vertex2f(left, bottom); + gGL.vertex2f(right, bottom); + gGL.vertex2f(right, top); + gGL.end(); } -void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items, LLUIImagePtr image) +void LLWorldMapView::drawGenericItems(const LLSimInfo::item_info_list_t& items, LLUIImagePtr image) { - LLWorldMap::item_info_list_t::const_iterator e; + LLSimInfo::item_info_list_t::const_iterator e; for (e = items.begin(); e != items.end(); ++e) { drawGenericItem(*e, image); @@ -883,7 +770,7 @@ void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items, void LLWorldMapView::drawGenericItem(const LLItemInfo& item, LLUIImagePtr image) { - drawImage(item.mPosGlobal, image); + drawImage(item.getGlobalPosition(), image); } @@ -906,137 +793,91 @@ void LLWorldMapView::drawImageStack(const LLVector3d& global_pos, LLUIImagePtr i } } - -void LLWorldMapView::drawAgents() +void LLWorldMapView::drawItems() { - static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white); - static LLUIColor map_avatar_friend_color = LLUIColorTable::instance().getColor("MapAvatarFriendColor", LLColor4::white); - - F32 agents_scale = (gMapScale * 0.9f) / 256.f; + bool mature_enabled = gAgent.canAccessMature(); + bool adult_enabled = gAgent.canAccessAdult(); + + BOOL show_mature = mature_enabled && gSavedSettings.getBOOL("ShowMatureEvents"); + BOOL show_adult = adult_enabled && gSavedSettings.getBOOL("ShowAdultEvents"); for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter) { U64 handle = *iter; - LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle); - if (siminfo && (siminfo->mAccess == SIM_ACCESS_DOWN)) + LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle); + if ((info == NULL) || (info->isDown())) { continue; } - LLWorldMap::agent_list_map_t::iterator counts_iter = LLWorldMap::getInstance()->mAgentLocationsMap.find(handle); - if (siminfo && siminfo->mShowAgentLocations && counts_iter != LLWorldMap::getInstance()->mAgentLocationsMap.end()) + // Infohubs + if (gSavedSettings.getBOOL("MapShowInfohubs")) { - // Show Individual agents (or little stacks where real agents are) - LLWorldMap::item_info_list_t& agentcounts = counts_iter->second; - S32 sim_agent_count = 0; - for (LLWorldMap::item_info_list_t::iterator iter = agentcounts.begin(); - iter != agentcounts.end(); ++iter) - { - const LLItemInfo& info = *iter; - S32 agent_count = info.mExtra; - sim_agent_count += info.mExtra; - // Here's how we'd choose the color if info.mID were available but it's not being sent: - //LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? map_avatar_friend_color : map_avatar_color; - drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count, 3.f, map_avatar_color); - } - LLWorldMap::getInstance()->mNumAgents[handle] = sim_agent_count; // override mNumAgents for this sim + drawGenericItems(info->getInfoHub(), sInfohubImage); } - else + // Telehubs + if (gSavedSettings.getBOOL("MapShowTelehubs")) + { + drawGenericItems(info->getTeleHub(), sTelehubImage); + } + // Land for sale + if (gSavedSettings.getBOOL("MapShowLandForSale")) { - // Show agent 'stack' at center of sim - S32 num_agents = LLWorldMap::getInstance()->mNumAgents[handle]; - if (num_agents > 0) + drawGenericItems(info->getLandForSale(), sForSaleImage); + // for 1.23, we're showing normal land and adult land in the same UI; you don't + // get a choice about which ones you want. If you're currently asking for adult + // content and land you'll get the adult land. + if (gAgent.canAccessAdult()) { - LLVector3d region_center = from_region_handle(handle); - region_center[VX] += REGION_WIDTH_METERS / 2; - region_center[VY] += REGION_WIDTH_METERS / 2; - // Reduce the stack size as you zoom out - always display at lease one agent where there is one or more - S32 agent_count = (S32)(((num_agents-1) * agents_scale + (num_agents-1) * 0.1f)+.1f) + 1; - drawImageStack(region_center, sAvatarSmallImage, agent_count, 3.f, map_avatar_color); + drawGenericItems(info->getLandForSaleAdult(), sForSaleAdultImage); } } + // PG Events + if (gSavedSettings.getBOOL("MapShowEvents")) + { + drawGenericItems(info->getPGEvent(), sEventImage); + } + // Mature Events + if (show_mature) + { + drawGenericItems(info->getMatureEvent(), sEventMatureImage); + } + // Adult Events + if (show_adult) + { + drawGenericItems(info->getAdultEvent(), sEventAdultImage); + } } } - -void LLWorldMapView::drawEvents() +void LLWorldMapView::drawAgents() { - bool mature_enabled = gAgent.canAccessMature(); - bool adult_enabled = gAgent.canAccessAdult(); - - BOOL show_pg = gSavedSettings.getBOOL("MapShowEvents"); - BOOL show_mature = mature_enabled && gSavedSettings.getBOOL("ShowMatureEvents"); - BOOL show_adult = adult_enabled && gSavedSettings.getBOOL("ShowAdultEvents"); + static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white); - // First the non-selected events - LLWorldMap::item_info_list_t::const_iterator e; - if (show_pg) + for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter) { - for (e = LLWorldMap::getInstance()->mPGEvents.begin(); e != LLWorldMap::getInstance()->mPGEvents.end(); ++e) + U64 handle = *iter; + LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle); + if ((siminfo == NULL) || (siminfo->isDown())) { - if (!e->mSelected) - { - drawGenericItem(*e, sEventImage); - } + continue; } - } - if (show_mature) - { - for (e = LLWorldMap::getInstance()->mMatureEvents.begin(); e != LLWorldMap::getInstance()->mMatureEvents.end(); ++e) - { - if (!e->mSelected) - { - drawGenericItem(*e, sEventMatureImage); - } - } - } - if (show_adult) - { - for (e = LLWorldMap::getInstance()->mAdultEvents.begin(); e != LLWorldMap::getInstance()->mAdultEvents.end(); ++e) - { - if (!e->mSelected) - { - drawGenericItem(*e, sEventAdultImage); - } - } - } - // Then the selected events - if (show_pg) - { - for (e = LLWorldMap::getInstance()->mPGEvents.begin(); e != LLWorldMap::getInstance()->mPGEvents.end(); ++e) + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAgentLocation().begin(); + while (it != siminfo->getAgentLocation().end()) { - if (e->mSelected) - { - drawGenericItem(*e, sEventImage); - } + // Show Individual agents (or little stacks where real agents are) + + // Here's how we'd choose the color if info.mID were available but it's not being sent: + // LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? friend_color : avatar_color; + drawImageStack(it->getGlobalPosition(), sAvatarSmallImage, it->getCount(), 3.f, map_avatar_color); + ++it; } } - if (show_mature) - { - for (e = LLWorldMap::getInstance()->mMatureEvents.begin(); e != LLWorldMap::getInstance()->mMatureEvents.end(); ++e) - { - if (e->mSelected) - { - drawGenericItem(*e, sEventMatureImage); - } - } - } - if (show_adult) - { - for (e = LLWorldMap::getInstance()->mAdultEvents.begin(); e != LLWorldMap::getInstance()->mAdultEvents.end(); ++e) - { - if (e->mSelected) - { - drawGenericItem(*e, sEventAdultImage); - } - } - } } - void LLWorldMapView::drawFrustum() { // Draw frustum - F32 meters_to_pixels = gMapScale/ REGION_WIDTH_METERS; + F32 meters_to_pixels = sMapScale/ REGION_WIDTH_METERS; F32 horiz_fov = LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect(); F32 far_clip_meters = LLViewerCamera::getInstance()->getFar(); @@ -1077,8 +918,8 @@ LLVector3 LLWorldMapView::globalPosToView( const LLVector3d& global_pos ) LLVector3 pos_local; pos_local.setVec(relative_pos_global); // convert to floats from doubles - pos_local.mV[VX] *= sPixelsPerMeter; - pos_local.mV[VY] *= sPixelsPerMeter; + pos_local.mV[VX] *= sMapScale / REGION_WIDTH_METERS; + pos_local.mV[VY] *= sMapScale / REGION_WIDTH_METERS; // leave Z component in meters @@ -1162,7 +1003,7 @@ LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y ) LLVector3 pos_local( (F32)x, (F32)y, 0.f ); - pos_local *= ( REGION_WIDTH_METERS / gMapScale ); + pos_local *= ( REGION_WIDTH_METERS / sMapScale ); LLVector3d pos_global; pos_global.setVec( pos_local ); @@ -1183,23 +1024,20 @@ LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y ) BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask ) { LLVector3d pos_global = viewPosToGlobal(x, y); - + U64 handle = to_region_handle(pos_global); std::string tooltip_msg; - LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global); + LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle); if (info) { LLViewerRegion *region = gAgent.getRegion(); - std::string message = - llformat("%s (%s)", - info->mName.c_str(), - LLViewerRegion::accessToString(info->mAccess).c_str()); + std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str()); - if (info->mAccess != SIM_ACCESS_DOWN) + if (!info->isDown()) { - S32 agent_count = LLWorldMap::getInstance()->mNumAgents[info->mHandle]; - if (region && region->getHandle() == info->mHandle) + S32 agent_count = info->getAgentCount(); + if (region && (region->getHandle() == handle)) { ++agent_count; // Bump by 1 if we're here } @@ -1208,6 +1046,8 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask ) // zoomed out, so don't display anything about the count. JC if (agent_count > 0) { + // Merov: i18n horror!!! Even using gettext(), concatenating strings is not localizable. + // The singular/plural switch form here under might make no sense in some languages. Don't do that. message += llformat("\n%d ", agent_count); if (agent_count == 1) @@ -1223,7 +1063,7 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask ) tooltip_msg.assign( message ); // Optionally show region flags - std::string region_flags = LLViewerRegion::regionFlagsToString(info->mRegionFlags); + std::string region_flags = info->getFlagsString(); if (!region_flags.empty()) { @@ -1263,6 +1103,9 @@ static void drawDot(F32 x_pixels, F32 y_pixels, } else { + // Draw V indicator for above or below + // *TODO: Replace this vector drawing with icons + F32 left = x_pixels - dot_radius; F32 right = x_pixels + dot_radius; F32 center = (left + right) * 0.5f; @@ -1271,13 +1114,14 @@ static void drawDot(F32 x_pixels, F32 y_pixels, gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); gGL.color4fv( color.mV ); - LLUI::setLineWidth(1.5f); - F32 h_bar = relative_z > HEIGHT_THRESHOLD ? top : bottom; // horizontal bar Y + LLUI::setLineWidth(3.0f); + F32 point = relative_z > HEIGHT_THRESHOLD ? top : bottom; // Y pos of the point of the V + F32 back = relative_z > HEIGHT_THRESHOLD ? bottom : top; // Y pos of the ends of the V gGL.begin( LLRender::LINES ); - gGL.vertex2f(center, top); - gGL.vertex2f(left, h_bar); - gGL.vertex2f(right, h_bar); - gGL.vertex2f(right, bottom); + gGL.vertex2f(left, back); + gGL.vertex2f(center, point); + gGL.vertex2f(center, point); + gGL.vertex2f(right, back); gGL.end(); LLUI::setLineWidth(1.0f); } @@ -1292,7 +1136,7 @@ void LLWorldMapView::drawAvatar(F32 x_pixels, F32 dot_radius) { const F32 HEIGHT_THRESHOLD = 7.f; - LLUIImagePtr dot_image = sAvatarSmallImage; + LLUIImagePtr dot_image = sAvatarLevelImage; if(relative_z < -HEIGHT_THRESHOLD) { dot_image = sAvatarBelowImage; @@ -1301,10 +1145,12 @@ void LLWorldMapView::drawAvatar(F32 x_pixels, { dot_image = sAvatarAboveImage; } - dot_image->draw( - llround(x_pixels) - dot_image->getWidth()/2, - llround(y_pixels) - dot_image->getHeight()/2, - color); + S32 dot_width = llround(dot_radius * 2.f); + dot_image->draw(llround(x_pixels - dot_radius), + llround(y_pixels - dot_radius), + dot_width, + dot_width, + color); } // Pass relative Z of 0 to draw at same level. @@ -1565,7 +1411,7 @@ void LLWorldMapView::reshape( S32 width, S32 height, BOOL called_from_parent ) bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track) { - LLVector3 pos_view = globalPosToView(item.mPosGlobal); + LLVector3 pos_view = globalPosToView(item.getGlobalPosition()); S32 item_x = llround(pos_view.mV[VX]); S32 item_y = llround(pos_view.mV[VY]); @@ -1574,12 +1420,12 @@ bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bo if (y < item_y - BIG_DOT_RADIUS) return false; if (y > item_y + BIG_DOT_RADIUS) return false; - LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromHandle(item.mRegionHandle); + LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromHandle(item.getRegionHandle()); if (sim_info) { if (track) { - gFloaterWorldMap->trackLocation(item.mPosGlobal); + gFloaterWorldMap->trackLocation(item.getGlobalPosition()); } } @@ -1588,8 +1434,8 @@ bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bo gFloaterWorldMap->trackGenericItem(item); } - item.mSelected = TRUE; - *id = item.mID; +// item.setSelected(true); + *id = item.getUUID(); return true; } @@ -1612,108 +1458,116 @@ void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask, *hit_type = 0; // hit nothing - LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE; - LLWorldMap::getInstance()->mIsTrackingDoubleClick = FALSE; - LLWorldMap::getInstance()->mIsTrackingCommit = FALSE; + LLWorldMap::getInstance()->cancelTracking(); - LLWorldMap::item_info_list_t::iterator it; - - // clear old selected stuff - for (it = LLWorldMap::getInstance()->mPGEvents.begin(); it != LLWorldMap::getInstance()->mPGEvents.end(); ++it) - { - (*it).mSelected = FALSE; - } - for (it = LLWorldMap::getInstance()->mMatureEvents.begin(); it != LLWorldMap::getInstance()->mMatureEvents.end(); ++it) + S32 level = LLWorldMipmap::scaleToLevel(sMapScale); + // If the zoom level is not too far out already, test hits + if (level <= DRAW_SIMINFO_THRESHOLD) { - (*it).mSelected = FALSE; - } - for (it = LLWorldMap::getInstance()->mAdultEvents.begin(); it != LLWorldMap::getInstance()->mAdultEvents.end(); ++it) - { - (*it).mSelected = FALSE; - } - for (it = LLWorldMap::getInstance()->mLandForSale.begin(); it != LLWorldMap::getInstance()->mLandForSale.end(); ++it) - { - (*it).mSelected = FALSE; - } - - // Select event you clicked on - if (gSavedSettings.getBOOL("MapShowEvents")) - { - for (it = LLWorldMap::getInstance()->mPGEvents.begin(); it != LLWorldMap::getInstance()->mPGEvents.end(); ++it) - { - LLItemInfo& event = *it; - - if (checkItemHit(x, y, event, id, false)) - { - *hit_type = MAP_ITEM_PG_EVENT; - mItemPicked = TRUE; - gFloaterWorldMap->trackEvent(event); - return; - } - } - } - if (gSavedSettings.getBOOL("ShowMatureEvents")) - { - for (it = LLWorldMap::getInstance()->mMatureEvents.begin(); it != LLWorldMap::getInstance()->mMatureEvents.end(); ++it) - { - LLItemInfo& event = *it; - - if (checkItemHit(x, y, event, id, false)) - { - *hit_type = MAP_ITEM_MATURE_EVENT; - mItemPicked = TRUE; - gFloaterWorldMap->trackEvent(event); - return; - } - } - } - if (gSavedSettings.getBOOL("ShowAdultEvents")) - { - for (it = LLWorldMap::getInstance()->mAdultEvents.begin(); it != LLWorldMap::getInstance()->mAdultEvents.end(); ++it) - { - LLItemInfo& event = *it; - - if (checkItemHit(x, y, event, id, false)) - { - *hit_type = MAP_ITEM_ADULT_EVENT; - mItemPicked = TRUE; - gFloaterWorldMap->trackEvent(event); - return; - } - } - } - - if (gSavedSettings.getBOOL("MapShowLandForSale")) - { - for (it = LLWorldMap::getInstance()->mLandForSale.begin(); it != LLWorldMap::getInstance()->mLandForSale.end(); ++it) - { - LLItemInfo& land = *it; + bool show_mature = gAgent.canAccessMature() && gSavedSettings.getBOOL("ShowMatureEvents"); + bool show_adult = gAgent.canAccessAdult() && gSavedSettings.getBOOL("ShowAdultEvents"); - if (checkItemHit(x, y, land, id, true)) - { - *hit_type = MAP_ITEM_LAND_FOR_SALE; - mItemPicked = TRUE; - return; - } - } - - for (it = LLWorldMap::getInstance()->mLandForSaleAdult.begin(); it != LLWorldMap::getInstance()->mLandForSaleAdult.end(); ++it) + // Test hits if trackable data are displayed, otherwise, we don't even bother + if (gSavedSettings.getBOOL("MapShowEvents") || show_mature || show_adult || gSavedSettings.getBOOL("MapShowLandForSale")) { - LLItemInfo& land = *it; - - if (checkItemHit(x, y, land, id, true)) + // Iterate through the visible regions + for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter) { - *hit_type = MAP_ITEM_LAND_FOR_SALE_ADULT; - mItemPicked = TRUE; - return; + U64 handle = *iter; + LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle); + if ((siminfo == NULL) || (siminfo->isDown())) + { + continue; + } + // If on screen check hits with the visible item lists + if (gSavedSettings.getBOOL("MapShowEvents")) + { + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getPGEvent().begin(); + while (it != siminfo->getPGEvent().end()) + { + LLItemInfo event = *it; + if (checkItemHit(x, y, event, id, false)) + { + *hit_type = MAP_ITEM_PG_EVENT; + mItemPicked = TRUE; + gFloaterWorldMap->trackEvent(event); + return; + } + ++it; + } + } + if (show_mature) + { + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getMatureEvent().begin(); + while (it != siminfo->getMatureEvent().end()) + { + LLItemInfo event = *it; + if (checkItemHit(x, y, event, id, false)) + { + *hit_type = MAP_ITEM_MATURE_EVENT; + mItemPicked = TRUE; + gFloaterWorldMap->trackEvent(event); + return; + } + ++it; + } + } + if (show_adult) + { + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAdultEvent().begin(); + while (it != siminfo->getAdultEvent().end()) + { + LLItemInfo event = *it; + if (checkItemHit(x, y, event, id, false)) + { + *hit_type = MAP_ITEM_ADULT_EVENT; + mItemPicked = TRUE; + gFloaterWorldMap->trackEvent(event); + return; + } + ++it; + } + } + if (gSavedSettings.getBOOL("MapShowLandForSale")) + { + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getLandForSale().begin(); + while (it != siminfo->getLandForSale().end()) + { + LLItemInfo event = *it; + if (checkItemHit(x, y, event, id, true)) + { + *hit_type = MAP_ITEM_LAND_FOR_SALE; + mItemPicked = TRUE; + return; + } + ++it; + } + // for 1.23, we're showing normal land and adult land in the same UI; you don't + // get a choice about which ones you want. If you're currently asking for adult + // content and land you'll get the adult land. + if (gAgent.canAccessAdult()) + { + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getLandForSaleAdult().begin(); + while (it != siminfo->getLandForSaleAdult().end()) + { + LLItemInfo event = *it; + if (checkItemHit(x, y, event, id, true)) + { + *hit_type = MAP_ITEM_LAND_FOR_SALE_ADULT; + mItemPicked = TRUE; + return; + } + ++it; + } + } + } } } } - // If we get here, we haven't clicked on an icon + // If we get here, we haven't clicked on anything gFloaterWorldMap->trackLocation(pos_global); mItemPicked = FALSE; - *id = LLUUID::null; return; } @@ -1774,59 +1628,36 @@ BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask ) return FALSE; } -U32 LLWorldMapView::updateBlock(S32 block_x, S32 block_y) +void LLWorldMapView::updateVisibleBlocks() { - U32 blocks_requested = 0; - S32 offset = block_x | (block_y * MAP_BLOCK_RES); - if (!LLWorldMap::getInstance()->mMapBlockLoaded[LLWorldMap::getInstance()->mCurrentMap][offset]) + if (LLWorldMipmap::scaleToLevel(sMapScale) > DRAW_SIMINFO_THRESHOLD) { -// llinfos << "Loading Block (" << block_x << "," << block_y << ")" << llendl; - LLWorldMap::getInstance()->sendMapBlockRequest(block_x << 3, block_y << 3, (block_x << 3) + 7, (block_y << 3) + 7); - LLWorldMap::getInstance()->mMapBlockLoaded[LLWorldMap::getInstance()->mCurrentMap][offset] = TRUE; - blocks_requested++; + // If we're zoomed out too much, we just don't load all those sim info: too much! + return; } - return blocks_requested; -} -U32 LLWorldMapView::updateVisibleBlocks() -{ - if (gMapScale < SIM_MAP_SCALE) - { - // We don't care what is loaded if we're zoomed out - return 0; - } + // Load the blocks visible in the current World Map view + // Get the World Map view coordinates and boundaries LLVector3d camera_global = gAgent.getCameraPositionGlobal(); - - F32 pixels_per_region = gMapScale; const S32 width = getRect().getWidth(); const S32 height = getRect().getHeight(); - // Convert pan to sim coordinates - S32 world_center_x_lo = S32(((-sPanX - width/2) / pixels_per_region) + (camera_global.mdV[0] / REGION_WIDTH_METERS)); - S32 world_center_x_hi = S32(((-sPanX + width/2) / pixels_per_region) + (camera_global.mdV[0] / REGION_WIDTH_METERS)); - S32 world_center_y_lo = S32(((-sPanY - height/2) / pixels_per_region) + (camera_global.mdV[1] / REGION_WIDTH_METERS)); - S32 world_center_y_hi = S32(((-sPanY + height/2)/ pixels_per_region) + (camera_global.mdV[1] / REGION_WIDTH_METERS)); - - // Find the corresponding 8x8 block - S32 world_block_x_lo = world_center_x_lo >> 3; - S32 world_block_x_hi = world_center_x_hi >> 3; - S32 world_block_y_lo = world_center_y_lo >> 3; - S32 world_block_y_hi = world_center_y_hi >> 3; - - U32 blocks_requested = 0; - const U32 max_blocks_requested = 9; + const F32 half_width = F32(width) / 2.0f; + const F32 half_height = F32(height) / 2.0f; - for (S32 block_x = llmax(world_block_x_lo, 0); block_x <= llmin(world_block_x_hi, MAP_BLOCK_RES-1); ++block_x) - { - for (S32 block_y = llmax(world_block_y_lo, 0); block_y <= llmin(world_block_y_hi, MAP_BLOCK_RES-1); ++block_y) - { - blocks_requested += updateBlock(block_x, block_y); - if (blocks_requested >= max_blocks_requested) - return blocks_requested; - } - } - return blocks_requested; -} + // Compute center into sim grid coordinates + S32 world_center_x = S32((-sPanX / sMapScale) + (camera_global.mdV[0] / REGION_WIDTH_METERS)); + S32 world_center_y = S32((-sPanY / sMapScale) + (camera_global.mdV[1] / REGION_WIDTH_METERS)); + + // Compute the boundaries into sim grid coordinates + S32 world_left = world_center_x - S32(half_width / sMapScale) - 1; + S32 world_right = world_center_x + S32(half_width / sMapScale) + 1; + S32 world_bottom = world_center_y - S32(half_height / sMapScale) - 1; + S32 world_top = world_center_y + S32(half_height / sMapScale) + 1; + + //LL_INFOS("World Map") << "LLWorldMapView::updateVisibleBlocks() : sMapScale = " << sMapScale << ", left = " << world_left << ", right = " << world_right << ", bottom = " << world_bottom << ", top = " << world_top << LL_ENDL; + LLWorldMap::getInstance()->updateRegions(world_left, world_bottom, world_right, world_top); +} BOOL LLWorldMapView::handleHover( S32 x, S32 y, MASK mask ) { @@ -1915,16 +1746,16 @@ BOOL LLWorldMapView::handleDoubleClick( S32 x, S32 y, MASK mask ) } default: { - if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation) + if (LLWorldMap::getInstance()->isTracking()) { - LLWorldMap::getInstance()->mIsTrackingDoubleClick = TRUE; + LLWorldMap::getInstance()->setTrackingDoubleClick(); } else { // Teleport if we got a valid location LLVector3d pos_global = viewPosToGlobal(x,y); LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global); - if (sim_info && sim_info->mAccess != SIM_ACCESS_DOWN) + if (sim_info && !sim_info->isDown()) { gAgent.teleportViaLocation( pos_global ); } |