From 4d3a65ebb786a2d6869198fd385515114829d073 Mon Sep 17 00:00:00 2001 From: Siana Gearz Date: Thu, 24 Feb 2011 18:36:06 +0100 Subject: [PATCH] Revert Old Map --- indra/newview/CMakeLists.txt | 6 +- indra/newview/app_settings/settings.xml | 37 +- indra/newview/llagent.cpp | 39 +- indra/newview/llfloaterworldmap.cpp | 181 +-- indra/newview/llfloaterworldmap.h | 11 +- indra/newview/llstartup.cpp | 9 +- indra/newview/llurldispatcher.cpp | 8 +- indra/newview/llviewermenu.cpp | 6 +- indra/newview/llworldmap.cpp | 1279 ++++++----------- indra/newview/llworldmap.h | 334 +++-- indra/newview/llworldmapmessage.cpp | 274 ++++ indra/newview/llworldmapmessage.h | 82 ++ indra/newview/llworldmapview.cpp | 1113 +++++++------- indra/newview/llworldmapview.h | 41 +- indra/newview/llworldmipmap.cpp | 294 ++++ indra/newview/llworldmipmap.h | 100 ++ .../default/xui/en-us/floater_world_map.xml | 6 +- .../skins/default/xui/en-us/strings.xml | 7 - 18 files changed, 1963 insertions(+), 1864 deletions(-) create mode 100644 indra/newview/llworldmapmessage.cpp create mode 100644 indra/newview/llworldmapmessage.h create mode 100644 indra/newview/llworldmipmap.cpp create mode 100644 indra/newview/llworldmipmap.h diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3dcf25c0d..26fc2e516 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -494,7 +494,8 @@ set(viewer_SOURCE_FILES llwlparamset.cpp llworld.cpp llworldmap.cpp - llmapresponders.cpp + llworldmapmessage.cpp + llworldmipmap.cpp llworldmapview.cpp llxmlrpctransaction.cpp noise.cpp @@ -968,7 +969,8 @@ set(viewer_HEADER_FILES llwlparamset.h llworld.h llworldmap.h - llmapresponders.h + llworldmapmessage.h + llworldmipmap.h llworldmapview.h llxmlrpctransaction.h macmain.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index d10ceb0d8..37e59d2d7 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -7275,17 +7275,6 @@ Value http://map.secondlife.com.s3.amazonaws.com/ - UseWebMapTiles - - Comment - Use web map tiles whenever possible - Persist - 1 - Type - Boolean - Value - 1 - MapOverlayIndex Comment @@ -7319,10 +7308,10 @@ Value 1 - MapShowPGEvents + MapShowEvents Comment - Show PG events on world map + Show events on world map Persist 1 Type @@ -7330,28 +7319,6 @@ Value 1 - MapShowMatureEvents - - Comment - Show mature events on world map - Persist - 1 - Type - Boolean - Value - 0 - - MapShowAdultEvents - - Comment - Show adult events on world map - Persist - 1 - Type - Boolean - Value - 0 - MapShowInfohubs Comment diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 1e455d9b3..adb0fe2f5 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -111,7 +111,6 @@ #include "lltoolmgr.h" #include "lltoolpie.h" #include "lltoolview.h" -#include "lltrans.h" #include "llui.h" // for make_ui_sound #include "llurldispatcher.h" #include "llviewercamera.h" @@ -140,6 +139,9 @@ #include "llviewerjoystick.h" #include "llfollowcam.h" +#include "llworldmapmessage.h" +#include "llfollowcam.h" + // [RLVa:KB] - Checked: 2010-09-27 (RLVa-1.1.3b) #include "rlvhandler.h" #include "rlvinventory.h" @@ -8512,26 +8514,21 @@ std::string LLAgent::getCapability(const std::string& name) const } return iter->second; } +// void LLAgent::showLureDestination(const std::string fromname, const int global_x, const int global_y, const int x, const int y, const int z, const std::string maturity) { const LLVector3d posglobal = LLVector3d(F64(global_x), F64(global_y), F64(0)); LLSimInfo* siminfo; siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(posglobal); - std::string sim_name; - LLWorldMap::getInstance()->simNameFromPosGlobal( posglobal, sim_name ); - if(siminfo) { - llinfos << fromname << "'s teleport lure is to " << sim_name << " (" << maturity << ")" << llendl; - LLStringUtil::format_map_t args; - args["[NAME]"] = fromname; - args["[DESTINATION]"] = LLURLDispatcher::buildSLURL(sim_name.c_str(), S32(x), S32(y), S32(z)); - std::string msg = LLTrans::getString("TeleportLureMaturity", args); - if (maturity != "") - { + llinfos << fromname << "'s teleport lure is to " << siminfo->getName() << " (" << maturity << ")" << llendl; + std::string url = LLURLDispatcher::buildSLURL(siminfo->getName(), S32(x), S32(y), S32(z)); + std::string msg; + msg = llformat("%s's teleport lure is to %s", fromname.c_str(), url.c_str()); + if(maturity != "") msg.append(llformat(" (%s)", maturity.c_str())); - } LLChat chat(msg); LLFloaterChat::addChat(chat); } @@ -8546,7 +8543,7 @@ void LLAgent::showLureDestination(const std::string fromname, const int global_x LLAgent::lure_y = y; LLAgent::lure_z = z; LLAgent::lure_maturity = maturity; - LLWorldMap::getInstance()->sendMapBlockRequest(lure_global_x, lure_global_y, lure_global_x, lure_global_y, true); + LLWorldMapMessage::getInstance()->sendMapBlockRequest(lure_global_x, lure_global_y, lure_global_x, lure_global_y, true); } } @@ -8555,19 +8552,14 @@ void LLAgent::onFoundLureDestination() LLAgent::lure_show = FALSE; LLSimInfo* siminfo; siminfo = LLWorldMap::getInstance()->simInfoFromPosGlobal(LLAgent::lure_posglobal); - std::string sim_name; - LLWorldMap::getInstance()->simNameFromPosGlobal(LLAgent::lure_posglobal, sim_name ); if(siminfo) { - llinfos << LLAgent::lure_name << "'s teleport lure is to " << sim_name << " (" << LLAgent::lure_maturity << ")" << llendl; - LLStringUtil::format_map_t args; - args["[NAME]"] = LLAgent::lure_name; - args["[DESTINATION]"] = LLURLDispatcher::buildSLURL(sim_name, S32(LLAgent::lure_x), S32(LLAgent::lure_y), S32(LLAgent::lure_z)); - std::string msg = LLTrans::getString("TeleportOfferMaturity", args); - if (LLAgent::lure_maturity != "") - { + llinfos << LLAgent::lure_name << "'s teleport lure is to " << siminfo->getName() << " (" << LLAgent::lure_maturity << ")" << llendl; + std::string url = LLURLDispatcher::buildSLURL(siminfo->getName(), S32(LLAgent::lure_x), S32(LLAgent::lure_y), S32(LLAgent::lure_z)); + std::string msg; + msg = llformat("%s's teleport lure is to %s", LLAgent::lure_name.c_str(), url.c_str()); + if(LLAgent::lure_maturity != "") msg.append(llformat(" (%s)", LLAgent::lure_maturity.c_str())); - } LLChat chat(msg); LLFloaterChat::addChat(chat); } @@ -8575,6 +8567,7 @@ void LLAgent::onFoundLureDestination() llwarns << "Grand scheme failed" << llendl; } +// // EOF diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp index f48c2fa0d..424be7380 100644 --- a/indra/newview/llfloaterworldmap.cpp +++ b/indra/newview/llfloaterworldmap.cpp @@ -61,7 +61,9 @@ #include "llviewermenu.h" #include "llviewerregion.h" #include "llviewerstats.h" +#include "llviewerimage.h" #include "llworldmap.h" +#include "llworldmapmessage.h" #include "llworldmapview.h" #include "lluictrlfactory.h" #include "llappviewer.h" @@ -79,6 +81,12 @@ //--------------------------------------------------------------------------- static const F32 MAP_ZOOM_TIME = 0.2f; +// Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed +// width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across +// sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit. +// Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window. +static const S32 MAX_VISIBLE_REGIONS = 512; + enum EPanDirection { PAN_UP, @@ -167,7 +175,6 @@ LLFloaterWorldMap::LLFloaterWorldMap() { LLCallbackMap::map_t factory_map; factory_map["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL); - factory_map["terrain_mapview"] = LLCallbackMap(createWorldMapView, NULL); LLUICtrlFactory::getInstance()->buildFloater(this, "floater_world_map.xml", &factory_map); } @@ -179,30 +186,7 @@ void* LLFloaterWorldMap::createWorldMapView(void* data) BOOL LLFloaterWorldMap::postBuild() { - mTabs = getChild("maptab"); - if (!mTabs) return FALSE; - - LLPanel *panel; - - panel = mTabs->getChild("objects_mapview"); - if (panel) - { - mTabs->setTabChangeCallback(panel, onCommitBackground); - mTabs->setTabUserData(panel, this); - } - panel = mTabs->getChild("terrain_mapview"); - if (panel) - { - mTabs->setTabChangeCallback(panel, onCommitBackground); - mTabs->setTabUserData(panel, this); - } - - // The following callback syncs the worlmap tabs with the images. - // Commented out since it was crashing when LLWorldMap became a singleton. - // We should be fine without it but override the onOpen method and put it - // there if it turns out to be needed. -MG - // - //onCommitBackground((void*)this, false); + mPanel = getChild("objects_mapview"); childSetCommitCallback("friend combo", onAvatarComboCommit, this); @@ -263,7 +247,7 @@ BOOL LLFloaterWorldMap::postBuild() LLFloaterWorldMap::~LLFloaterWorldMap() { // All cleaned up by LLView destructor - mTabs = NULL; + mPanel = NULL; // Inventory deletes all observers on shutdown mInventory = NULL; @@ -296,7 +280,7 @@ void LLFloaterWorldMap::show(void*, BOOL center_on_target) gFloaterWorldMap->open(); /* Flawfinder: ignore */ LLWorldMapView* map_panel; - map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel(); + map_panel = (LLWorldMapView*)gFloaterWorldMap->mPanel; map_panel->clearLastClick(); if (!was_visible) @@ -308,15 +292,8 @@ void LLFloaterWorldMap::show(void*, BOOL center_on_target) } map_panel->updateVisibleBlocks(); - // Reload the agent positions when we show the window - LLWorldMap::getInstance()->eraseItems(); - - // Reload any maps that may have changed - LLWorldMap::getInstance()->clearSimFlags(); - - const S32 panel_num = gFloaterWorldMap->mTabs->getCurrentPanelIndex(); - const bool request_from_sim = true; - LLWorldMap::getInstance()->setCurrentLayer(panel_num, request_from_sim); + // Reload items as they may have changed + LLWorldMap::getInstance()->reloadItems(); // We may already have a bounding box for the regions of the world, // so use that to adjust the view. @@ -350,9 +327,7 @@ void LLFloaterWorldMap::show(void*, BOOL center_on_target) // static void LLFloaterWorldMap::reloadIcons(void*) { - LLWorldMap::getInstance()->eraseItems(); - - LLWorldMap::getInstance()->sendMapLayerRequest(); + LLWorldMap::getInstance()->reloadItems(); } @@ -390,7 +365,7 @@ void LLFloaterWorldMap::setVisible( BOOL visible ) if( !visible ) { - // While we're not visible, discard the overlay images we're using + // While we're not visible, discard the image tiles and overlays LLWorldMap::getInstance()->clearImageRefs(); } } @@ -427,12 +402,6 @@ BOOL LLFloaterWorldMap::handleScrollWheel(S32 x, S32 y, S32 clicks) void LLFloaterWorldMap::reshape( S32 width, S32 height, BOOL called_from_parent ) { LLFloater::reshape( width, height, called_from_parent ); - - // Might have changed size of world display area - // JC: Technically, this is correct, but it makes the slider "pop" - // if you resize the window, then draw the slider. Just leaving it - // the way it was when you opened the window seems better. - // adjustZoomSliderBounds(); } @@ -511,7 +480,7 @@ void LLFloaterWorldMap::draw() childSetEnabled("Teleport", (BOOL)tracking_status); // childSetEnabled("Clear", (BOOL)tracking_status); - childSetEnabled("Show Destination", (BOOL)tracking_status || LLWorldMap::getInstance()->mIsTrackingUnknownLocation); + childSetEnabled("Show Destination", (BOOL)tracking_status || LLWorldMap::getInstance()->isTracking()); childSetEnabled("copy_slurl", (mSLURL.size() > 0) ); setMouseOpaque(TRUE); @@ -532,6 +501,18 @@ void LLFloaterWorldMap::draw() F32 map_scale = 256.f*pow(2.f, mCurZoomVal); LLWorldMapView::setScale( map_scale ); + // Enable/disable checkboxes depending on the zoom level + // If above threshold level (i.e. low res) -> Disable all checkboxes + // If under threshold level (i.e. high res) -> Enable all checkboxes + bool enable = LLWorldMapView::showRegionInfo(); + childSetEnabled("people_chk", enable); + childSetEnabled("infohub_chk", enable); + childSetEnabled("telehubchk", enable); + childSetEnabled("land_for_sale_chk", enable); + childSetEnabled("event_chk", enable); + childSetEnabled("event_mature_chk", enable); + childSetEnabled("event_adult_chk", enable); + LLFloater::draw(); } @@ -619,14 +600,14 @@ void LLFloaterWorldMap::trackLandmark( const LLUUID& landmark_item_id ) void LLFloaterWorldMap::trackEvent(const LLItemInfo &event_info) { mTrackedStatus = LLTracker::TRACKING_LOCATION; - LLTracker::trackLocation(event_info.mPosGlobal, event_info.mName, event_info.mToolTip, LLTracker::LOCATION_EVENT); + LLTracker::trackLocation(event_info.getGlobalPosition(), event_info.getName(), event_info.getToolTip(), LLTracker::LOCATION_EVENT); setDefaultBtn("Teleport"); } void LLFloaterWorldMap::trackGenericItem(const LLItemInfo &item) { mTrackedStatus = LLTracker::TRACKING_LOCATION; - LLTracker::trackLocation(item.mPosGlobal, item.mName, item.mToolTip, LLTracker::LOCATION_ITEM); + LLTracker::trackLocation(item.getGlobalPosition(), item.getName(), item.getToolTip(), LLTracker::LOCATION_ITEM); setDefaultBtn("Teleport"); } @@ -635,29 +616,27 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global); if (!sim_info) { - LLWorldMap::getInstance()->mIsTrackingUnknownLocation = TRUE; - LLWorldMap::getInstance()->mInvalidLocation = FALSE; - LLWorldMap::getInstance()->mUnknownLocation = pos_global; + // We haven't found a region for that point yet, leave the tracking to the world map + LLWorldMap::getInstance()->setTracking(pos_global); LLTracker::stopTracking(NULL); S32 world_x = S32(pos_global.mdV[0] / 256); S32 world_y = S32(pos_global.mdV[1] / 256); - LLWorldMap::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true); + LLWorldMapMessage::getInstance()->sendMapBlockRequest(world_x, world_y, world_x, world_y, true); setDefaultBtn(""); return; } - if (sim_info->mAccess == SIM_ACCESS_DOWN) + if (sim_info->isDown()) { - // Down sim. Show the blue circle of death! - LLWorldMap::getInstance()->mIsTrackingUnknownLocation = TRUE; - LLWorldMap::getInstance()->mUnknownLocation = pos_global; - LLWorldMap::getInstance()->mInvalidLocation = TRUE; + // Down region. Show the blue circle of death! + // i.e. let the world map that this and tell it it's invalid + LLWorldMap::getInstance()->setTracking(pos_global); + LLWorldMap::getInstance()->setTrackingInvalid(); LLTracker::stopTracking(NULL); setDefaultBtn(""); return; } - std::string sim_name; - LLWorldMap::getInstance()->simNameFromPosGlobal( pos_global, sim_name ); + std::string sim_name = sim_info->getName(); F32 region_x = (F32)fmod( pos_global.mdV[VX], (F64)REGION_WIDTH_METERS ); F32 region_y = (F32)fmod( pos_global.mdV[VY], (F64)REGION_WIDTH_METERS ); std::string full_name = llformat("%s (%d, %d, %d)", @@ -672,9 +651,7 @@ void LLFloaterWorldMap::trackLocation(const LLVector3d& pos_global) std::string tooltip(""); mTrackedStatus = LLTracker::TRACKING_LOCATION; LLTracker::trackLocation(pos_global, full_name, tooltip); - LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE; - LLWorldMap::getInstance()->mIsTrackingDoubleClick = FALSE; - LLWorldMap::getInstance()->mIsTrackingCommit = FALSE; + LLWorldMap::getInstance()->cancelTracking(); // The floater is taking over the tracking setDefaultBtn("Teleport"); } @@ -803,9 +780,9 @@ void LLFloaterWorldMap::trackURL(const std::string& region_name, S32 x_coord, S3 // pass sim name to combo box gFloaterWorldMap->mCompletingRegionName = region_name; - LLWorldMap::getInstance()->sendNamedRegionRequest(region_name); + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name); LLStringUtil::toLower(gFloaterWorldMap->mCompletingRegionName); - LLWorldMap::getInstance()->mIsTrackingCommit = TRUE; + LLWorldMap::getInstance()->setTrackingCommit(); } } @@ -986,7 +963,7 @@ void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui) { childSetValue("spin z", 0); } - LLWorldMap::getInstance()->mIsTrackingCommit = FALSE; + LLWorldMap::getInstance()->cancelTracking(); mCompletingRegionName = ""; mExactMatch = FALSE; } @@ -1023,18 +1000,16 @@ void LLFloaterWorldMap::clearAvatarSelection(BOOL clear_ui) // can see the whole world, plus a little. void LLFloaterWorldMap::adjustZoomSliderBounds() { - // World size in regions - S32 world_width_regions = LLWorldMap::getInstance()->getWorldWidth() / REGION_WIDTH_UNITS; - S32 world_height_regions = LLWorldMap::getInstance()->getWorldHeight() / REGION_WIDTH_UNITS; - - // Pad the world size a little bit, so we have a nice border on - // the edge - world_width_regions++; - world_height_regions++; + // Merov: we switched from using the "world size" (which varies depending where the user went) to a fixed + // width of 512 regions max visible at a time. This makes the zoom slider works in a consistent way across + // sessions and doesn't prevent the user to pan the world if it was to grow a lot beyond that limit. + // Currently (01/26/09), this value allows the whole grid to be visible in a 1024x1024 window. + S32 world_width_regions = MAX_VISIBLE_REGIONS; + S32 world_height_regions = MAX_VISIBLE_REGIONS; // Find how much space we have to display the world LLWorldMapView* map_panel; - map_panel = (LLWorldMapView*)mTabs->getCurrentPanel(); + map_panel = (LLWorldMapView*)mPanel; LLRect view_rect = map_panel->getRect(); // View size in pixels @@ -1084,7 +1059,7 @@ void LLFloaterWorldMap::onPanBtn( void* userdata ) } LLWorldMapView* map_panel; - map_panel = (LLWorldMapView*)gFloaterWorldMap->mTabs->getCurrentPanel(); + map_panel = (LLWorldMapView*)gFloaterWorldMap->mPanel; map_panel->translatePan( pan_x, pan_y ); } @@ -1284,16 +1259,16 @@ void LLFloaterWorldMap::onLocationCommit( void* userdata ) LLStringUtil::toLower(str); gFloaterWorldMap->mCompletingRegionName = str; - LLWorldMap::getInstance()->mIsTrackingCommit = TRUE; + LLWorldMap::getInstance()->setTrackingCommit(); self->mExactMatch = FALSE; if (str.length() >= 3) { - LLWorldMap::getInstance()->sendNamedRegionRequest(str); + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str); } else { str += "#"; - LLWorldMap::getInstance()->sendNamedRegionRequest(str); + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str); } } @@ -1304,7 +1279,7 @@ void LLFloaterWorldMap::onClearBtn(void* data) LLFloaterWorldMap* self = (LLFloaterWorldMap*)data; self->mTrackedStatus = LLTracker::TRACKING_NOTHING; LLTracker::stopTracking((void *)(intptr_t)TRUE); - LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE; + LLWorldMap::getInstance()->cancelTracking(); self->mSLURL = ""; // Clear the SLURL since it's invalid self->mSetToUserPosition = TRUE; // Revert back to the current user position } @@ -1379,9 +1354,9 @@ void LLFloaterWorldMap::centerOnTarget(BOOL animate) pos_global = LLTracker::getTrackedPositionGlobal() - gAgent.getCameraPositionGlobal(); } } - else if(LLWorldMap::getInstance()->mIsTrackingUnknownLocation) + else if(LLWorldMap::getInstance()->isTracking()) { - pos_global = LLWorldMap::getInstance()->mUnknownLocation - gAgent.getCameraPositionGlobal();; + pos_global = LLWorldMap::getInstance()->getTrackedPositionGlobal() - gAgent.getCameraPositionGlobal();; } else { @@ -1389,8 +1364,8 @@ void LLFloaterWorldMap::centerOnTarget(BOOL animate) pos_global.clearVec(); } - LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sPixelsPerMeter)), - -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sPixelsPerMeter)), + LLWorldMapView::setPan( -llfloor((F32)(pos_global.mdV[VX] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)), + -llfloor((F32)(pos_global.mdV[VY] * (F64)LLWorldMapView::sMapScale / REGION_WIDTH_METERS)), !animate); mWaitingForTracker = FALSE; } @@ -1566,17 +1541,6 @@ void LLFloaterWorldMap::flyToAvatar() } } -// static -void LLFloaterWorldMap::onCommitBackground(void* userdata, bool from_click) -{ - LLFloaterWorldMap* self = (LLFloaterWorldMap*) userdata; - - // Find my index - S32 index = self->mTabs->getCurrentPanelIndex(); - - LLWorldMap::getInstance()->setCurrentLayer(index); -} - void LLFloaterWorldMap::updateSims(bool found_null_sim) { if (mCompletingRegionName == "") @@ -1594,28 +1558,27 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim) BOOL match_found = FALSE; S32 num_results = 0; std::map::const_iterator it; - for (it = LLWorldMap::getInstance()->mSimInfoMap.begin(); it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it) + for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it) { - LLSimInfo* info = (*it).second; - std::string sim_name = info->mName; - std::string sim_name_lower = sim_name; + LLSimInfo* info = it->second; + std::string sim_name_lower = info->getName(); LLStringUtil::toLower(sim_name_lower); if (sim_name_lower.substr(0, name_length) == mCompletingRegionName) { - if (LLWorldMap::getInstance()->mIsTrackingCommit) + if (LLWorldMap::getInstance()->isTrackingCommit()) { - if (sim_name_lower == mCompletingRegionName) + if (info->isName(mCompletingRegionName)) { - selected_value = sim_name; + selected_value = info->getName(); match_found = TRUE; } } LLSD value; - value["id"] = sim_name; + value["id"] = info->getName(); value["columns"][0]["column"] = "sim_name"; - value["columns"][0]["value"] = sim_name; + value["columns"][0]["value"] = info->getName(); list->addElement(value); num_results++; } @@ -1682,15 +1645,13 @@ void LLFloaterWorldMap::onCommitSearchResult(LLUICtrl*, void* userdata) LLStringUtil::toLower(sim_name); std::map::const_iterator it; - for (it = LLWorldMap::getInstance()->mSimInfoMap.begin(); it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it) + for (it = LLWorldMap::getInstance()->getRegionMap().begin(); it != LLWorldMap::getInstance()->getRegionMap().end(); ++it) { - LLSimInfo* info = (*it).second; - std::string info_sim_name = info->mName; - LLStringUtil::toLower(info_sim_name); + LLSimInfo* info = it->second; - if (sim_name == info_sim_name) + if (info->isName(sim_name)) { - LLVector3d pos_global = from_region_handle( info->mHandle ); + LLVector3d pos_global = info->getGlobalOrigin(); F64 local_x = self->childGetValue("spin x"); F64 local_y = self->childGetValue("spin y"); F64 local_z = self->childGetValue("spin z"); diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h index de7cfd8ad..dd5da1529 100644 --- a/indra/newview/llfloaterworldmap.h +++ b/indra/newview/llfloaterworldmap.h @@ -50,7 +50,6 @@ class LLInventoryModel; class LLInventoryObserver; class LLItemInfo; class LLTabContainer; -class LLWorldMapView; class LLFloaterWorldMap : public LLFloater { @@ -112,7 +111,7 @@ public: // teleport to the tracked item, if there is one void teleport(); -protected: +private: static void onPanBtn( void* userdata ); static void onGoHome(void* data); @@ -123,8 +122,6 @@ protected: static void onAvatarComboPrearrange( LLUICtrl* ctrl, void* data ); static void onAvatarComboCommit( LLUICtrl* ctrl, void* data ); - static void onCommitBackground(void* data, bool from_click); - static void onComboTextEntry( LLLineEditor* ctrl, void* data ); static void onSearchTextEntry( LLLineEditor* ctrl, void* data ); @@ -161,10 +158,10 @@ protected: void cacheLandmarkPosition(); -protected: - LLTabContainer* mTabs; +private: + LLPanel* mPanel; // Panel displaying the map - // Sets sMapScale, in pixels per region + // Ties to LLWorldMapView::sMapScale, in pixels per region F32 mCurZoomVal; LLFrameTimer mZoomTimer; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 9224cb5b0..4194b9241 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -180,7 +180,7 @@ #include "llweb.h" #include "llwind.h" #include "llworld.h" -#include "llworldmap.h" +#include "llworldmapmessage.h" #include "llxfermanager.h" #include "pipeline.h" #include "llappviewer.h" @@ -1781,8 +1781,6 @@ bool idle_startup() if(!map_server_url.empty()) { gSavedSettings.setString("MapServerURL", map_server_url); - LLWorldMap::gotMapServerURL(true); - llinfos << "Got Map server URL: " << map_server_url << llendl; } // Override grid info with anything sent in the login response @@ -3566,9 +3564,8 @@ void register_viewer_callbacks(LLMessageSystem* msg) msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply); - msg->setHandlerFunc("MapLayerReply", LLWorldMap::processMapLayerReply); - msg->setHandlerFunc("MapBlockReply", LLWorldMap::processMapBlockReply); - msg->setHandlerFunc("MapItemReply", LLWorldMap::processMapItemReply); + msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply); + msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply); msg->setHandlerFunc("EventInfoReply", LLPanelEvent::processEventInfoReply); msg->setHandlerFunc("PickInfoReply", LLPanelPick::processPickInfoReply); diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp index 1144c5827..a2e2fcfed 100644 --- a/indra/newview/llurldispatcher.cpp +++ b/indra/newview/llurldispatcher.cpp @@ -44,7 +44,7 @@ #include "llstartup.h" // gStartupState #include "llurlsimstring.h" #include "llweb.h" -#include "llworldmap.h" +#include "llworldmapmessage.h" // library includes #include "llsd.h" @@ -243,7 +243,7 @@ bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, bool right_mous url_displayp->setName(region_name); // Request a region handle by name - LLWorldMap::getInstance()->sendNamedRegionRequest(region_name, + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, LLURLDispatcherImpl::regionNameCallback, url, false); // don't teleport @@ -282,7 +282,7 @@ void LLURLDispatcherImpl::regionNameCallback(U64 region_handle, const std::strin LLVector3d global_pos = from_region_handle(region_handle) + LLVector3d(local_pos); U64 new_region_handle = to_region_handle(global_pos); - LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, + LLWorldMapMessage::getInstance()->sendHandleRegionRequest(new_region_handle, LLURLDispatcherImpl::regionHandleCallback, url, teleport); } @@ -401,7 +401,7 @@ public: { url += tokens[i].asString() + "/"; } - LLWorldMap::getInstance()->sendNamedRegionRequest(region_name, + LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, LLURLDispatcherImpl::regionHandleCallback, url, true); // teleport diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 8729d5714..7e49f4be8 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -1029,9 +1029,6 @@ void init_client_menu(LLMenuGL* menu) // menu->append(new LLMenuItemCallGL("Clear Group Cache", LLGroupMgr::debugClearAllGroups)); - - menu->append(new LLMenuItemCheckGL("Use Web Map Tiles", menu_toggle_control, NULL, menu_check_control, (void*)"UseWebMapTiles")); - menu->appendSeparator(); sub_menu = new LLMenuGL("Rendering"); @@ -3574,8 +3571,7 @@ void set_god_level(U8 god_level) LLFloaterDirectory::requestClassifieds(); // God mode changes region visibility - LLWorldMap::getInstance()->reset(); - LLWorldMap::getInstance()->setCurrentLayer(0); + LLWorldMap::getInstance()->reloadItems(true); // inventory in items may change in god mode gObjectList.dirtyAllObjectInventory(); diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp index 9d6d4d2b0..9e238ada9 100644 --- a/indra/newview/llworldmap.cpp +++ b/indra/newview/llworldmap.cpp @@ -34,64 +34,85 @@ #include "llworldmap.h" -#include "llregionhandle.h" +#include "llworldmapmessage.h" #include "message.h" - - #include "llappviewer.h" // for gPacificDaylightTime -#include "llagent.h" -#include "llmapresponders.h" -#include "llviewercontrol.h" -#include "llfloaterworldmap.h" +#include "llcachename.h" // for gCacheName #include "lltracker.h" +#include "llviewerimage.h" #include "llviewerimagelist.h" -#include "llviewerregion.h" -#include "llregionflags.h" - #include "hippogridmanager.h" -bool LLWorldMap::sGotMapURL = false; -const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // 10 minutes -// For DEV-17507, do lazy image loading in llworldmapview.cpp instead, -// limiting requests to currently visible regions and minimizing the -// number of textures being requested simultaneously. -// -// Uncomment IMMEDIATE_IMAGE_LOAD to restore the old behavior -// -//#define IMMEDIATE_IMAGE_LOAD +#include "hippogridmanager.h" + +// Timers to temporise database requests +const F32 AGENTS_UPDATE_TIMER = 60.0; // Seconds between 2 agent requests for a region +const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // Seconds before we consider re-requesting item data for the grid + +//--------------------------------------------------------------------------- +// LLItemInfo +//--------------------------------------------------------------------------- + LLItemInfo::LLItemInfo(F32 global_x, F32 global_y, const std::string& name, - LLUUID id, - S32 extra, S32 extra2) + LLUUID id) : mName(name), mToolTip(""), mPosGlobal(global_x, global_y, 40.0), mID(id), - mSelected(FALSE), - mExtra(extra), - mExtra2(extra2) + mCount(1) +// mSelected(false) +// mColor() { - mRegionHandle = to_region_handle(mPosGlobal); } -LLSimInfo::LLSimInfo() -: mHandle(0), +//--------------------------------------------------------------------------- +// LLSimInfo +//--------------------------------------------------------------------------- + +LLSimInfo::LLSimInfo(U64 handle) +: mHandle(handle), mName(), mAgentsUpdateTime(0), - mShowAgentLocations(FALSE), mAccess(0x0), mRegionFlags(0x0), - mWaterHeight(0.f), - mAlpha(-1.f) + mFirstAgentRequest(true) +// mWaterHeight(0.f) { } - -LLVector3d LLSimInfo::getGlobalOrigin() const +void LLSimInfo::setLandForSaleImage (LLUUID image_id) { - return from_region_handle(mHandle); + mMapImageID = image_id; + + // Fetch the image + if (mMapImageID.notNull()) + { + mOverlayImage = gImageList.getImage(mMapImageID, MIPMAP_TRUE, FALSE); + mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP); + } + else + { + mOverlayImage = NULL; + } } -LLVector3d LLSimInfo::getGlobalPos(LLVector3 local_pos) const +LLPointer LLSimInfo::getLandForSaleImage () +{ + if (mOverlayImage.isNull() && mMapImageID.notNull()) + { + // Fetch the image if it hasn't been done yet (unlikely but...) + mOverlayImage = gImageList.getImage(mMapImageID, MIPMAP_TRUE, FALSE); + mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP); + } + if (!mOverlayImage.isNull()) + { + // Boost the fetch level when we try to access that image + mOverlayImage->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP); + } + return mOverlayImage; +} + +LLVector3d LLSimInfo::getGlobalPos(const LLVector3& local_pos) const { LLVector3d pos = from_region_handle(mHandle); pos.mdV[VX] += local_pos.mV[VX]; @@ -100,121 +121,180 @@ LLVector3d LLSimInfo::getGlobalPos(LLVector3 local_pos) const return pos; } +LLVector3d LLSimInfo::getGlobalOrigin() const +{ + return from_region_handle(mHandle); +} + +void LLSimInfo::clearImage() +{ + if (!mOverlayImage.isNull()) + { + mOverlayImage->setBoostLevel(0); + mOverlayImage = NULL; + } +} + +void LLSimInfo::dropImagePriority() +{ + if (!mOverlayImage.isNull()) + { + mOverlayImage->setBoostLevel(0); + } +} + +// Update the agent count for that region +void LLSimInfo::updateAgentCount(F64 time) +{ + if ((time - mAgentsUpdateTime > AGENTS_UPDATE_TIMER) || mFirstAgentRequest) + { + LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, mHandle); + mAgentsUpdateTime = time; + mFirstAgentRequest = false; + } +} + +// Get the total agents count +const S32 LLSimInfo::getAgentCount() const +{ + S32 total_agent_count = 0; + for (LLSimInfo::item_info_list_t::const_iterator it = mAgentLocations.begin(); it != mAgentLocations.end(); ++it) + { + total_agent_count += it->getCount(); + } + return total_agent_count; +} + +bool LLSimInfo::isName(const std::string& name) const +{ + return (LLStringUtil::compareInsensitive(name, mName) == 0); +} + +void LLSimInfo::dump() const +{ + U32 x_pos, y_pos; + from_region_handle(mHandle, &x_pos, &y_pos); + + LL_INFOS("World Map") << x_pos << "," << y_pos + << " " << mName + << " " << (S32)mAccess + << " " << std::hex << mRegionFlags << std::dec +// << " " << mWaterHeight + << LL_ENDL; +} + +void LLSimInfo::clearItems() +{ + mTelehubs.clear(); + mInfohubs.clear(); + mPGEvents.clear(); + mMatureEvents.clear(); + mAdultEvents.clear(); + mLandForSale.clear(); + mLandForSaleAdult.clear(); +// We persist the agent count though as it is updated on a frequent basis +// mAgentLocations.clear(); +} + +void LLSimInfo::insertAgentLocation(const LLItemInfo& item) +{ + std::string name = item.getName(); + + + // Find the last item in the list with a different name and erase them + item_info_list_t::iterator lastiter; + for (lastiter = mAgentLocations.begin(); lastiter != mAgentLocations.end(); ++lastiter) + { + LLItemInfo& info = *lastiter; + if (info.isName(name)) + { + break; + } + } + if (lastiter != mAgentLocations.begin()) + { + mAgentLocations.erase(mAgentLocations.begin(), lastiter); + } + + // Now append the new location + mAgentLocations.push_back(item); +} //--------------------------------------------------------------------------- // World Map //--------------------------------------------------------------------------- LLWorldMap::LLWorldMap() : - mIsTrackingUnknownLocation( FALSE ), - mInvalidLocation( FALSE ), - mIsTrackingDoubleClick( FALSE ), - mIsTrackingCommit( FALSE ), - mUnknownLocation( 0, 0, 0 ), - mRequestLandForSale(true), - mCurrentMap(0), - mMinX(U32_MAX), - mMaxX(U32_MIN), - mMinY(U32_MAX), - mMaxY(U32_MIN), - mNeighborMap(NULL), - mTelehubCoverageMap(NULL), - mNeighborMapWidth(0), - mNeighborMapHeight(0), - mSLURLRegionName(), - mSLURLRegionHandle(0), - mSLURL(), - mSLURLCallback(0), - mSLURLTeleport(false) + mIsTrackingLocation( false ), + mIsTrackingFound( false ), + mIsInvalidLocation( false ), + mIsTrackingDoubleClick( false ), + mIsTrackingCommit( false ), + mTrackingLocation( 0, 0, 0 ), + mFirstRequest(true) { - for (S32 map=0; map LLWorldMap::LLWorldMap()" << LL_ENDL; + mMapBlockLoaded = new bool[MAP_BLOCK_RES*MAP_BLOCK_RES]; + clearSimFlags(); } LLWorldMap::~LLWorldMap() { + //LL_INFOS("World Map") << "Destroying the World Map -> LLWorldMap::~LLWorldMap()" << LL_ENDL; reset(); - for (S32 map=0; map REQUEST_ITEMS_TIMER) + bool clear = false; + if ((mRequestTimer.getElapsedTimeF32() > REQUEST_ITEMS_TIMER) || mFirstRequest || force) { mRequestTimer.reset(); - mTelehubs.clear(); - mInfohubs.clear(); - mPGEvents.clear(); - mMatureEvents.clear(); - mAdultEvents.clear(); - mLandForSale.clear(); + LLSimInfo* sim_info = NULL; + for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) + { + sim_info = it->second; + if (sim_info) + { + sim_info->clearItems(); + } + } + clear = true; + mFirstRequest = false; } -// mAgentLocationsMap.clear(); // persists -// mNumAgents.clear(); // persists + return clear; } - void LLWorldMap::clearImageRefs() { + // We clear the reference to the images we're holding. + // Images hold by the world mipmap first + mWorldMipmap.reset(); + + // Images hold by the region map + LLSimInfo* sim_info = NULL; for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { - LLSimInfo* info = (*it).second; - if (info->mCurrentImage) + sim_info = it->second; + if (sim_info) { - info->mCurrentImage->setBoostLevel(0); - info->mCurrentImage = NULL; - } - if (info->mOverlayImage) - { - info->mOverlayImage->setBoostLevel(0); - info->mOverlayImage = NULL; + sim_info->clearImage(); } } } @@ -222,15 +302,25 @@ void LLWorldMap::clearImageRefs() // Doesn't clear the already-loaded sim infos, just re-requests them void LLWorldMap::clearSimFlags() { - for (S32 map=0; mapsecond; } return NULL; } @@ -257,816 +343,289 @@ LLSimInfo* LLWorldMap::simInfoFromName(const std::string& sim_name) LLSimInfo* sim_info = NULL; if (!sim_name.empty()) { - for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) + // Iterate through the entire sim info map and compare the name + sim_info_map_t::iterator it; + for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { - sim_info = (*it).second; - if (sim_info - && (0 == LLStringUtil::compareInsensitive(sim_name, sim_info->mName)) ) + sim_info = it->second; + if (sim_info && sim_info->isName(sim_name) ) { + // break out of loop if success break; } - sim_info = NULL; } + // If we got to the end, we haven't found the sim. Reset the ouput value to NULL. + if (it == mSimInfoMap.end()) + sim_info = NULL; } return sim_info; } bool LLWorldMap::simNameFromPosGlobal(const LLVector3d& pos_global, std::string & outSimName ) { - bool gotSimName = true; + LLSimInfo* sim_info = simInfoFromPosGlobal(pos_global); - U64 handle = to_region_handle(pos_global); - - sim_info_map_t::iterator it = mSimInfoMap.find(handle); - if (it != mSimInfoMap.end()) + if (sim_info) { - LLSimInfo* info = (*it).second; - outSimName = info->mName; + outSimName = sim_info->getName(); } else { - gotSimName = false; outSimName = "(unknown region)"; } - return gotSimName; + return (sim_info != NULL); } -void LLWorldMap::setCurrentLayer(S32 layer, bool request_layer) +void LLWorldMap::reloadItems(bool force) { - mCurrentMap = layer; - if (!mMapLoaded[layer] || request_layer) + //LL_INFOS("World Map") << "LLWorldMap::reloadItems()" << LL_ENDL; + if (clearItems(force)) { - sendMapLayerRequest(); + LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_TELEHUB); + LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_PG_EVENT); + LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_MATURE_EVENT); + LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_ADULT_EVENT); + LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE); } - - if (mTelehubs.size() == 0 || - mInfohubs.size() == 0) - { - // Request for telehubs - sendItemRequest(MAP_ITEM_TELEHUB); - } - - if (mPGEvents.size() == 0) - { - // Request for events - sendItemRequest(MAP_ITEM_PG_EVENT); - } - - if (mMatureEvents.size() == 0) - { - // Request for events (mature) - sendItemRequest(MAP_ITEM_MATURE_EVENT); - } - - if (mAdultEvents.size() == 0) - { - // Request for events (adult) - sendItemRequest(MAP_ITEM_ADULT_EVENT); - } - - if (mLandForSale.size() == 0) - { - // Request for Land For Sale - sendItemRequest(MAP_ITEM_LAND_FOR_SALE); - } - - if (mLandForSaleAdult.size() == 0) - { - // Request for Land For Sale - sendItemRequest(MAP_ITEM_LAND_FOR_SALE_ADULT); - } - - clearImageRefs(); - clearSimFlags(); } -void LLWorldMap::sendItemRequest(U32 type, U64 handle) +// static public +// Insert a region in the region map +// returns true if region inserted, false otherwise +bool LLWorldMap::insertRegion(U32 x_world, U32 y_world, std::string& name, LLUUID& image_id, U32 accesscode, U32 region_flags) { - LLMessageSystem* msg = gMessageSystem; - S32 layer = mCurrentMap; - - msg->newMessageFast(_PREHASH_MapItemRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addU32Fast(_PREHASH_Flags, layer); - msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim - msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim - - msg->nextBlockFast(_PREHASH_RequestData); - msg->addU32Fast(_PREHASH_ItemType, type); - msg->addU64Fast(_PREHASH_RegionHandle, handle); // If zero, filled in on sim - - gAgent.sendReliableMessage(); -} - -// public -void LLWorldMap::sendMapLayerRequest() -{ - if (!gAgent.getRegion()) return; - - LLSD body; - body["Flags"] = mCurrentMap; - std::string url = gAgent.getRegion()->getCapability( - gAgent.isGodlike() ? "MapLayerGod" : "MapLayer"); - - if (!url.empty()) + // This region doesn't exist + if (accesscode == 255) { - llinfos << "LLWorldMap::sendMapLayerRequest via capability" << llendl; - LLHTTPClient::post(url, body, new LLMapLayerResponder()); + // Checks if the track point is in it and invalidates it if it is + if (LLWorldMap::getInstance()->isTrackingInRectangle( x_world, y_world, x_world + REGION_WIDTH_UNITS, y_world + REGION_WIDTH_UNITS)) + { + LLWorldMap::getInstance()->setTrackingInvalid(); + } + // return failure to insert + return false; } else { - llinfos << "LLWorldMap::sendMapLayerRequest via message system" << llendl; - LLMessageSystem* msg = gMessageSystem; - S32 layer = mCurrentMap; - - // Request for layer - msg->newMessageFast(_PREHASH_MapLayerRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addU32Fast(_PREHASH_Flags, layer); - msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim - msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim - gAgent.sendReliableMessage(); - - if (mRequestLandForSale) + U64 handle = to_region_handle(x_world, y_world); + //LL_INFOS("World Map") << "Map sim : " << name << ", ID : " << image_id.getString() << LL_ENDL; + // Insert the region in the region map of the world map + // Loading the LLSimInfo object with what we got and insert it in the map + LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle); + if (siminfo == NULL) { - msg->newMessageFast(_PREHASH_MapLayerRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addU32Fast(_PREHASH_Flags, 2); - msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim - msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim - gAgent.sendReliableMessage(); + siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle); } - } -} + siminfo->setName(name); + siminfo->setAccess(accesscode); + siminfo->setRegionFlags(region_flags); + // siminfo->setWaterHeight((F32) water_height); + siminfo->setLandForSaleImage(image_id); -// public -void LLWorldMap::sendNamedRegionRequest(std::string region_name) -{ - LLMessageSystem* msg = gMessageSystem; - S32 layer = mCurrentMap; - - // Request for layer - msg->newMessageFast(_PREHASH_MapNameRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addU32Fast(_PREHASH_Flags, layer); - msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim - msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim - msg->nextBlockFast(_PREHASH_NameData); - msg->addStringFast(_PREHASH_Name, region_name); - gAgent.sendReliableMessage(); -} -// public -void LLWorldMap::sendNamedRegionRequest(std::string region_name, - url_callback_t callback, - const std::string& callback_url, - bool teleport) // immediately teleport when result returned -{ - mSLURLRegionName = region_name; - mSLURLRegionHandle = 0; - mSLURL = callback_url; - mSLURLCallback = callback; - mSLURLTeleport = teleport; - - sendNamedRegionRequest(region_name); -} - -void LLWorldMap::sendHandleRegionRequest(U64 region_handle, - url_callback_t callback, - const std::string& callback_url, - bool teleport) // immediately teleport when result returned -{ - mSLURLRegionName.clear(); - mSLURLRegionHandle = region_handle; - mSLURL = callback_url; - mSLURLCallback = callback; - mSLURLTeleport = teleport; - - U32 global_x; - U32 global_y; - from_region_handle(region_handle, &global_x, &global_y); - U16 grid_x = (U16)(global_x / REGION_WIDTH_UNITS); - U16 grid_y = (U16)(global_y / REGION_WIDTH_UNITS); - - sendMapBlockRequest(grid_x, grid_y, grid_x, grid_y, true); -} - -// public -void LLWorldMap::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) -{ - S32 layer = mCurrentMap; - LLMessageSystem* msg = gMessageSystem; - msg->newMessageFast(_PREHASH_MapBlockRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - U32 flags = layer; - flags |= (return_nonexistent ? 0x10000 : 0); - msg->addU32Fast(_PREHASH_Flags, flags); - msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim - msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim - msg->nextBlockFast(_PREHASH_PositionData); - msg->addU16Fast(_PREHASH_MinX, min_x); - msg->addU16Fast(_PREHASH_MinY, min_y); - msg->addU16Fast(_PREHASH_MaxX, max_x); - msg->addU16Fast(_PREHASH_MaxY, max_y); - gAgent.sendReliableMessage(); - - if (mRequestLandForSale) - { - msg->newMessageFast(_PREHASH_MapBlockRequest); - msg->nextBlockFast(_PREHASH_AgentData); - msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); - msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); - msg->addU32Fast(_PREHASH_Flags, 2); - msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim - msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim - msg->nextBlockFast(_PREHASH_PositionData); - msg->addU16Fast(_PREHASH_MinX, min_x); - msg->addU16Fast(_PREHASH_MinY, min_y); - msg->addU16Fast(_PREHASH_MaxX, max_x); - msg->addU16Fast(_PREHASH_MaxY, max_y); - gAgent.sendReliableMessage(); - } -} - -// public static -void LLWorldMap::processMapLayerReply(LLMessageSystem* msg, void**) -{ - llinfos << "LLWorldMap::processMapLayerReply from message system" << llendl; - - U32 agent_flags; - msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); - - if (agent_flags != (U32)LLWorldMap::getInstance()->mCurrentMap) - { - llwarns << "Invalid or out of date map image type returned!" << llendl; - return; - } - - LLUUID image_id; - //U32 left, right, top, bottom; - - S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_LayerData); - - LLWorldMap::getInstance()->mMapLayers[agent_flags].clear(); - -// bool use_web_map_tiles = useWebMapTiles(); - BOOL adjust = FALSE; - for (S32 block=0; blockgetUUIDFast(_PREHASH_LayerData, _PREHASH_ImageID, new_layer.LayerImageID, block); - - U32 left, right, top, bottom; - msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Left, left, block); - msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Right, right, block); - msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Top, top, block); - msg->getU32Fast(_PREHASH_LayerData, _PREHASH_Bottom, bottom, block); - -// if (use_web_map_tiles) -// { -// new_layer.LayerImage = loadObjectsTile(left, bottom); // no good... Maybe using of level 2 and higher web maps ? -// } -// else -// { - new_layer.LayerImage = gImageList.getImage(new_layer.LayerImageID, MIPMAP_TRUE, FALSE); -// } - - gGL.getTexUnit(0)->bind(new_layer.LayerImage.get()); - new_layer.LayerImage->setAddressMode(LLTexUnit::TAM_CLAMP); - - new_layer.LayerExtents.mLeft = left; - new_layer.LayerExtents.mRight = right; - new_layer.LayerExtents.mBottom = bottom; - new_layer.LayerExtents.mTop = top; - - F32 x_meters = F32(left*REGION_WIDTH_UNITS); - F32 y_meters = F32(bottom*REGION_WIDTH_UNITS); - adjust = LLWorldMap::getInstance()->extendAABB(U32(x_meters), U32(y_meters), - U32(x_meters+REGION_WIDTH_UNITS*new_layer.LayerExtents.getWidth()), - U32(y_meters+REGION_WIDTH_UNITS*new_layer.LayerExtents.getHeight())) || adjust; - - LLWorldMap::getInstance()->mMapLayers[agent_flags].push_back(new_layer); - } - - LLWorldMap::getInstance()->mMapLoaded[agent_flags] = TRUE; - if(adjust) gFloaterWorldMap->adjustZoomSliderBounds(); -} - -// public static -bool LLWorldMap::useWebMapTiles() -{ - return gSavedSettings.getBOOL("UseWebMapTiles") && - (( gHippoGridManager->getConnectedGrid()->isSecondLife() || sGotMapURL) && LLWorldMap::getInstance()->mCurrentMap == 0); -} - -// public static -LLPointer LLWorldMap::loadObjectsTile(U32 grid_x, U32 grid_y) -{ - // Get the grid coordinates - std::string imageurl = gSavedSettings.getString("MapServerURL") + llformat("map-%d-%d-%d-objects.jpg", 1, grid_x, grid_y); - - LLPointer img = gImageList.getImageFromUrl(imageurl); - img->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP); - - // Return the smart pointer - return img; -} - -// public static -void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**) -{ - U32 agent_flags; - msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); - - if ((S32)agent_flags < 0 || agent_flags >= MAP_SIM_IMAGE_TYPES) - { - llwarns << "Invalid map image type returned! " << agent_flags << llendl; - return; - } - - S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data); - - bool found_null_sim = false; - -#ifdef IMMEDIATE_IMAGE_LOAD - bool use_web_map_tiles = useWebMapTiles(); -#endif - BOOL adjust = FALSE; - for (S32 block=0; blockgetU16Fast(_PREHASH_Data, _PREHASH_X, x_regions, block); - msg->getU16Fast(_PREHASH_Data, _PREHASH_Y, y_regions, block); - msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block); - msg->getU8Fast(_PREHASH_Data, _PREHASH_Access, accesscode, block); - msg->getU32Fast(_PREHASH_Data, _PREHASH_RegionFlags, region_flags, block); - msg->getU8Fast(_PREHASH_Data, _PREHASH_WaterHeight, water_height, block); - msg->getU8Fast(_PREHASH_Data, _PREHASH_Agents, agents, block); - msg->getUUIDFast(_PREHASH_Data, _PREHASH_MapImageID, image_id, block); - - U32 x_meters = x_regions * REGION_WIDTH_UNITS; - U32 y_meters = y_regions * REGION_WIDTH_UNITS; - - U64 handle = to_region_handle(x_meters, y_meters); - - if (accesscode == 255) + // Handle the location tracking (for teleport, UI feedback and info display) + if (LLWorldMap::getInstance()->isTrackingInRectangle( x_world, y_world, x_world + REGION_WIDTH_UNITS, y_world + REGION_WIDTH_UNITS)) { - // This region doesn't exist - if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation && - LLWorldMap::getInstance()->mUnknownLocation.mdV[0] >= x_meters && - LLWorldMap::getInstance()->mUnknownLocation.mdV[0] < x_meters + 256 && - LLWorldMap::getInstance()->mUnknownLocation.mdV[1] >= y_meters && - LLWorldMap::getInstance()->mUnknownLocation.mdV[1] < y_meters + 256) + if (siminfo->isDown()) { - // We were tracking this location, but it doesn't exist - LLWorldMap::getInstance()->mInvalidLocation = TRUE; - } - - found_null_sim = true; - } - else - { - adjust = LLWorldMap::getInstance()->extendAABB(x_meters, - y_meters, - x_meters+REGION_WIDTH_UNITS, - y_meters+REGION_WIDTH_UNITS) || adjust; - -// llinfos << "Map sim " << name << " image layer " << agent_flags << " ID " << image_id.getString() << llendl; - - LLSimInfo* siminfo = new LLSimInfo(); - sim_info_map_t::iterator iter = LLWorldMap::getInstance()->mSimInfoMap.find(handle); - if (iter != LLWorldMap::getInstance()->mSimInfoMap.end()) - { - LLSimInfo* oldinfo = iter->second; - for (S32 image=0; imagemMapImageID[image] = oldinfo->mMapImageID[image]; - } - delete oldinfo; - } - LLWorldMap::getInstance()->mSimInfoMap[handle] = siminfo; - - siminfo->mHandle = handle; - siminfo->mName.assign( name ); - siminfo->mAccess = accesscode; - siminfo->mRegionFlags = region_flags; - siminfo->mWaterHeight = (F32) water_height; - siminfo->mMapImageID[agent_flags] = image_id; - -#ifdef IMMEDIATE_IMAGE_LOAD - if (use_web_map_tiles) - { - siminfo->mCurrentImage = loadObjectsTile((U32)x_regions, (U32)y_regions); + // We were tracking this location, but it's no available + LLWorldMap::getInstance()->setTrackingInvalid(); } else { - siminfo->mCurrentImage = gImageList.getImage(siminfo->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE); + // We were tracking this location, and it does exist and is available + LLWorldMap::getInstance()->setTrackingValid(); } - gGL.getTexUnit(0)->bind(siminfo->mCurrentImage.get()); - siminfo->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP); -#endif + } + // return insert region success + return true; + } +} + +// static public +// Insert an item in the relevant region map +// returns true if item inserted, false otherwise +bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& uuid, U32 type, S32 extra, S32 extra2) +{ + // Create an item record for the received object + LLItemInfo new_item((F32)x_world, (F32)y_world, name, uuid); + + // Compute a region handle based on the objects coordinates + LLVector3d pos((F32)x_world, (F32)y_world, 40.0); + U64 handle = to_region_handle(pos); + + // Get the region record for that handle or NULL if we haven't browsed it yet + LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle); + if (siminfo == NULL) + { + siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle); + } + + //LL_INFOS("World Map") << "Process item : type = " << type << LL_ENDL; + switch (type) + { + case MAP_ITEM_TELEHUB: // telehubs + { + /* Merov: we are not using the hub color anymore for display so commenting that out + // Telehub color + U32 X = x_world / REGION_WIDTH_UNITS; + U32 Y = y_world / REGION_WIDTH_UNITS; + F32 red = fmod((F32)X * 0.11f, 1.f) * 0.8f; + F32 green = fmod((F32)Y * 0.11f, 1.f) * 0.8f; + F32 blue = fmod(1.5f * (F32)(X + Y) * 0.11f, 1.f) * 0.8f; + F32 add_amt = (X % 2) ? 0.15f : -0.15f; + add_amt += (Y % 2) ? -0.15f : 0.15f; + LLColor4 color(red + add_amt, green + add_amt, blue + add_amt); + new_item.setColor(color); + */ - if (siminfo->mMapImageID[2].notNull()) + // extra2 specifies whether this is an infohub or a telehub. + if (extra2) { -#ifdef IMMEDIATE_IMAGE_LOAD - siminfo->mOverlayImage = gImageList.getImage(siminfo->mMapImageID[2], MIPMAP_TRUE, FALSE); -#endif + siminfo->insertInfoHub(new_item); } else { - siminfo->mOverlayImage = NULL; - } - - if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation && - LLWorldMap::getInstance()->mUnknownLocation.mdV[0] >= x_meters && - LLWorldMap::getInstance()->mUnknownLocation.mdV[0] < x_meters + 256 && - LLWorldMap::getInstance()->mUnknownLocation.mdV[1] >= y_meters && - LLWorldMap::getInstance()->mUnknownLocation.mdV[1] < y_meters + 256) - { - if (siminfo->mAccess == SIM_ACCESS_DOWN) - { - // We were tracking this location, but it doesn't exist - LLWorldMap::getInstance()->mInvalidLocation = true; - } - else - { - // We were tracking this location, and it does exist - bool is_tracking_dbl = LLWorldMap::getInstance()->mIsTrackingDoubleClick == TRUE; - gFloaterWorldMap->trackLocation(LLWorldMap::getInstance()->mUnknownLocation); - if (is_tracking_dbl) - { - LLVector3d pos_global = LLTracker::getTrackedPositionGlobal(); - gAgent.teleportViaLocation( pos_global ); - } - } + siminfo->insertTeleHub(new_item); } + break; } - - if(LLWorldMap::getInstance()->mSLURLCallback != NULL) + case MAP_ITEM_PG_EVENT: // events + case MAP_ITEM_MATURE_EVENT: + case MAP_ITEM_ADULT_EVENT: { - // Server returns definitive capitalization, SLURL might not have that. - if ((LLStringUtil::compareInsensitive(LLWorldMap::getInstance()->mSLURLRegionName, name)==0) - || (LLWorldMap::getInstance()->mSLURLRegionHandle == handle)) + struct tm* timep; + // Convert to Pacific, based on server's opinion of whether + // it's daylight savings time there. + timep = utc_to_pacific_time(extra, gPacificDaylightTime); + + S32 display_hour = timep->tm_hour % 12; + if (display_hour == 0) display_hour = 12; + + std::string tooltip = llformat( "%d:%02d %s", + display_hour, + timep->tm_min, + (timep->tm_hour < 12 ? "AM" : "PM") ); + new_item.setTooltip(tooltip); + + // HACK: store Z in extra2 + new_item.setElevation((F64)extra2); + if (type == MAP_ITEM_PG_EVENT) { - url_callback_t callback = LLWorldMap::getInstance()->mSLURLCallback; - - LLWorldMap::getInstance()->mSLURLCallback = NULL; - LLWorldMap::getInstance()->mSLURLRegionName.clear(); - LLWorldMap::getInstance()->mSLURLRegionHandle = 0; - - callback(handle, LLWorldMap::getInstance()->mSLURL, image_id, LLWorldMap::getInstance()->mSLURLTeleport); + siminfo->insertPGEvent(new_item); } + else if (type == MAP_ITEM_MATURE_EVENT) + { + siminfo->insertMatureEvent(new_item); + } + else if (type == MAP_ITEM_ADULT_EVENT) + { + siminfo->insertAdultEvent(new_item); + } + break; } - if(LLAgent::lure_show) + case MAP_ITEM_LAND_FOR_SALE: // land for sale + case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale { - if((x_regions == LLAgent::lure_global_x) && (y_regions == LLAgent::lure_global_y)) + std::string tooltip = llformat("%d sq. m. %s%d", + extra, + gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str(), + extra2); + new_item.setTooltip(tooltip); + if (type == MAP_ITEM_LAND_FOR_SALE) { - gAgent.onFoundLureDestination(); + siminfo->insertLandForSale(new_item); } + else if (type == MAP_ITEM_LAND_FOR_SALE_ADULT) + { + siminfo->insertLandForSaleAdult(new_item); + } + break; } + case MAP_ITEM_CLASSIFIED: // classifieds + { + //DEPRECATED: no longer used + break; + } + case MAP_ITEM_AGENT_LOCATIONS: // agent locations + { + /* + // yes, we like to know who it is who's there! + std::string avFullName; + + gCacheName->getFullName(uuid, avFullName); + + LL_INFOS("World Map") << "New Location " << avFullName << LL_ENDL; + // + */ + if (extra > 0) + { + new_item.setCount(extra); + siminfo->insertAgentLocation(new_item); + } + break; + } + default: + break; } - - if(adjust) gFloaterWorldMap->adjustZoomSliderBounds(); - gFloaterWorldMap->updateSims(found_null_sim); + return true; } -// public static -void LLWorldMap::processMapItemReply(LLMessageSystem* msg, void**) +bool LLWorldMap::isTrackingInRectangle(F64 x0, F64 y0, F64 x1, F64 y1) { - U32 type; - msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ItemType, type); + if (!mIsTrackingLocation) + return false; + return ((mTrackingLocation[0] >= x0) && (mTrackingLocation[0] < x1) && (mTrackingLocation[1] >= y0) && (mTrackingLocation[1] < y1)); +} - S32 num_blocks = msg->getNumberOfBlocks("Data"); - - for (S32 block=0; blockgetU32Fast(_PREHASH_Data, _PREHASH_X, X, block); - msg->getU32Fast(_PREHASH_Data, _PREHASH_Y, Y, block); - msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block); - msg->getUUIDFast(_PREHASH_Data, _PREHASH_ID, uuid, block); - msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra, extra, block); - msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra2, extra2, block); + LLSimInfo* info = it->second; + info->dropImagePriority(); + } +} - F32 world_x = (F32)X; - X /= REGION_WIDTH_UNITS; - F32 world_y = (F32)Y; - Y /= REGION_WIDTH_UNITS; - - LLItemInfo new_item(world_x, world_y, name, uuid, extra, extra2); - LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(new_item.mRegionHandle); +// Load all regions in a given rectangle (in region grid coordinates, i.e. world / 256 meters) +void LLWorldMap::updateRegions(S32 x0, S32 y0, S32 x1, S32 y1) +{ + // Convert those boundaries to the corresponding (MAP_BLOCK_SIZE x MAP_BLOCK_SIZE) block coordinates + x0 = x0 / MAP_BLOCK_SIZE; + x1 = x1 / MAP_BLOCK_SIZE; + y0 = y0 / MAP_BLOCK_SIZE; + y1 = y1 / MAP_BLOCK_SIZE; - switch (type) + // Load the region info those blocks + for (S32 block_x = llmax(x0, 0); block_x <= llmin(x1, MAP_BLOCK_RES-1); ++block_x) + { + for (S32 block_y = llmax(y0, 0); block_y <= llmin(y1, MAP_BLOCK_RES-1); ++block_y) { - case MAP_ITEM_TELEHUB: // telehubs + S32 offset = block_x | (block_y * MAP_BLOCK_RES); + if (!mMapBlockLoaded[offset]) { - // Telehub color, store in extra as 4 U8's - U8 *color = (U8 *)&new_item.mExtra; - - F32 red = fmod((F32)X * 0.11f, 1.f) * 0.8f; - F32 green = fmod((F32)Y * 0.11f, 1.f) * 0.8f; - F32 blue = fmod(1.5f * (F32)(X + Y) * 0.11f, 1.f) * 0.8f; - F32 add_amt = (X % 2) ? 0.15f : -0.15f; - add_amt += (Y % 2) ? -0.15f : 0.15f; - color[0] = U8((red + add_amt) * 255); - color[1] = U8((green + add_amt) * 255); - color[2] = U8((blue + add_amt) * 255); - color[3] = 255; - - // extra2 specifies whether this is an infohub or a telehub. - if (extra2) - { - LLWorldMap::getInstance()->mInfohubs.push_back(new_item); - } - else - { - LLWorldMap::getInstance()->mTelehubs.push_back(new_item); - } - - break; + //LL_INFOS("World Map") << "Loading Block (" << block_x << "," << block_y << ")" << LL_ENDL; + LLWorldMapMessage::getInstance()->sendMapBlockRequest(block_x * MAP_BLOCK_SIZE, block_y * MAP_BLOCK_SIZE, (block_x * MAP_BLOCK_SIZE) + MAP_BLOCK_SIZE - 1, (block_y * MAP_BLOCK_SIZE) + MAP_BLOCK_SIZE - 1); + mMapBlockLoaded[offset] = true; } - case MAP_ITEM_PG_EVENT: // events - case MAP_ITEM_MATURE_EVENT: - case MAP_ITEM_ADULT_EVENT: - { - struct tm* timep; - // Convert to Pacific, based on server's opinion of whether - // it's daylight savings time there. - timep = utc_to_pacific_time(extra, gPacificDaylightTime); - - S32 display_hour = timep->tm_hour % 12; - if (display_hour == 0) display_hour = 12; - - new_item.mToolTip = llformat( "%d:%02d %s", - display_hour, - timep->tm_min, - (timep->tm_hour < 12 ? "AM" : "PM") ); - - // HACK: store Z in extra2 - new_item.mPosGlobal.mdV[VZ] = (F64)extra2; - if (type == MAP_ITEM_PG_EVENT) - { - LLWorldMap::getInstance()->mPGEvents.push_back(new_item); - } - else if (type == MAP_ITEM_MATURE_EVENT) - { - LLWorldMap::getInstance()->mMatureEvents.push_back(new_item); - } - else if (type == MAP_ITEM_ADULT_EVENT) - { - LLWorldMap::getInstance()->mAdultEvents.push_back(new_item); - } - - break; - } - case MAP_ITEM_LAND_FOR_SALE: // land for sale - case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale - { - new_item.mToolTip = llformat("%d sq. m. %s%d", new_item.mExtra, - gHippoGridManager->getConnectedGrid()->getCurrencySymbol().c_str(), - new_item.mExtra2); - if (type == MAP_ITEM_LAND_FOR_SALE) - { - LLWorldMap::getInstance()->mLandForSale.push_back(new_item); - } - else if (type == MAP_ITEM_LAND_FOR_SALE_ADULT) - { - LLWorldMap::getInstance()->mLandForSaleAdult.push_back(new_item); - } - break; - } - case MAP_ITEM_CLASSIFIED: // classifieds - { - //DEPRECATED: no longer used - break; - } - case MAP_ITEM_AGENT_LOCATIONS: // agent locations - { - if (!siminfo) - { - llinfos << "siminfo missing for " << new_item.mPosGlobal.mdV[0] << ", " << new_item.mPosGlobal.mdV[1] << llendl; - break; - } -// llinfos << "New Location " << new_item.mName << llendl; - - item_info_list_t& agentcounts = LLWorldMap::getInstance()->mAgentLocationsMap[new_item.mRegionHandle]; - - // Find the last item in the list with a different name and erase them - item_info_list_t::iterator lastiter; - for (lastiter = agentcounts.begin(); lastiter!=agentcounts.end(); ++lastiter) - { - const LLItemInfo& info = *lastiter; - if (info.mName == new_item.mName) - { - break; - } - } - if (lastiter != agentcounts.begin()) - { - agentcounts.erase(agentcounts.begin(), lastiter); - } - // Now append the new location - if (new_item.mExtra > 0) - { - agentcounts.push_back(new_item); - } - break; - } - default: - break; - }; + } } } void LLWorldMap::dump() { + LL_INFOS("World Map") << "LLWorldMap::dump()" << LL_ENDL; for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) { - U64 handle = (*it).first; - LLSimInfo* info = (*it).second; - - U32 x_pos, y_pos; - from_region_handle(handle, &x_pos, &y_pos); - - llinfos << x_pos << "," << y_pos - << " " << info->mName - << " " << (S32)info->mAccess - << " " << std::hex << info->mRegionFlags << std::dec - << " " << info->mWaterHeight - //<< " " << info->mTelehubName - //<< " " << info->mTelehubPosition - << llendl; - - if (info->mCurrentImage) + LLSimInfo* info = it->second; + if (info) { - llinfos << "image discard " << (S32)info->mCurrentImage->getDiscardLevel() - << " fullwidth " << info->mCurrentImage->getWidth(0) - << " fullheight " << info->mCurrentImage->getHeight(0) - << " maxvirt " << info->mCurrentImage->mMaxVirtualSize - << " maxdisc " << (S32)info->mCurrentImage->getMaxDiscardLevel() - << llendl; + info->dump(); } } } - -BOOL LLWorldMap::extendAABB(U32 min_x, U32 min_y, U32 max_x, U32 max_y) -{ - BOOL rv = FALSE; - if (min_x < mMinX) - { - rv = TRUE; - mMinX = min_x; - } - if (min_y < mMinY) - { - rv = TRUE; - mMinY = min_y; - } - if (max_x > mMaxX) - { - rv = TRUE; - mMaxX = max_x; - } - if (max_y > mMaxY) - { - rv = TRUE; - mMaxY = max_y; - } - lldebugs << "World map aabb: (" << mMinX << ", " << mMinY << "), (" - << mMaxX << ", " << mMaxY << ")" << llendl; - return rv; -} - - -U32 LLWorldMap::getWorldWidth() const -{ - return mMaxX - mMinX; -} - - -U32 LLWorldMap::getWorldHeight() const -{ - return mMaxY - mMinY; -} - -BOOL LLWorldMap::coveredByTelehub(LLSimInfo* infop) -{ - /*if (!mTelehubCoverageMap) - { - return FALSE; - } - U32 x_pos, y_pos; - from_region_handle(infop->mHandle, &x_pos, &y_pos); - x_pos /= REGION_WIDTH_UNITS; - y_pos /= REGION_WIDTH_UNITS; - - S32 index = x_pos - (mMinX / REGION_WIDTH_UNITS - 1) + (mNeighborMapWidth * (y_pos - (mMinY / REGION_WIDTH_UNITS - 1))); - return mTelehubCoverageMap[index] != 0; */ - return FALSE; -} - -void LLWorldMap::updateTelehubCoverage() -{ - /*S32 neighbor_width = getWorldWidth() / REGION_WIDTH_UNITS + 2; - S32 neighbor_height = getWorldHeight() / REGION_WIDTH_UNITS + 2; - if (neighbor_width > mNeighborMapWidth || neighbor_height > mNeighborMapHeight) - { - mNeighborMapWidth = neighbor_width; - mNeighborMapHeight = neighbor_height; - delete mNeighborMap; - delete mTelehubCoverageMap; - - mNeighborMap = new U8[mNeighborMapWidth * mNeighborMapHeight]; - mTelehubCoverageMap = new U8[mNeighborMapWidth * mNeighborMapHeight]; - } - - memset(mNeighborMap, 0, mNeighborMapWidth * mNeighborMapHeight * sizeof(U8)); - memset(mTelehubCoverageMap, 0, mNeighborMapWidth * mNeighborMapHeight * sizeof(U8)); - - // leave 1 sim border - S32 min_x = (mMinX / REGION_WIDTH_UNITS) - 1; - S32 min_y = (mMinY / REGION_WIDTH_UNITS) - 1; - - std::map::const_iterator it; - for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) - { - U64 handle = (*it).first; - //LLSimInfo* info = (*it).second; - - U32 x_pos, y_pos; - from_region_handle(handle, &x_pos, &y_pos); - x_pos /= REGION_WIDTH_UNITS; - y_pos /= REGION_WIDTH_UNITS; - x_pos -= min_x; - y_pos -= min_y; - - S32 index = x_pos + (mNeighborMapWidth * y_pos); - mNeighborMap[index - 1]++; - mNeighborMap[index + 1]++; - mNeighborMap[index - mNeighborMapWidth]++; - mNeighborMap[index + mNeighborMapWidth]++; - } - - for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) - { - U64 handle = (*it).first; - LLSimInfo* info = (*it).second; - - U32 x_pos, y_pos; - from_region_handle(handle, &x_pos, &y_pos); - x_pos /= REGION_WIDTH_UNITS; - y_pos /= REGION_WIDTH_UNITS; - x_pos -= min_x; - y_pos -= min_y; - - S32 index = x_pos + (mNeighborMapWidth * y_pos); - - if (!info->mTelehubName.empty() && mNeighborMap[index]) - { - S32 x_start = llmax(0, S32(x_pos - 5)); - S32 x_span = llmin(mNeighborMapWidth - 1, (S32)(x_pos + 5)) - x_start + 1; - S32 y_start = llmax(0, (S32)y_pos - 5); - S32 y_end = llmin(mNeighborMapHeight - 1, (S32)(y_pos + 5)); - for (S32 y_index = y_start; y_index <= y_end; y_index++) - { - memset(&mTelehubCoverageMap[x_start + y_index * mNeighborMapWidth], 0xff, sizeof(U8) * x_span); - } - } - } - - for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it) - { - U64 handle = (*it).first; - //LLSimInfo* info = (*it).second; - - U32 x_pos, y_pos; - from_region_handle(handle, &x_pos, &y_pos); - x_pos /= REGION_WIDTH_UNITS; - y_pos /= REGION_WIDTH_UNITS; - - S32 index = x_pos - min_x + (mNeighborMapWidth * (y_pos - min_y)); - mTelehubCoverageMap[index] *= mNeighborMap[index]; - }*/ -} diff --git a/indra/newview/llworldmap.h b/indra/newview/llworldmap.h index b7089f348..ffa7b2443 100644 --- a/indra/newview/llworldmap.h +++ b/indra/newview/llworldmap.h @@ -33,207 +33,245 @@ #ifndef LL_LLWORLDMAP_H #define LL_LLWORLDMAP_H -#include -#include -#include +#include "llworldmipmap.h" -#include "v3math.h" #include "v3dmath.h" -#include "llframetimer.h" -#include "llmapimagetype.h" #include "lluuid.h" #include "llmemory.h" +#include "llviewerregion.h" #include "llviewerimage.h" -#include "lleventinfo.h" -#include "v3color.h" - -class LLMessageSystem; - +// Description of objects like hubs, events, land for sale, people and more (TBD). +// Note: we don't store a "type" in there so we need to store instances of this class in +// well known objects (i.e. list of objects which type is "well known"). class LLItemInfo { public: - LLItemInfo(F32 global_x, F32 global_y, const std::string& name, LLUUID id, S32 extra = 0, S32 extra2 = 0); + LLItemInfo(F32 global_x, F32 global_y, const std::string& name, LLUUID id); - std::string mName; - std::string mToolTip; - LLVector3d mPosGlobal; - LLUUID mID; - BOOL mSelected; - S32 mExtra; - S32 mExtra2; - U64 mRegionHandle; + // Setters + void setTooltip(std::string& tooltip) { mToolTip = tooltip; } + void setElevation(F64 z) { mPosGlobal.mdV[VZ] = z; } + void setCount(S32 count) { mCount = count; } +// void setSelected(bool selected) { mSelected = selected; } +// void setColor(LLColor4 color) { mColor = color; } + + // Accessors + const LLVector3d& getGlobalPosition() const { return mPosGlobal; } + const std::string& getName() const { return mName; } + const std::string& getToolTip() const { return mToolTip; } + const LLUUID& getUUID() const { return mID; } + S32 getCount() const { return mCount; } + + U64 getRegionHandle() const { return to_region_handle(mPosGlobal); } // Build the handle on the fly + + bool isName(const std::string& name) const { return (mName == name); } // True if name same as item's name +// bool isSelected() const { return mSelected; } + +private: + std::string mName; // Name of the individual item + std::string mToolTip; // Tooltip : typically, something to be displayed to the user when selecting this item + LLVector3d mPosGlobal; // Global world position + LLUUID mID; // UUID of the item + S32 mCount; // Number of elements in item (e.g. people count) + // Currently not used but might prove useful one day so we comment out +// bool mSelected; // Selected or not: updated by the viewer UI, not the simulator or asset DB +// LLColor4 mColor; // Color of the item }; -#define MAP_SIM_IMAGE_TYPES 3 -// 0 - Prim -// 1 - Terrain Only -// 2 - Overlay: Land For Sale - +// Info per region +// Such records are stored in a global map hold by the LLWorldMap and indexed by region handles. +// To avoid creating too many of them, they are requested in "blocks" corresponding to areas covered by the screen. +// Unfortunately, when the screen covers the whole world (zoomed out), that can translate in requesting info for +// every sim on the grid... Not good... +// To avoid this, the code implements a cut-off threshold for overlay graphics and, therefore, all LLSimInfo. +// In other words, when zooming out too much, we simply stop requesting LLSimInfo and +// LLItemInfo and just display the map tiles. +// As they are stored in different structures (LLSimInfo and LLWorldMipmap), this strategy is now workable. class LLSimInfo { public: - LLSimInfo(); + LLSimInfo(U64 handle); - LLVector3d getGlobalPos(LLVector3 local_pos) const; + // Convert local region coordinates into world coordinates + LLVector3d getGlobalPos(const LLVector3& local_pos) const; // Get the world coordinates of the SW corner of that region LLVector3d getGlobalOrigin() const; -public: - U64 mHandle; - std::string mName; + void clearImage(); // Clears the reference to the Land for sale image for that region + void dropImagePriority(); // Drops the boost level of the Land for sale image for that region + void updateAgentCount(F64 time); // Send an item request for agent count on that region if time's up - F64 mAgentsUpdateTime; - BOOL mShowAgentLocations; // are agents visible? + // Setters + void setName(std::string& name) { mName = name; } + void setAccess (U32 accesscode) { mAccess = accesscode; } + void setRegionFlags (U32 region_flags) { mRegionFlags = region_flags; } + void setLandForSaleImage (LLUUID image_id); +// void setWaterHeight (F32 water_height) { mWaterHeight = water_height; } - U8 mAccess; - U32 mRegionFlags; - F32 mWaterHeight; + // Accessors + const std::string getName() const { return mName; } + const std::string getFlagsString() const { return LLViewerRegion::regionFlagsToString(mRegionFlags); } + const std::string getAccessString() const { return LLViewerRegion::accessToString((U8)mAccess); } + const std::string getShortAccessString() const { return LLViewerRegion::accessToShortString((U8)mAccess); } - F32 mAlpha; + const S32 getAgentCount() const; // Compute the total agents count + LLPointer getLandForSaleImage(); // Get the overlay image, fetch it if necessary + // + //Added this so I could get map images on opensim. + const LLUUID getMapImageID() const { return mMapImageID; } - // Image ID for the current overlay mode. - LLUUID mMapImageID[MAP_SIM_IMAGE_TYPES]; + bool isName(const std::string& name) const; + bool isDown() { return (mAccess == SIM_ACCESS_DOWN); } + bool isPG() { return (mAccess <= SIM_ACCESS_PG); } - // Hold a reference to the currently displayed image. - LLPointer mCurrentImage; - LLPointer mOverlayImage; -}; - -#define MAP_BLOCK_RES 256 - -struct LLWorldMapLayer -{ - BOOL LayerDefined; - LLPointer LayerImage; - LLUUID LayerImageID; - LLRect LayerExtents; - - LLWorldMapLayer() : LayerDefined(FALSE) { } + // Debug only + void dump() const; // Print the region info to the standard output + + // Items lists handling + typedef std::vector item_info_list_t; + void clearItems(); + + void insertTeleHub(const LLItemInfo& item) { mTelehubs.push_back(item); } + void insertInfoHub(const LLItemInfo& item) { mInfohubs.push_back(item); } + void insertPGEvent(const LLItemInfo& item) { mPGEvents.push_back(item); } + void insertMatureEvent(const LLItemInfo& item) { mMatureEvents.push_back(item); } + void insertAdultEvent(const LLItemInfo& item) { mAdultEvents.push_back(item); } + void insertLandForSale(const LLItemInfo& item) { mLandForSale.push_back(item); } + void insertLandForSaleAdult(const LLItemInfo& item) { mLandForSaleAdult.push_back(item); } + void insertAgentLocation(const LLItemInfo& item); + + const LLSimInfo::item_info_list_t& getTeleHub() const { return mTelehubs; } + const LLSimInfo::item_info_list_t& getInfoHub() const { return mInfohubs; } + const LLSimInfo::item_info_list_t& getPGEvent() const { return mPGEvents; } + const LLSimInfo::item_info_list_t& getMatureEvent() const { return mMatureEvents; } + const LLSimInfo::item_info_list_t& getAdultEvent() const { return mAdultEvents; } + const LLSimInfo::item_info_list_t& getLandForSale() const { return mLandForSale; } + const LLSimInfo::item_info_list_t& getLandForSaleAdult() const { return mLandForSaleAdult; } + const LLSimInfo::item_info_list_t& getAgentLocation() const { return mAgentLocations; } + +private: + U64 mHandle; // This is a hash of the X and Y world coordinates of the SW corner of the sim + std::string mName; // Region name + + F64 mAgentsUpdateTime; // Time stamp giving the last time the agents information was requested for that region + bool mFirstAgentRequest; // Init agent request flag + + U32 mAccess; // Down/up and maturity rating of the region + U32 mRegionFlags; // Tell us if the siminfo has been received (if non 0) and what kind of region it is (Sandbox, allow damage) + // Currently not used but might prove useful one day so we comment out +// F32 mWaterHeight; // Water height on the region (not actively used) + + // Handling the "land for sale / land for auction" overlay image + + LLUUID mMapImageID; // Image ID of the overlay image + LLPointer mOverlayImage; // Reference to the overlay image + + // Items for this region + // Those are data received through item requests (as opposed to block requests for the rest of the data) + item_info_list_t mTelehubs; // List of tele hubs in the region + item_info_list_t mInfohubs; // List of info hubs in the region + item_info_list_t mPGEvents; // List of PG events in the region + item_info_list_t mMatureEvents; // List of Mature events in the region + item_info_list_t mAdultEvents; // List of Adult events in the region (AO) + item_info_list_t mLandForSale; // List of Land for sales in the region + item_info_list_t mLandForSaleAdult; // List of Adult Land for sales in the region (AO) + item_info_list_t mAgentLocations; // List of agents in the region }; +// We request region data on the world by "blocks" of (MAP_BLOCK_SIZE x MAP_BLOCK_SIZE) regions +// This is to reduce the number of requests to the asset DB and get things in big "blocks" +const S32 MAP_MAX_SIZE = 2048; +const S32 MAP_BLOCK_SIZE = 4; +const S32 MAP_BLOCK_RES = (MAP_MAX_SIZE / MAP_BLOCK_SIZE); class LLWorldMap : public LLSingleton { public: - typedef void(*url_callback_t)(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport); - LLWorldMap(); ~LLWorldMap(); - // clears the list + // Clear all: list of region info, tiles, blocks and items void reset(); - // clear the visible items - void eraseItems(); + void clearImageRefs(); // Clears the image references + void dropImagePriorities(); // Drops the priority of the images being fetched + void reloadItems(bool force = false); // Reload the items (people, hub, etc...) - // Removes references to cached images - void clearImageRefs(); + // Region Map access + typedef std::map sim_info_map_t; + const LLWorldMap::sim_info_map_t& getRegionMap() const { return mSimInfoMap; } + void updateRegions(S32 x0, S32 y0, S32 x1, S32 y1); // Requests region info for a rectangle of regions (in grid coordinates) - // Clears the flags indicating that we've received sim infos - // Causes a re-request of the sim info without erasing extisting info - void clearSimFlags(); + // Insert a region and items in the map global instance + // Note: x_world and y_world in world coordinates (meters) + static bool insertRegion(U32 x_world, U32 y_world, std::string& name, LLUUID& uuid, U32 accesscode, U32 region_flags); + static bool insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& uuid, U32 type, S32 extra, S32 extra2); - // Returns simulator information, or NULL if out of range + // Get info on sims (region) : note that those methods only search the range of loaded sims (the one that are being browsed) + // *not* the entire world. So a NULL return does not mean a down or unexisting region, just an out of range region. LLSimInfo* simInfoFromHandle(const U64 handle); - - // Returns simulator information, or NULL if out of range LLSimInfo* simInfoFromPosGlobal(const LLVector3d& pos_global); - - // Returns simulator information for named sim, or NULL if non-existent LLSimInfo* simInfoFromName(const std::string& sim_name); - // Gets simulator name for a global position, returns true if it was found + // Gets simulator name from a global position, returns true if found bool simNameFromPosGlobal(const LLVector3d& pos_global, std::string& outSimName ); - // Sets the current layer - void setCurrentLayer(S32 layer, bool request_layer = false); + // Debug only + void dump(); // Print the world info to the standard output - void sendMapLayerRequest(); - void sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent = false); - void sendNamedRegionRequest(std::string region_name); - void sendNamedRegionRequest(std::string region_name, - url_callback_t callback, - const std::string& callback_url, - bool teleport); - void sendHandleRegionRequest(U64 region_handle, - url_callback_t callback, - const std::string& callback_url, - bool teleport); - void sendItemRequest(U32 type, U64 handle = 0); + // Track handling + void cancelTracking() { mIsTrackingLocation = false; mIsTrackingFound = false; mIsInvalidLocation = false; mIsTrackingDoubleClick = false; mIsTrackingCommit = false; } - static void processMapLayerReply(LLMessageSystem*, void**); - static void processMapBlockReply(LLMessageSystem*, void**); - static void processMapItemReply(LLMessageSystem*, void**); + void setTracking(const LLVector3d& loc) { mIsTrackingLocation = true; mTrackingLocation = loc; mIsTrackingFound = false; mIsInvalidLocation = false; mIsTrackingDoubleClick = false; mIsTrackingCommit = false;} + void setTrackingInvalid() { mIsTrackingFound = true; mIsInvalidLocation = true; } + void setTrackingValid() { mIsTrackingFound = true; mIsInvalidLocation = false; } + void setTrackingDoubleClick() { mIsTrackingDoubleClick = true; } + void setTrackingCommit() { mIsTrackingCommit = true; } - static void gotMapServerURL(bool flag) { sGotMapURL = flag; } - static bool useWebMapTiles(); - static LLPointer loadObjectsTile(U32 grid_x, U32 grid_y); + bool isTracking() { return mIsTrackingLocation; } + bool isTrackingValidLocation() { return mIsTrackingFound && !mIsInvalidLocation; } + bool isTrackingInvalidLocation() { return mIsTrackingFound && mIsInvalidLocation; } + bool isTrackingDoubleClick() { return mIsTrackingDoubleClick; } + bool isTrackingCommit() { return mIsTrackingCommit; } + bool isTrackingInRectangle(F64 x0, F64 y0, F64 x1, F64 y1); - void dump(); + LLVector3d getTrackedPositionGlobal() const { return mTrackingLocation; } - // Extend the bounding box of the list of simulators. Returns true - // if the extents changed. - BOOL extendAABB(U32 x_min, U32 y_min, U32 x_max, U32 y_max); - - // build coverage maps for telehub region visualization - void updateTelehubCoverage(); - BOOL coveredByTelehub(LLSimInfo* infop); - - // Bounds of the world, in meters - U32 getWorldWidth() const; - U32 getWorldHeight() const; -public: - // Map from region-handle to simulator info - typedef std::map sim_info_map_t; - sim_info_map_t mSimInfoMap; - - BOOL mIsTrackingUnknownLocation, mInvalidLocation, mIsTrackingDoubleClick, mIsTrackingCommit; - LLVector3d mUnknownLocation; - - bool mRequestLandForSale; - - typedef std::vector item_info_list_t; - item_info_list_t mTelehubs; - item_info_list_t mInfohubs; - item_info_list_t mPGEvents; - item_info_list_t mMatureEvents; - item_info_list_t mAdultEvents; - item_info_list_t mLandForSale; - item_info_list_t mLandForSaleAdult; - - std::map mNumAgents; - - typedef std::map agent_list_map_t; - agent_list_map_t mAgentLocationsMap; - - std::vector mMapLayers[MAP_SIM_IMAGE_TYPES]; - BOOL mMapLoaded[MAP_SIM_IMAGE_TYPES]; - BOOL * mMapBlockLoaded[MAP_SIM_IMAGE_TYPES]; - S32 mCurrentMap; - - // AABB of the list of simulators - U32 mMinX; - U32 mMaxX; - U32 mMinY; - U32 mMaxY; - - U8* mNeighborMap; - U8* mTelehubCoverageMap; - S32 mNeighborMapWidth; - S32 mNeighborMapHeight; + // World Mipmap delegation: currently used when drawing the mipmap + void equalizeBoostLevels(); + LLPointer getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load = true) { return mWorldMipmap.getObjectsTile(grid_x, grid_y, level, load); } private: - LLTimer mRequestTimer; + bool clearItems(bool force = false); // Clears the item lists + void clearSimFlags(); // Clears the block flags indicating that we've already requested region infos - // search for named region for url processing - std::string mSLURLRegionName; - U64 mSLURLRegionHandle; - std::string mSLURL; - url_callback_t mSLURLCallback; - bool mSLURLTeleport; + // Create a region record corresponding to the handle, insert it in the region map and returns a pointer + LLSimInfo* createSimInfoFromHandle(const U64 handle); - static bool sGotMapURL; + // Map from region-handle to region info + sim_info_map_t mSimInfoMap; + + // Holds the tiled mipmap of the world. This is the structure that contains the images used for rendering. + LLWorldMipmap mWorldMipmap; + + // The World is divided in "blocks" of (MAP_BLOCK_SIZE x MAP_BLOCK_SIZE) regions that get requested at once. + // This boolean table avoids "blocks" to be requested multiple times. + // Issue: Not sure this scheme is foolproof though as I've seen + // cases where a block is never retrieved and, because of this boolean being set, never re-requested + bool * mMapBlockLoaded; // Telling us if the block of regions has been requested or not + + // Track location data : used while there's nothing tracked yet by LLTracker + bool mIsTrackingLocation; // True when we're tracking a point + bool mIsTrackingFound; // True when the tracking position has been found, valid or not + bool mIsInvalidLocation; // The region is down or the location does not correspond to an existing region + bool mIsTrackingDoubleClick; // User double clicked to set the location (i.e. teleport when found please...) + bool mIsTrackingCommit; // User used the search or landmark fields to set the location + LLVector3d mTrackingLocation; // World global position being tracked + + // General grid items request timing flags (used for events,hubs and land for sale) + LLTimer mRequestTimer; + bool mFirstRequest; }; #endif diff --git a/indra/newview/llworldmapmessage.cpp b/indra/newview/llworldmapmessage.cpp new file mode 100644 index 000000000..0777a77e9 --- /dev/null +++ b/indra/newview/llworldmapmessage.cpp @@ -0,0 +1,274 @@ +/** + * @file llworldmapmessage.cpp + * @brief Handling of the messages to the DB made by and for the world map. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llworldmapmessage.h" + +#include "llworldmap.h" +#include "llagent.h" +#include "llfloaterworldmap.h" + +#include "llviewernetwork.h" //for isInProductionGrid() +#include "hippogridmanager.h" + +const U32 LAYER_FLAG = 2; + +//--------------------------------------------------------------------------- +// World Map Message Handling +//--------------------------------------------------------------------------- + +LLWorldMapMessage::LLWorldMapMessage() : + mSLURLRegionName(), + mSLURLRegionHandle(0), + mSLURL(), + mSLURLCallback(0), + mSLURLTeleport(false) +{ +} + +LLWorldMapMessage::~LLWorldMapMessage() +{ +} + +void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle) +{ + //LL_INFOS("World Map") << "Send item request : type = " << type << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + + msg->newMessageFast(_PREHASH_MapItemRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addU32Fast(_PREHASH_Flags, LAYER_FLAG); + msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim + msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim + + msg->nextBlockFast(_PREHASH_RequestData); + msg->addU32Fast(_PREHASH_ItemType, type); + msg->addU64Fast(_PREHASH_RegionHandle, handle); // If zero, filled in on sim + + gAgent.sendReliableMessage(); +} + +void LLWorldMapMessage::sendNamedRegionRequest(std::string region_name) +{ + //LL_INFOS("World Map") << "LLWorldMap::sendNamedRegionRequest()" << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + + // Request for region data + msg->newMessageFast(_PREHASH_MapNameRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + msg->addU32Fast(_PREHASH_Flags, LAYER_FLAG); + msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim + msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim + msg->nextBlockFast(_PREHASH_NameData); + msg->addStringFast(_PREHASH_Name, region_name); + gAgent.sendReliableMessage(); +} + +void LLWorldMapMessage::sendNamedRegionRequest(std::string region_name, + url_callback_t callback, + const std::string& callback_url, + bool teleport) // immediately teleport when result returned +{ + //LL_INFOS("World Map") << "LLWorldMap::sendNamedRegionRequest()" << LL_ENDL; + mSLURLRegionName = region_name; + mSLURLRegionHandle = 0; + mSLURL = callback_url; + mSLURLCallback = callback; + mSLURLTeleport = teleport; + + sendNamedRegionRequest(region_name); +} + +void LLWorldMapMessage::sendHandleRegionRequest(U64 region_handle, + url_callback_t callback, + const std::string& callback_url, + bool teleport) // immediately teleport when result returned +{ + //LL_INFOS("World Map") << "LLWorldMap::sendHandleRegionRequest()" << LL_ENDL; + mSLURLRegionName.clear(); + mSLURLRegionHandle = region_handle; + mSLURL = callback_url; + mSLURLCallback = callback; + mSLURLTeleport = teleport; + + U32 global_x; + U32 global_y; + from_region_handle(region_handle, &global_x, &global_y); + U16 grid_x = (U16)(global_x / REGION_WIDTH_UNITS); + U16 grid_y = (U16)(global_y / REGION_WIDTH_UNITS); + + sendMapBlockRequest(grid_x, grid_y, grid_x, grid_y, true); +} + +void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) +{ + //LL_INFOS("World Map") << "LLWorldMap::sendMapBlockRequest()" << ", min = (" << min_x << ", " << min_y << "), max = (" << max_x << ", " << max_y << "), nonexistent = " << return_nonexistent << LL_ENDL; + LLMessageSystem* msg = gMessageSystem; + msg->newMessageFast(_PREHASH_MapBlockRequest); + msg->nextBlockFast(_PREHASH_AgentData); + msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); + msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID()); + U32 flags = LAYER_FLAG; + flags |= (return_nonexistent ? 0x10000 : 0); + msg->addU32Fast(_PREHASH_Flags, flags); + msg->addU32Fast(_PREHASH_EstateID, 0); // Filled in on sim + msg->addBOOLFast(_PREHASH_Godlike, FALSE); // Filled in on sim + msg->nextBlockFast(_PREHASH_PositionData); + msg->addU16Fast(_PREHASH_MinX, min_x); + msg->addU16Fast(_PREHASH_MinY, min_y); + msg->addU16Fast(_PREHASH_MaxX, max_x); + msg->addU16Fast(_PREHASH_MaxY, max_y); + gAgent.sendReliableMessage(); +} + +// public static +void LLWorldMapMessage::processMapBlockReply(LLMessageSystem* msg, void**) +{ + U32 agent_flags; + msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags); + + // There's only one flag that we ever use here + if (agent_flags != LAYER_FLAG + && gHippoGridManager->getConnectedGrid()->getPlatform() == HippoGridInfo::PLATFORM_SECONDLIFE) + { + llwarns << "Invalid map image type returned! layer = " << agent_flags << llendl; + return; + } + + S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data); + //LL_INFOS("World Map") << "LLWorldMap::processMapBlockReply(), num_blocks = " << num_blocks << LL_ENDL; + + bool found_null_sim = false; + + for (S32 block=0; blockgetU16Fast(_PREHASH_Data, _PREHASH_X, x_regions, block); + msg->getU16Fast(_PREHASH_Data, _PREHASH_Y, y_regions, block); + msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block); + msg->getU8Fast(_PREHASH_Data, _PREHASH_Access, accesscode, block); + msg->getU32Fast(_PREHASH_Data, _PREHASH_RegionFlags, region_flags, block); +// msg->getU8Fast(_PREHASH_Data, _PREHASH_WaterHeight, water_height, block); +// msg->getU8Fast(_PREHASH_Data, _PREHASH_Agents, agents, block); + msg->getUUIDFast(_PREHASH_Data, _PREHASH_MapImageID, image_id, block); + + U32 x_world = (U32)(x_regions) * REGION_WIDTH_UNITS; + U32 y_world = (U32)(y_regions) * REGION_WIDTH_UNITS; + + // Insert that region in the world map, if failure, flag it as a "null_sim" + if (!(LLWorldMap::getInstance()->insertRegion(x_world, y_world, name, image_id, (U32)accesscode, region_flags))) + { + found_null_sim = true; + } + + // If we hit a valid tracking location, do what needs to be done app level wise + if (LLWorldMap::getInstance()->isTrackingValidLocation()) + { + LLVector3d pos_global = LLWorldMap::getInstance()->getTrackedPositionGlobal(); + if (LLWorldMap::getInstance()->isTrackingDoubleClick()) + { + // Teleport if the user double clicked + gAgent.teleportViaLocation(pos_global); + } + // Update the "real" tracker information + gFloaterWorldMap->trackLocation(pos_global); + } + + // Handle the SLURL callback if any + if(LLWorldMapMessage::getInstance()->mSLURLCallback != NULL) + { + U64 handle = to_region_handle(x_world, y_world); + // Check if we reached the requested region + if ((LLStringUtil::compareInsensitive(LLWorldMapMessage::getInstance()->mSLURLRegionName, name)==0) + || (LLWorldMapMessage::getInstance()->mSLURLRegionHandle == handle)) + { + url_callback_t callback = LLWorldMapMessage::getInstance()->mSLURLCallback; + + LLWorldMapMessage::getInstance()->mSLURLCallback = NULL; + LLWorldMapMessage::getInstance()->mSLURLRegionName.clear(); + LLWorldMapMessage::getInstance()->mSLURLRegionHandle = 0; + + callback(handle, LLWorldMapMessage::getInstance()->mSLURL, image_id, LLWorldMapMessage::getInstance()->mSLURLTeleport); + } + } + // + if(LLAgent::lure_show) + { + if((x_regions == LLAgent::lure_global_x) && (y_regions == LLAgent::lure_global_y)) + { + gAgent.onFoundLureDestination(); + } + } + // + } + // Tell the UI to update itself + gFloaterWorldMap->updateSims(found_null_sim); +} + +// public static +void LLWorldMapMessage::processMapItemReply(LLMessageSystem* msg, void**) +{ + //LL_INFOS("World Map") << "LLWorldMap::processMapItemReply()" << LL_ENDL; + U32 type; + msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ItemType, type); + + S32 num_blocks = msg->getNumberOfBlocks("Data"); + + for (S32 block=0; blockgetU32Fast(_PREHASH_Data, _PREHASH_X, X, block); + msg->getU32Fast(_PREHASH_Data, _PREHASH_Y, Y, block); + msg->getStringFast(_PREHASH_Data, _PREHASH_Name, name, block); + msg->getUUIDFast(_PREHASH_Data, _PREHASH_ID, uuid, block); + msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra, extra, block); + msg->getS32Fast(_PREHASH_Data, _PREHASH_Extra2, extra2, block); + + LLWorldMap::getInstance()->insertItem(X, Y, name, uuid, type, extra, extra2); + } +} + diff --git a/indra/newview/llworldmapmessage.h b/indra/newview/llworldmapmessage.h new file mode 100644 index 000000000..96434661b --- /dev/null +++ b/indra/newview/llworldmapmessage.h @@ -0,0 +1,82 @@ +/** + * @file llworldmapmessage.h + * @brief Handling of the messages to the DB made by and for the world map. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLWORLDMAPMESSAGE_H +#define LL_LLWORLDMAPMESSAGE_H + +// Handling of messages (send and process) as well as SLURL callback if necessary +class LLMessageSystem; + +class LLWorldMapMessage : public LLSingleton +{ +public: + typedef void(*url_callback_t)(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport); + + LLWorldMapMessage(); + ~LLWorldMapMessage(); + + // Process incoming answers to map stuff requests + static void processMapBlockReply(LLMessageSystem*, void**); + static void processMapItemReply(LLMessageSystem*, void**); + + // Request data for all regions in a rectangular area. Coordinates in grids (i.e. meters / 256). + void sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent = false); + + // Various methods to request LLSimInfo data to the simulator and asset DB + void sendNamedRegionRequest(std::string region_name); + void sendNamedRegionRequest(std::string region_name, + url_callback_t callback, + const std::string& callback_url, + bool teleport); + void sendHandleRegionRequest(U64 region_handle, + url_callback_t callback, + const std::string& callback_url, + bool teleport); + + // Request item data for regions + // Note: the handle works *only* when requesting agent count (type = MAP_ITEM_AGENT_LOCATIONS). In that case, + // the request will actually be transitting through the spaceserver (all that is done on the sim). + // All other values of type do create a global grid request to the asset DB. So no need to try to get, say, + // the events for one particular region. For such a request, the handle is ignored. + void sendItemRequest(U32 type, U64 handle = 0); + +private: + // Search for region (by name or handle) for SLURL processing and teleport + // None of this relies explicitly on the LLWorldMap instance so better handle it here + std::string mSLURLRegionName; + U64 mSLURLRegionHandle; + std::string mSLURL; + url_callback_t mSLURLCallback; + bool mSLURLTeleport; +}; + +#endif // LL_LLWORLDMAPMESSAGE_H diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 6bfd93afd..42cf50a26 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -34,18 +34,11 @@ #include "llworldmapview.h" -#include "indra_constants.h" -#include "llui.h" -#include "llmath.h" // clampf() -#include "llregionhandle.h" -#include "lleventflags.h" #include "llrender.h" - #include "llagent.h" #include "llcallingcard.h" #include "llcolorscheme.h" #include "llviewercontrol.h" -#include "llcylinder.h" #include "llfloaterdirectory.h" #include "llfloatermap.h" #include "llfloaterworldmap.h" @@ -56,13 +49,8 @@ #include "llviewercamera.h" #include "llviewerimage.h" #include "llviewerimagelist.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" @@ -71,6 +59,14 @@ #include "rlvhandler.h" // [/RLVa:KB] +// 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; @@ -97,27 +93,24 @@ 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; +bool LLWorldMapView::sVisibleTilesLoaded = false; F32 LLWorldMapView::sMapScale = 128.f; -F32 CONE_SIZE = 0.6f; std::map 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() @@ -174,7 +167,7 @@ void LLWorldMapView::cleanupClass() LLWorldMapView::LLWorldMapView(const std::string& name, const LLRect& rect ) : LLPanel(name, rect, BORDER_NO), - 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 ), @@ -183,7 +176,8 @@ LLWorldMapView::LLWorldMapView(const std::string& name, const LLRect& rect ) mMouseDownY( 0 ), mSelectIDStart(0) { - sPixelsPerMeter = sMapScale / REGION_WIDTH_METERS; + //LL_INFOS("World Map") << "Creating the Map -> LLWorldMapView::LLWorldMapView()" << LL_ENDL; + clearLastClick(); const S32 DIR_WIDTH = 10; @@ -231,6 +225,7 @@ LLWorldMapView::LLWorldMapView(const std::string& name, const LLRect& rect ) LLWorldMapView::~LLWorldMapView() { + //LL_INFOS("World Map") << "Destroying the map -> LLWorldMapView::~LLWorldMapView()" << LL_ENDL; cleanupTextures(); } @@ -249,7 +244,7 @@ void LLWorldMapView::setScale( F32 scale ) F32 old_scale = sMapScale; sMapScale = scale; - if (sMapScale == 0.f) + if (sMapScale <= 0.f) { sMapScale = 0.1f; } @@ -259,8 +254,7 @@ void LLWorldMapView::setScale( F32 scale ) sPanY *= ratio; sTargetPanX = sPanX; sTargetPanY = sPanY; - - sPixelsPerMeter = sMapScale / REGION_WIDTH_METERS; + sVisibleTilesLoaded = false; } } @@ -272,6 +266,7 @@ void LLWorldMapView::translatePan( S32 delta_x, S32 delta_y ) sPanY += delta_y; sTargetPanX = sPanX; sTargetPanY = sPanY; + sVisibleTilesLoaded = false; } @@ -285,18 +280,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() @@ -317,6 +316,10 @@ void LLWorldMapView::draw() const F32 half_height = F32(height) / 2.0f; LLVector3d camera_global = gAgent.getCameraPositionGlobal(); + S32 level = LLWorldMipmap::scaleToLevel(sMapScale); + + //LL_INFOS("World Map") << "Entering LLWorldMapView::draw(): scale = " << sMapScale << ", w = " << width << ", h = " << height << ", x = " << sTargetPanX << ", y = " << sTargetPanY << ", camera = " << camera_global << LL_ENDL; + LLLocalClipRect clip(getLocalRect()); { gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); @@ -333,317 +336,58 @@ 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_idxmMapLayers[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]; - LLViewerImage *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) * sMapScale; - F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * sMapScale; - - F32 pix_width = sMapScale*(layer->LayerExtents.getWidth() + 1); - F32 pix_height = sMapScale*(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(LLViewerImageBoostLevel::BOOST_MAP_VISIBLE); - current_image->setKnownDrawSize(llround(pix_width * LLUI::sGLScaleFactor.mV[VX]), llround(pix_height * LLUI::sGLScaleFactor.mV[VY])); - - if (!current_image->getHasGLTexture()) - { - 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(); - } - - 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; +#if 1 + // Draw the image tiles + drawMipmap(width, height); + gGL.flush(); - // 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; + gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); + gGL.setColorMask(true, true); - bool use_web_map_tiles = LLWorldMap::useWebMapTiles(); - - 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; - - LLViewerImage* simimage = info->mCurrentImage; - LLViewerImage* overlayimage = info->mOverlayImage; - - if (sMapScale < SIM_MAP_SCALE) - { - if (simimage != NULL) simimage->setBoostLevel(0); - if (overlayimage != NULL) overlayimage->setBoostLevel(0); - continue; - } + U64 handle = it->first; + LLSimInfo* info = it->second; 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) * 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 + sMapScale ; F32 right = left + sMapScale ; - // 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) + // Discard if region is outside the screen rectangle (not visible on screen) + if ((top < 0.f) || (bottom > height) || + (right < 0.f) || (left > width) ) { - map_scale_cutoff = SIM_NULL_MAP_SCALE; - } - - info->mShowAgentLocations = (sMapScale >= SIM_MAP_AGENT_SCALE); - - bool sim_visible = - (sMapScale >= map_scale_cutoff) && - (simimage != NULL) && - (simimage->getHasGLTexture()); - - 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 ) - { - 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++; - if (use_web_map_tiles) - { - LLVector3d region_pos = info->getGlobalOrigin(); - info->mCurrentImage = LLWorldMap::loadObjectsTile((U32)(region_pos.mdV[VX] / REGION_WIDTH_UNITS), (U32)(region_pos.mdV[VY] / REGION_WIDTH_UNITS)); - } - else - { - info->mCurrentImage = gImageList.getImage(info->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE); - } - 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 = gImageList.getImage(info->mMapImageID[2], MIPMAP_TRUE, FALSE); - 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) + + // Update the agent count for that region if we're not too zoomed out already + if (level <= DRAW_SIMINFO_THRESHOLD) { - LLWorldMap::getInstance()->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, info->mHandle); - info->mAgentsUpdateTime = current_time; + info->updateAgentCount(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(sMapScale); - if (simimage != NULL) - { - simimage->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP); - simimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY])); - } - - if (overlayimage != NULL) - { - overlayimage->setBoostLevel(LLViewerImageBoostLevel::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) - { - // 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->getHasGLTexture()) - { - 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); - } - } - - 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); @@ -662,11 +406,9 @@ void LLWorldMapView::draw() // 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); @@ -679,71 +421,103 @@ void LLWorldMapView::draw() gGL.end(); } **********************/ - // Draw the region name in the lower left corner - LLFontGL* font = LLFontGL::getFontSansSerifSmall(); - - std::string mesg; - if (sMapScale < sThresholdA) + else if (gSavedSettings.getBOOL("MapShowLandForSale") && (level <= DRAW_LANDFORSALE_THRESHOLD)) { - } - else if (sMapScale < sThresholdB) - { - // mesg = llformat( info->mAgents); + // Draw the overlay image "Land for Sale / Land for Auction" + LLViewerImage* 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->getHasGLTexture()) + { + 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 we're not displaying the "land for sale", drop its fetching priority + info->dropImagePriority(); + } + + // 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() ); + LLFontGL* font = LLFontGL::getFontSansSerifSmall(); + std::string mesg; // [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Checked: 2009-07-04 (RLVa-1.0.0a) if (gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) { mesg = RlvStrings::getString(RLV_STRING_HIDDEN); } + else if (info->isDown()) // [/RLVa:KB] - else if (info->mAccess == SIM_ACCESS_DOWN) + //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 if (gSavedSettings.getBOOL("MapShowAgentCount") && gSavedSettings.getBOOL("MapShowPeople")) + { + // Display the agent count after the region name + S32 agent_count = info->getAgentCount(); + LLViewerRegion *region = gAgent.getRegion(); + + if (region && region->getHandle() == handle) + { + ++agent_count; // Bump by 1 if we're in this region + } + + if (agent_count > 0) + { + std::string count = llformat("%d %s", agent_count, agent_count > 1 ? "avatars" : "avatar"); + font->renderUTF8( + count, 0, + llfloor(left + 3), + llfloor(bottom + 20), + LLColor4::white, + LLFontGL::LEFT, + LLFontGL::BASELINE, + LLFontGL::DROP_SHADOW); + + } + mesg = info->getName() + " (" + info->getShortAccessString() +")"; + } + // else { - mesg = info->mName; + // + mesg = info->getName() + " (" + info->getShortAccessString() +")"; } - } - if (!mesg.empty()) { font->renderUTF8( mesg, 0, - llfloor(left + 3), - llfloor(bottom + 2), - LLColor4::white, - LLFontGL::LEFT, - LLFontGL::BASELINE, - LLFontGL::DROP_SHADOW); - - // If map texture is still loading, - // display "Loading" placeholder text. - if ((simimage != NULL) && - simimage->getDiscardLevel() != 1 && - simimage->getDiscardLevel() != 0) - { - font->renderUTF8( - sStringsMap["loading"], 0, - llfloor(left + 18), - llfloor(top - 25), + llfloor(left + 3), llfloor(bottom + 2), LLColor4::white, - LLFontGL::LEFT, - LLFontGL::BASELINE, - 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; { @@ -757,45 +531,25 @@ void LLWorldMapView::draw() gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); gGL.setSceneBlendType(LLRender::BT_ALPHA); - // Infohubs - if (gSavedSettings.getBOOL("MapShowInfohubs")) //(sMapScale >= 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")) //(sMapScale >= 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("MapShowPGEvents") || - gSavedSettings.getBOOL("MapShowMatureEvents") || - gSavedSettings.getBOOL("MapShowAdultEvents") ) - { - 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, sAvatarYouImage); @@ -810,12 +564,12 @@ void LLWorldMapView::draw() 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(); } @@ -837,23 +591,24 @@ void LLWorldMapView::draw() drawTracking( pos_global, gTrackColor, 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, "Invalid Location", ""); + drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, "Invalid Location", ""); } 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); LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0); - drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, "Loading...", ""); + drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, "Loading...", ""); } } - // #endif used to be here +#endif // turn off the scissor LLGLDisable no_scissor(GL_SCISSOR_TEST); @@ -862,6 +617,7 @@ void LLWorldMapView::draw() LLView::draw(); + // Get sim info for all sims in view updateVisibleBlocks(); } // end draw() @@ -872,36 +628,182 @@ void LLWorldMapView::setVisible(BOOL visible) LLPanel::setVisible(visible); if (!visible) { - for (S32 map = 0; map < MAP_SIM_IMAGE_TYPES; map++) - { - for (U32 layer_idx=0; layer_idxmMapLayers[map].size(); ++layer_idx) - { - if (LLWorldMap::getInstance()->mMapLayers[map][layer_idx].LayerDefined) - { - LLWorldMapLayer *layer = &LLWorldMap::getInstance()->mMapLayers[map][layer_idx]; - layer->LayerImage->setBoostLevel(0); - } - } - } - for (LLWorldMap::sim_info_map_t::iterator it = LLWorldMap::getInstance()->mSimInfoMap.begin(); - it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it) - { - LLSimInfo* info = (*it).second; - if (info->mCurrentImage.notNull()) - { - info->mCurrentImage->setBoostLevel(0); - } - if (info->mOverlayImage.notNull()) - { - info->mOverlayImage->setBoostLevel(0); - } - } + // Drop the download of tiles and images priority to nil if we hide the map + LLWorldMap::getInstance()->dropImagePriorities(); } } -void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items, LLUIImagePtr image) +void LLWorldMapView::drawMipmap(S32 width, S32 height) { - LLWorldMap::item_info_list_t::const_iterator e; + // 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--) + { + drawMipmapLevel(width, height, l, false); + } + // 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) + { + 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 simimage = LLWorldMap::getInstance()->getObjectsTile(grid_x, grid_y, level, load); + if (simimage) + { + // Check the texture state + if (simimage->getHasGLTexture()) + { + // 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; + //} + } + else + { + // 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 LLSimInfo::item_info_list_t& items, LLUIImagePtr image) +{ + LLSimInfo::item_info_list_t::const_iterator e; for (e = items.begin(); e != items.end(); ++e) { drawGenericItem(*e, image); @@ -910,7 +812,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); } @@ -933,132 +835,86 @@ void LLWorldMapView::drawImageStack(const LLVector3d& global_pos, LLUIImagePtr i } } - -void LLWorldMapView::drawAgents() -{ - F32 agents_scale = (sMapScale * 0.9f) / 256.f; - - LLColor4 avatar_color = gColors.getColor( "MapAvatar" ); - // LLColor4 friend_color = gColors.getColor( "MapFriend" ); - - 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)) - { - continue; - } - LLWorldMap::agent_list_map_t::iterator counts_iter = LLWorldMap::getInstance()->mAgentLocationsMap.find(handle); - if (siminfo && siminfo->mShowAgentLocations && counts_iter != LLWorldMap::getInstance()->mAgentLocationsMap.end()) - { - // 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)) ? friend_color : avatar_color; - drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count, 3.f, avatar_color); - } - LLWorldMap::getInstance()->mNumAgents[handle] = sim_agent_count; // override mNumAgents for this sim - } - else - { - // Show agent 'stack' at center of sim - S32 num_agents = LLWorldMap::getInstance()->mNumAgents[handle]; - if (num_agents > 0) - { - 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, avatar_color); - } - } - } -} - - -void LLWorldMapView::drawEvents() +void LLWorldMapView::drawItems() { bool mature_enabled = gAgent.canAccessMature(); bool adult_enabled = gAgent.canAccessAdult(); - BOOL show_pg = gSavedSettings.getBOOL("MapShowPGEvents"); - BOOL show_mature = mature_enabled && gSavedSettings.getBOOL("MapShowMatureEvents"); - BOOL show_adult = adult_enabled && gSavedSettings.getBOOL("MapShowAdultEvents"); + BOOL show_mature = mature_enabled && gSavedSettings.getBOOL("ShowMatureEvents"); + BOOL show_adult = adult_enabled && gSavedSettings.getBOOL("ShowAdultEvents"); - // 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* info = LLWorldMap::getInstance()->simInfoFromHandle(handle); + if ((info == NULL) || (info->isDown())) { - if (!e->mSelected) + continue; + } + // Infohubs + if (gSavedSettings.getBOOL("MapShowInfohubs")) { - drawGenericItem(*e, sEventImage); + drawGenericItems(info->getInfoHub(), sInfohubImage); + } + // Telehubs + if (gSavedSettings.getBOOL("MapShowTelehubs")) + { + drawGenericItems(info->getTeleHub(), sTelehubImage); + } + // Land for sale + if (gSavedSettings.getBOOL("MapShowLandForSale")) + { + 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()) + { + drawGenericItems(info->getLandForSaleAdult(), sForSaleAdultImage); } } + // PG Events + if (gSavedSettings.getBOOL("MapShowEvents")) + { + drawGenericItems(info->getPGEvent(), sEventImage); } + // Mature Events if (show_mature) { - for (e = LLWorldMap::getInstance()->mMatureEvents.begin(); e != LLWorldMap::getInstance()->mMatureEvents.end(); ++e) - { - if (!e->mSelected) - { - drawGenericItem(*e, sEventMatureImage); - } - } + drawGenericItems(info->getMatureEvent(), sEventMatureImage); } + // Adult Events 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) - { - if (e->mSelected) - { - drawGenericItem(*e, sEventImage); - } - } - } - 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); - } + drawGenericItems(info->getAdultEvent(), sEventAdultImage); } } } +void LLWorldMapView::drawAgents() +{ + LLColor4 avatar_color = gColors.getColor( "MapAvatar" ); + // LLColor4 friend_color = gColors.getColor( "MapFriend" ); + for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter) + { + U64 handle = *iter; + LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle); + if ((siminfo == NULL) || (siminfo->isDown())) + { + continue; + } + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAgentLocation().begin(); + while (it != siminfo->getAgentLocation().end()) + { + // 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, avatar_color); + ++it; + } + } +} void LLWorldMapView::drawFrustum() { @@ -1104,8 +960,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 @@ -1213,8 +1069,9 @@ LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y ) BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* sticky_rect_screen ) { LLVector3d pos_global = viewPosToGlobal(x, y); + U64 handle = to_region_handle(pos_global); - LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global); + LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle); if (info) { LLViewerRegion *region = gAgent.getRegion(); @@ -1222,14 +1079,14 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* stic // std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str()); // [RLVa:KB] - Alternate: Snowglobe-1.2.4 | Checked: 2009-07-04 (RLVa-1.0.0a) std::string message = llformat("%s (%s)", - (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? info->mName.c_str() : RlvStrings::getString(RLV_STRING_HIDDEN).c_str(), - LLViewerRegion::accessToString(info->mAccess).c_str()); + (!gRlvHandler.hasBehaviour(RLV_BHVR_SHOWLOC)) ? info->getName().c_str() : RlvStrings::getString(RLV_STRING_HIDDEN).c_str(), + info->getAccessString().c_str()); // [/RLVa:KB] - 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 } @@ -1238,28 +1095,35 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, std::string& msg, LLRect* stic // 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) { - message += "avatar"; + // + message += "agents"; } else { - message += "avatars"; + // + message += "agents"; } } } msg.assign( message ); // Optionally show region flags - std::string region_flags = LLViewerRegion::regionFlagsToString(info->mRegionFlags); + std::string region_flags = info->getFlagsString(); + // + // always seems to be zero anyways... if (!region_flags.empty()) { msg += '\n'; - msg += region_flags; + msg += "Region Flags: " + region_flags; } + // S32 SLOP = 4; localPointToScreen( @@ -1603,7 +1467,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]); @@ -1612,12 +1476,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()); } } @@ -1626,8 +1490,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; } @@ -1650,37 +1514,34 @@ 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; + S32 level = LLWorldMipmap::scaleToLevel(sMapScale); + // If the zoom level is not too far out already, test hits + if (level <= DRAW_SIMINFO_THRESHOLD) + { + bool show_mature = gAgent.canAccessMature() && gSavedSettings.getBOOL("ShowMatureEvents"); + bool show_adult = gAgent.canAccessAdult() && gSavedSettings.getBOOL("ShowAdultEvents"); - // clear old selected stuff - for (it = LLWorldMap::getInstance()->mPGEvents.begin(); it != LLWorldMap::getInstance()->mPGEvents.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")) { - (*it).mSelected = FALSE; - } - for (it = LLWorldMap::getInstance()->mMatureEvents.begin(); it != LLWorldMap::getInstance()->mMatureEvents.end(); ++it) + // Iterate through the visible regions + for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter) { - (*it).mSelected = FALSE; - } - for (it = LLWorldMap::getInstance()->mAdultEvents.begin(); it != LLWorldMap::getInstance()->mAdultEvents.end(); ++it) + U64 handle = *iter; + LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle); + if ((siminfo == NULL) || (siminfo->isDown())) { - (*it).mSelected = FALSE; + continue; } - for (it = LLWorldMap::getInstance()->mLandForSale.begin(); it != LLWorldMap::getInstance()->mLandForSale.end(); ++it) + // If on screen check hits with the visible item lists + if (gSavedSettings.getBOOL("MapShowEvents")) { - (*it).mSelected = FALSE; - } - - // Select event you clicked on - if (gSavedSettings.getBOOL("MapShowPGEvents")) + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getPGEvent().begin(); + while (it != siminfo->getPGEvent().end()) { - for (it = LLWorldMap::getInstance()->mPGEvents.begin(); it != LLWorldMap::getInstance()->mPGEvents.end(); ++it) - { - LLItemInfo& event = *it; - + LLItemInfo event = *it; if (checkItemHit(x, y, event, id, false)) { *hit_type = MAP_ITEM_PG_EVENT; @@ -1688,14 +1549,15 @@ void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask, gFloaterWorldMap->trackEvent(event); return; } + ++it; } } - if (gSavedSettings.getBOOL("MapShowMatureEvents")) + if (show_mature) { - for (it = LLWorldMap::getInstance()->mMatureEvents.begin(); it != LLWorldMap::getInstance()->mMatureEvents.end(); ++it) + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getMatureEvent().begin(); + while (it != siminfo->getMatureEvent().end()) { - LLItemInfo& event = *it; - + LLItemInfo event = *it; if (checkItemHit(x, y, event, id, false)) { *hit_type = MAP_ITEM_MATURE_EVENT; @@ -1703,14 +1565,15 @@ void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask, gFloaterWorldMap->trackEvent(event); return; } + ++it; } } - if (gSavedSettings.getBOOL("MapShowAdultEvents")) + if (show_adult) { - for (it = LLWorldMap::getInstance()->mAdultEvents.begin(); it != LLWorldMap::getInstance()->mAdultEvents.end(); ++it) + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAdultEvent().begin(); + while (it != siminfo->getAdultEvent().end()) { - LLItemInfo& event = *it; - + LLItemInfo event = *it; if (checkItemHit(x, y, event, id, false)) { *hit_type = MAP_ITEM_ADULT_EVENT; @@ -1718,40 +1581,49 @@ void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask, gFloaterWorldMap->trackEvent(event); return; } + ++it; } } - if (gSavedSettings.getBOOL("MapShowLandForSale")) { - for (it = LLWorldMap::getInstance()->mLandForSale.begin(); it != LLWorldMap::getInstance()->mLandForSale.end(); ++it) + LLSimInfo::item_info_list_t::const_iterator it = siminfo->getLandForSale().begin(); + while (it != siminfo->getLandForSale().end()) { - LLItemInfo& land = *it; - - if (checkItemHit(x, y, land, id, true)) + LLItemInfo event = *it; + if (checkItemHit(x, y, event, id, true)) { *hit_type = MAP_ITEM_LAND_FOR_SALE; mItemPicked = TRUE; return; } + ++it; } - - for (it = LLWorldMap::getInstance()->mLandForSaleAdult.begin(); it != LLWorldMap::getInstance()->mLandForSaleAdult.end(); ++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& land = *it; - - if (checkItemHit(x, y, land, id, true)) + 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; } @@ -1812,58 +1684,35 @@ 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++; - } - return blocks_requested; -} - -U32 LLWorldMapView::updateVisibleBlocks() -{ - if (sMapScale < SIM_MAP_SCALE) - { - // We don't care what is loaded if we're zoomed out - return 0; + // If we're zoomed out too much, we just don't load all those sim info: too much! + return; } + // 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 = sMapScale; 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)); + const F32 half_width = F32(width) / 2.0f; + const F32 half_height = F32(height) / 2.0f; - // 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; + // 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)); - U32 blocks_requested = 0; - const U32 max_blocks_requested = 9; + // 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; - 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; + //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 ) @@ -1953,16 +1802,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 ); } diff --git a/indra/newview/llworldmapview.h b/indra/newview/llworldmapview.h index bf3f580ed..b9fedd144 100644 --- a/indra/newview/llworldmapview.h +++ b/indra/newview/llworldmapview.h @@ -39,21 +39,14 @@ #define LL_LLWORLDMAPVIEW_H #include "llpanel.h" -#include "v3math.h" -#include "v3dmath.h" -#include "v4color.h" -#include "llviewerimage.h" -#include "llmapimagetype.h" #include "llworldmap.h" - -class LLItemInfo; +#include "v4color.h" const S32 DEFAULT_TRACKING_ARROW_SIZE = 16; -class LLColor4; -class LLColor4U; -class LLCoordGL; -class LLViewerImage; +class LLUUID; +class LLVector3d; +class LLVector3; class LLTextBox; @@ -78,22 +71,26 @@ public: bool checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track); void handleClick(S32 x, S32 y, MASK mask, S32* hit_type, LLUUID* id); - // Scale and pan are shared across all instances. + // Scale and pan are shared across all instances! (i.e. Terrain and Objects maps are always registered) static void setScale( F32 scale ); static void translatePan( S32 delta_x, S32 delta_y ); static void setPan( S32 x, S32 y, BOOL snap = TRUE ); + // Return true if the current scale level is above the threshold for accessing region info + static bool showRegionInfo(); LLVector3 globalPosToView(const LLVector3d& global_pos); LLVector3d viewPosToGlobal(S32 x,S32 y); virtual void draw(); - void drawGenericItems(const LLWorldMap::item_info_list_t& items, LLUIImagePtr image); + void drawGenericItems(const LLSimInfo::item_info_list_t& items, LLUIImagePtr image); void drawGenericItem(const LLItemInfo& item, LLUIImagePtr image); void drawImage(const LLVector3d& global_pos, LLUIImagePtr image, const LLColor4& color = LLColor4::white); void drawImageStack(const LLVector3d& global_pos, LLUIImagePtr image, U32 count, F32 offset, const LLColor4& color); void drawAgents(); - void drawEvents(); + void drawItems(); void drawFrustum(); + void drawMipmap(S32 width, S32 height); + bool drawMipmapLevel(S32 width, S32 height, S32 level, bool load = true); static void cleanupTextures(); @@ -109,7 +106,7 @@ public: F32 y_pixels, const LLColor4& color, F32 relative_z = 0.f, - F32 dot_radius = 3.f); + F32 dot_radius = 5.f); static void drawTrackingCircle( const LLRect& rect, S32 x, S32 y, const LLColor4& color, @@ -130,9 +127,7 @@ public: static void clearLastClick() { sHandledLastClick = FALSE; } // if the view changes, download additional sim info as needed - // return value is number of blocks newly requested. - U32 updateBlock(S32 block_x, S32 block_y); - U32 updateVisibleBlocks(); + void updateVisibleBlocks(); protected: void setDirectionPos( LLTextBox* text_box, F32 rotation ); @@ -147,6 +142,7 @@ public: static LLUIImagePtr sAvatarLevelImage; static LLUIImagePtr sAvatarAboveImage; static LLUIImagePtr sAvatarBelowImage; + static LLUIImagePtr sTelehubImage; static LLUIImagePtr sInfohubImage; static LLUIImagePtr sHomeImage; @@ -159,10 +155,6 @@ public: static LLUIImagePtr sForSaleImage; static LLUIImagePtr sForSaleAdultImage; - static F32 sThresholdA; - static F32 sThresholdB; - static F32 sPixelsPerMeter; // world meters to map pixels - static F32 sMapScale; // scale = size of a region in pixels BOOL mItemPicked; @@ -173,6 +165,7 @@ public: static F32 sTargetPanY; // in pixels static S32 sTrackingArrowX; static S32 sTrackingArrowY; + static bool sVisibleTilesLoaded; // Are we mid-pan from a user drag? BOOL mPanning; @@ -195,10 +188,14 @@ public: static BOOL sHandledLastClick; S32 mSelectIDStart; + // Keep the list of regions that are displayed on screen. Avoids iterating through the whole region map after draw(). typedef std::vector handle_list_t; handle_list_t mVisibleRegions; // set every frame static std::map sStringsMap; + +private: + void drawTileOutline(S32 level, F32 top, F32 left, F32 bottom, F32 right); }; #endif diff --git a/indra/newview/llworldmipmap.cpp b/indra/newview/llworldmipmap.cpp new file mode 100644 index 000000000..7e1497417 --- /dev/null +++ b/indra/newview/llworldmipmap.cpp @@ -0,0 +1,294 @@ +/** + * @file llworldmipmap.cpp + * @brief Data storage for the S3 mipmap of the entire world. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "llworldmipmap.h" + +#include "llviewercontrol.h" +#include "llviewerimagelist.h" +#include "math.h" // log() + +#include "llworldmap.h" +#include "llviewernetwork.h" //for isProductionGrid(); +#include "hippogridmanager.h" + +// Turn this on to output tile stats in the standard output +#define DEBUG_TILES_STAT 0 + +LLWorldMipmap::LLWorldMipmap() : + mCurrentLevel(0) +{ +} + +LLWorldMipmap::~LLWorldMipmap() +{ + reset(); +} + +// Delete all sublevel maps and clean them +void LLWorldMipmap::reset() +{ + for (int level = 0; level < MAP_LEVELS; level++) + { + mWorldObjectsMipMap[level].clear(); + } +} + +// This method should be called before each use of the mipmap (typically, before each draw), so that to let +// the boost level of unused tiles to drop to 0 (BOOST_NONE). +// Tiles that are accessed have had their boost level pushed to BOOST_MAP_VISIBLE so we can identify them. +// The result of this strategy is that if a tile is not used during 2 consecutive loops, its boost level drops to 0. +void LLWorldMipmap::equalizeBoostLevels() +{ +#if DEBUG_TILES_STAT + S32 nb_missing = 0; + S32 nb_tiles = 0; + S32 nb_visible = 0; +#endif // DEBUG_TILES_STAT + // For each level + for (S32 level = 0; level < MAP_LEVELS; level++) + { + sublevel_tiles_t& level_mipmap = mWorldObjectsMipMap[level]; + // For each tile + for (sublevel_tiles_t::iterator iter = level_mipmap.begin(); iter != level_mipmap.end(); iter++) + { + LLPointer img = iter->second; + S32 current_boost_level = img->getBoostLevel(); + if (current_boost_level == LLViewerImageBoostLevel::BOOST_MAP_VISIBLE) + { + // If level was BOOST_MAP_VISIBLE, the tile has been used in the last draw so keep it high + img->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP); + } + else + { + // If level was BOOST_MAP only (or anything else...), the tile wasn't used in the last draw + // so we drop its boost level to BOOST_NONE. + img->setBoostLevel(LLViewerImageBoostLevel::BOOST_NONE); + } +#if DEBUG_TILES_STAT + // Increment some stats if compile option on + nb_tiles++; + if (current_boost_level == LLViewerImageBoostLevel::BOOST_MAP_VISIBLE) + { + nb_visible++; + } + if (img->isMissingAsset()) + { + nb_missing++; + } +#endif // DEBUG_TILES_STAT + } + } +#if DEBUG_TILES_STAT + LL_INFOS("World Map") << "LLWorldMipmap tile stats : total requested = " << nb_tiles << ", visible = " << nb_visible << ", missing = " << nb_missing << LL_ENDL; +#endif // DEBUG_TILES_STAT +} + +// This method should be used when the mipmap is not actively used for a while, e.g., the map UI is hidden +void LLWorldMipmap::dropBoostLevels() +{ + // For each level + for (S32 level = 0; level < MAP_LEVELS; level++) + { + sublevel_tiles_t& level_mipmap = mWorldObjectsMipMap[level]; + // For each tile + for (sublevel_tiles_t::iterator iter = level_mipmap.begin(); iter != level_mipmap.end(); iter++) + { + LLPointer img = iter->second; + img->setBoostLevel(LLViewerImageBoostLevel::BOOST_NONE); + } + } +} + +LLPointer LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load) +{ + // Check the input data + llassert(level <= MAP_LEVELS); + llassert(level >= 1); + + // If the *loading* level changed, cleared the new level from "missed" tiles + // so that we get a chance to reload them + if (load && (level != mCurrentLevel)) + { + cleanMissedTilesFromLevel(level); + mCurrentLevel = level; + } + + // Build the region handle + U64 handle = convertGridToHandle(grid_x, grid_y); + + // Check if the image is around already + sublevel_tiles_t& level_mipmap = mWorldObjectsMipMap[level-1]; + sublevel_tiles_t::iterator found = level_mipmap.find(handle); + + // If not there and load on, go load it + if (found == level_mipmap.end()) + { + if (load) + { + // Load it + LLPointer img; + + //hack for opensims. + if(gHippoGridManager->getConnectedGrid()->getPlatform() == HippoGridInfo::PLATFORM_SECONDLIFE) + img = loadObjectsTile(grid_x, grid_y, level); + else + { + LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle); + if(info) + { + img = gImageList.getImage(info->getMapImageID(), MIPMAP_TRUE, FALSE); + img->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP); + } + else + return NULL; + } + // + // Insert the image in the map + level_mipmap.insert(sublevel_tiles_t::value_type( handle, img )); + // Find the element again in the map (it's there now...) + found = level_mipmap.find(handle); + } + else + { + // Return with NULL if not found and we're not trying to load + return NULL; + } + } + + // Get the image pointer and check if this asset is missing + LLPointer img = found->second; + if (img->isMissingAsset()) + { + // Return NULL if asset missing + return NULL; + } + else + { + // Boost the tile level so to mark it's in use *if* load on + if (load) + { + img->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP_VISIBLE); + } + return img; + } +} + +LLPointer LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level) +{ + // Get the grid coordinates + std::string imageurl = gSavedSettings.getString("MapServerURL") + llformat("map-%d-%d-%d-objects.jpg", level, grid_x, grid_y); + + // DO NOT COMMIT!! DEBUG ONLY!!! + // Use a local jpeg for every tile to test map speed without S3 access + //imageurl = "file://C:\\Develop\\mapserver-distribute-3\\indra\\build-vc80\\mapserver\\relwithdebinfo\\regions\\00995\\01001\\region-995-1001-prims.jpg"; + // END DEBUG + //LL_INFOS("World Map") << "LLWorldMipmap::loadObjectsTile(), URL = " << imageurl << LL_ENDL; + + LLPointer img = gImageList.getImageFromUrl(imageurl); + img->setBoostLevel(LLViewerImageBoostLevel::BOOST_MAP); + + // Return the smart pointer + return img; +} + +// This method is used to clean up a level from tiles marked as "missing". +// The idea is to allow tiles that have been improperly marked missing to be reloaded when retraversing the level again. +// When zooming in and out rapidly, some tiles are never properly loaded and, eventually marked missing. +// This creates "blue" areas in a subresolution that never got a chance to reload if we don't clean up the level. +void LLWorldMipmap::cleanMissedTilesFromLevel(S32 level) +{ + // Check the input data + llassert(level <= MAP_LEVELS); + llassert(level >= 0); + + // This happens when the object is first initialized + if (level == 0) + { + return; + } + + // Iterate through the subresolution level and suppress the tiles that are marked as missing + // Note: erasing in a map while iterating through it is bug prone. Using a postfix increment is mandatory here. + sublevel_tiles_t& level_mipmap = mWorldObjectsMipMap[level-1]; + sublevel_tiles_t::iterator it = level_mipmap.begin(); + while (it != level_mipmap.end()) + { + LLPointer img = it->second; + if (img->isMissingAsset()) + { + level_mipmap.erase(it++); + } + else + { + ++it; + } + } + return; +} + +// static methods +// Compute the level in the world mipmap (between 1 and MAP_LEVELS, as in the URL) given the scale (size of a sim in screen pixels) +S32 LLWorldMipmap::scaleToLevel(F32 scale) +{ + // If scale really small, picks up the higest level there is (lowest resolution) + if (scale <= F32_MIN) + return MAP_LEVELS; + // Compute the power of two resolution level knowing the base level + S32 level = llfloor((log(REGION_WIDTH_METERS/scale)/log(2.0f)) + 1.0f); + // Check bounds and return the value + if (level > MAP_LEVELS) + return MAP_LEVELS; + else if (level < 1) + return 1; + else + return level; +} + +// Convert world coordinates to mipmap grid coordinates at a given level (between 1 and MAP_LEVELS) +void LLWorldMipmap::globalToMipmap(F64 global_x, F64 global_y, S32 level, U32* grid_x, U32* grid_y) +{ + // Check the input data + llassert(level <= MAP_LEVELS); + llassert(level >= 1); + + // Convert world coordinates into grid coordinates + *grid_x = lltrunc(global_x/REGION_WIDTH_METERS); + *grid_y = lltrunc(global_y/REGION_WIDTH_METERS); + // Compute the valid grid coordinates at that level of the mipmap + S32 regions_in_tile = 1 << (level - 1); + *grid_x = *grid_x - (*grid_x % regions_in_tile); + *grid_y = *grid_y - (*grid_y % regions_in_tile); +} + + diff --git a/indra/newview/llworldmipmap.h b/indra/newview/llworldmipmap.h new file mode 100644 index 000000000..9d6a80a41 --- /dev/null +++ b/indra/newview/llworldmipmap.h @@ -0,0 +1,100 @@ +/** + * @file llworldmipmap.h + * @brief Data storage for the S3 mipmap of the entire world. + * + * $LicenseInfo:firstyear=2003&license=viewergpl$ + * + * Copyright (c) 2003-2009, Linden Research, Inc. + * + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab. Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + * + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + * + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + * + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLWORLDMIPMAP_H +#define LL_LLWORLDMIPMAP_H + +#include + +#include "llmemory.h" // LLPointer +#include "indra_constants.h" // REGION_WIDTH_UNITS +#include "llregionhandle.h" // to_region_handle() + +class LLViewerImage; + +// LLWorldMipmap : Mipmap handling of all the tiles used to render the world at any resolution. +// This class provides a clean structured access to the hierarchy of tiles stored in the +// Amazon S3 repository and abstracts its directory/file structure. +// The interface of this class though still assumes that the caller knows the general level/tiles +// structure (at least, that it exists...) but doesn't requite the caller to know the details of it. +// IOW, you need to know that rendering levels exists as well as grid coordinates for regions, +// but you can ignore where those tiles are located, how to get them, etc... +// The class API gives you back LLPointer per tile. + +// See llworldmipmapview.cpp for the implementation of a class who knows how to render an LLWorldMipmap. + +// Implementation notes: +// - On the S3 servers, the tiles are rendered in 2 flavors: Objects and Terrain. +// - For the moment, LLWorldMipmap implements access only to the Objects tiles. +class LLWorldMipmap +{ +public: + // Parameters of the mipmap + static const S32 MAP_LEVELS = 8; // Number of subresolution levels computed by the mapserver + static const S32 MAP_TILE_SIZE = 256; // Width in pixels of the tiles computed by the mapserver + + LLWorldMipmap(); + ~LLWorldMipmap(); + + // Clear up the maps and release all image handles + void reset(); + // Manage the boost levels between loops (typically draw() loops) + void equalizeBoostLevels(); + // Drop the boost levels to none (used when hiding the map) + void dropBoostLevels(); + // Get the tile smart pointer, does the loading if necessary + LLPointer getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load = true); + + // Helper functions: those are here as they depend solely on the topology of the mipmap though they don't access it + // Convert sim scale (given in sim width in display pixels) into a mipmap level + static S32 scaleToLevel(F32 scale); + // Convert world coordinates to mipmap grid coordinates at a given level + static void globalToMipmap(F64 global_x, F64 global_y, S32 level, U32* grid_x, U32* grid_y); + +private: + // Get a handle (key) from grid coordinates + U64 convertGridToHandle(U32 grid_x, U32 grid_y) { return to_region_handle(grid_x * REGION_WIDTH_UNITS, grid_y * REGION_WIDTH_UNITS); } + // Load the relevant tile from S3 + LLPointer loadObjectsTile(U32 grid_x, U32 grid_y, S32 level); + // Clear a level from its "missing" tiles + void cleanMissedTilesFromLevel(S32 level); + + // The mipmap is organized by resolution level (MAP_LEVELS of them). Each resolution level is an std::map + // using a region_handle as a key and storing a smart pointer to the image as a value. + typedef std::map > sublevel_tiles_t; + sublevel_tiles_t mWorldObjectsMipMap[MAP_LEVELS]; +// sublevel_tiles_t mWorldTerrainMipMap[MAP_LEVELS]; + + S32 mCurrentLevel; // The level last accessed by a getObjectsTile() +}; + +#endif // LL_LLWORLDMIPMAP_H diff --git a/indra/newview/skins/default/xui/en-us/floater_world_map.xml b/indra/newview/skins/default/xui/en-us/floater_world_map.xml index 645c1ca15..389efb539 100644 --- a/indra/newview/skins/default/xui/en-us/floater_world_map.xml +++ b/indra/newview/skins/default/xui/en-us/floater_world_map.xml @@ -82,19 +82,19 @@ - - - free week - - [NAME] is offering a TP to [DESTINATION] - - - [NAME]'s teleport lure is to [DESTINATION] - - Logging in. [APP_NAME] may appear frozen. Please wait. Authenticating