PageRenderTime 103ms CodeModel.GetById 1ms RepoModel.GetById 1ms app.codeStats 0ms

/indra/newview/llworldmap.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 614 lines | 447 code | 63 blank | 104 comment | 75 complexity | 77f42b8e01860ccc6553b4d1e5caf286 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llworldmap.cpp
  3. * @brief Underlying data representation for map of the world
  4. *
  5. * $LicenseInfo:firstyear=2003&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llworldmap.h"
  28. #include "llworldmapmessage.h"
  29. #include "message.h"
  30. #include "lltracker.h"
  31. #include "lluistring.h"
  32. #include "llviewertexturelist.h"
  33. #include "lltrans.h"
  34. // Timers to temporise database requests
  35. const F32 AGENTS_UPDATE_TIMER = 60.0; // Seconds between 2 agent requests for a region
  36. const F32 REQUEST_ITEMS_TIMER = 10.f * 60.f; // Seconds before we consider re-requesting item data for the grid
  37. //---------------------------------------------------------------------------
  38. // LLItemInfo
  39. //---------------------------------------------------------------------------
  40. LLItemInfo::LLItemInfo(F32 global_x, F32 global_y,
  41. const std::string& name,
  42. LLUUID id)
  43. : mName(name),
  44. mToolTip(""),
  45. mPosGlobal(global_x, global_y, 40.0),
  46. mID(id),
  47. mCount(1)
  48. // mSelected(false)
  49. // mColor()
  50. {
  51. }
  52. //---------------------------------------------------------------------------
  53. // LLSimInfo
  54. //---------------------------------------------------------------------------
  55. LLSimInfo::LLSimInfo(U64 handle)
  56. : mHandle(handle),
  57. mName(),
  58. mAgentsUpdateTime(0),
  59. mAccess(0x0),
  60. mRegionFlags(0x0),
  61. mFirstAgentRequest(true)
  62. // mWaterHeight(0.f)
  63. {
  64. }
  65. void LLSimInfo::setLandForSaleImage (LLUUID image_id)
  66. {
  67. mMapImageID = image_id;
  68. // Fetch the image
  69. if (mMapImageID.notNull())
  70. {
  71. mOverlayImage = LLViewerTextureManager::getFetchedTexture(mMapImageID, MIPMAP_TRUE, LLViewerTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE);
  72. mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP);
  73. }
  74. else
  75. {
  76. mOverlayImage = NULL;
  77. }
  78. }
  79. LLPointer<LLViewerFetchedTexture> LLSimInfo::getLandForSaleImage ()
  80. {
  81. if (mOverlayImage.isNull() && mMapImageID.notNull())
  82. {
  83. // Fetch the image if it hasn't been done yet (unlikely but...)
  84. mOverlayImage = LLViewerTextureManager::getFetchedTexture(mMapImageID, MIPMAP_TRUE, LLViewerTexture::BOOST_MAP, LLViewerTexture::LOD_TEXTURE);
  85. mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP);
  86. }
  87. if (!mOverlayImage.isNull())
  88. {
  89. // Boost the fetch level when we try to access that image
  90. mOverlayImage->setBoostLevel(LLViewerTexture::BOOST_MAP);
  91. }
  92. return mOverlayImage;
  93. }
  94. LLVector3d LLSimInfo::getGlobalPos(const LLVector3& local_pos) const
  95. {
  96. LLVector3d pos = from_region_handle(mHandle);
  97. pos.mdV[VX] += local_pos.mV[VX];
  98. pos.mdV[VY] += local_pos.mV[VY];
  99. pos.mdV[VZ] += local_pos.mV[VZ];
  100. return pos;
  101. }
  102. LLVector3d LLSimInfo::getGlobalOrigin() const
  103. {
  104. return from_region_handle(mHandle);
  105. }
  106. LLVector3 LLSimInfo::getLocalPos(LLVector3d global_pos) const
  107. {
  108. LLVector3d sim_origin = from_region_handle(mHandle);
  109. return LLVector3(global_pos - sim_origin);
  110. }
  111. void LLSimInfo::clearImage()
  112. {
  113. if (!mOverlayImage.isNull())
  114. {
  115. mOverlayImage->setBoostLevel(0);
  116. mOverlayImage = NULL;
  117. }
  118. }
  119. void LLSimInfo::dropImagePriority()
  120. {
  121. if (!mOverlayImage.isNull())
  122. {
  123. mOverlayImage->setBoostLevel(0);
  124. }
  125. }
  126. // Update the agent count for that region
  127. void LLSimInfo::updateAgentCount(F64 time)
  128. {
  129. if ((time - mAgentsUpdateTime > AGENTS_UPDATE_TIMER) || mFirstAgentRequest)
  130. {
  131. LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, mHandle);
  132. mAgentsUpdateTime = time;
  133. mFirstAgentRequest = false;
  134. }
  135. }
  136. // Get the total agents count
  137. const S32 LLSimInfo::getAgentCount() const
  138. {
  139. S32 total_agent_count = 0;
  140. for (LLSimInfo::item_info_list_t::const_iterator it = mAgentLocations.begin(); it != mAgentLocations.end(); ++it)
  141. {
  142. total_agent_count += it->getCount();
  143. }
  144. return total_agent_count;
  145. }
  146. bool LLSimInfo::isName(const std::string& name) const
  147. {
  148. return (LLStringUtil::compareInsensitive(name, mName) == 0);
  149. }
  150. void LLSimInfo::dump() const
  151. {
  152. U32 x_pos, y_pos;
  153. from_region_handle(mHandle, &x_pos, &y_pos);
  154. LL_INFOS("World Map") << x_pos << "," << y_pos
  155. << " " << mName
  156. << " " << (S32)mAccess
  157. << " " << std::hex << mRegionFlags << std::dec
  158. // << " " << mWaterHeight
  159. << LL_ENDL;
  160. }
  161. void LLSimInfo::clearItems()
  162. {
  163. mTelehubs.clear();
  164. mInfohubs.clear();
  165. mPGEvents.clear();
  166. mMatureEvents.clear();
  167. mAdultEvents.clear();
  168. mLandForSale.clear();
  169. mLandForSaleAdult.clear();
  170. // We persist the agent count though as it is updated on a frequent basis
  171. // mAgentLocations.clear();
  172. }
  173. void LLSimInfo::insertAgentLocation(const LLItemInfo& item)
  174. {
  175. std::string name = item.getName();
  176. // Find the last item in the list with a different name and erase them
  177. item_info_list_t::iterator lastiter;
  178. for (lastiter = mAgentLocations.begin(); lastiter != mAgentLocations.end(); ++lastiter)
  179. {
  180. LLItemInfo& info = *lastiter;
  181. if (info.isName(name))
  182. {
  183. break;
  184. }
  185. }
  186. if (lastiter != mAgentLocations.begin())
  187. {
  188. mAgentLocations.erase(mAgentLocations.begin(), lastiter);
  189. }
  190. // Now append the new location
  191. mAgentLocations.push_back(item);
  192. }
  193. //---------------------------------------------------------------------------
  194. // World Map
  195. //---------------------------------------------------------------------------
  196. LLWorldMap::LLWorldMap() :
  197. mIsTrackingLocation( false ),
  198. mIsTrackingFound( false ),
  199. mIsInvalidLocation( false ),
  200. mIsTrackingDoubleClick( false ),
  201. mIsTrackingCommit( false ),
  202. mTrackingLocation( 0, 0, 0 ),
  203. mFirstRequest(true)
  204. {
  205. //LL_INFOS("World Map") << "Creating the World Map -> LLWorldMap::LLWorldMap()" << LL_ENDL;
  206. mMapBlockLoaded = new bool[MAP_BLOCK_RES*MAP_BLOCK_RES];
  207. clearSimFlags();
  208. }
  209. LLWorldMap::~LLWorldMap()
  210. {
  211. //LL_INFOS("World Map") << "Destroying the World Map -> LLWorldMap::~LLWorldMap()" << LL_ENDL;
  212. reset();
  213. delete[] mMapBlockLoaded;
  214. }
  215. void LLWorldMap::reset()
  216. {
  217. clearItems(true); // Clear the items lists
  218. clearImageRefs(); // Clear the world mipmap and the land for sale tiles
  219. clearSimFlags(); // Clear the block info flags array
  220. // Finally, clear the region map itself
  221. for_each(mSimInfoMap.begin(), mSimInfoMap.end(), DeletePairedPointer());
  222. mSimInfoMap.clear();
  223. }
  224. // Returns true if the items have been cleared
  225. bool LLWorldMap::clearItems(bool force)
  226. {
  227. bool clear = false;
  228. if ((mRequestTimer.getElapsedTimeF32() > REQUEST_ITEMS_TIMER) || mFirstRequest || force)
  229. {
  230. mRequestTimer.reset();
  231. LLSimInfo* sim_info = NULL;
  232. for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
  233. {
  234. sim_info = it->second;
  235. if (sim_info)
  236. {
  237. sim_info->clearItems();
  238. }
  239. }
  240. clear = true;
  241. mFirstRequest = false;
  242. }
  243. return clear;
  244. }
  245. void LLWorldMap::clearImageRefs()
  246. {
  247. // We clear the reference to the images we're holding.
  248. // Images hold by the world mipmap first
  249. mWorldMipmap.reset();
  250. // Images hold by the region map
  251. LLSimInfo* sim_info = NULL;
  252. for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
  253. {
  254. sim_info = it->second;
  255. if (sim_info)
  256. {
  257. sim_info->clearImage();
  258. }
  259. }
  260. }
  261. // Doesn't clear the already-loaded sim infos, just re-requests them
  262. void LLWorldMap::clearSimFlags()
  263. {
  264. for (S32 idx=0; idx<MAP_BLOCK_RES*MAP_BLOCK_RES; ++idx)
  265. {
  266. mMapBlockLoaded[idx] = false;
  267. }
  268. }
  269. LLSimInfo* LLWorldMap::createSimInfoFromHandle(const U64 handle)
  270. {
  271. LLSimInfo* sim_info = new LLSimInfo(handle);
  272. mSimInfoMap[handle] = sim_info;
  273. return sim_info;
  274. }
  275. void LLWorldMap::equalizeBoostLevels()
  276. {
  277. mWorldMipmap.equalizeBoostLevels();
  278. return;
  279. }
  280. LLSimInfo* LLWorldMap::simInfoFromPosGlobal(const LLVector3d& pos_global)
  281. {
  282. U64 handle = to_region_handle(pos_global);
  283. return simInfoFromHandle(handle);
  284. }
  285. LLSimInfo* LLWorldMap::simInfoFromHandle(const U64 handle)
  286. {
  287. sim_info_map_t::iterator it = mSimInfoMap.find(handle);
  288. if (it != mSimInfoMap.end())
  289. {
  290. return it->second;
  291. }
  292. return NULL;
  293. }
  294. LLSimInfo* LLWorldMap::simInfoFromName(const std::string& sim_name)
  295. {
  296. LLSimInfo* sim_info = NULL;
  297. if (!sim_name.empty())
  298. {
  299. // Iterate through the entire sim info map and compare the name
  300. sim_info_map_t::iterator it;
  301. for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
  302. {
  303. sim_info = it->second;
  304. if (sim_info && sim_info->isName(sim_name) )
  305. {
  306. // break out of loop if success
  307. break;
  308. }
  309. }
  310. // If we got to the end, we haven't found the sim. Reset the ouput value to NULL.
  311. if (it == mSimInfoMap.end())
  312. sim_info = NULL;
  313. }
  314. return sim_info;
  315. }
  316. bool LLWorldMap::simNameFromPosGlobal(const LLVector3d& pos_global, std::string & outSimName )
  317. {
  318. LLSimInfo* sim_info = simInfoFromPosGlobal(pos_global);
  319. if (sim_info)
  320. {
  321. outSimName = sim_info->getName();
  322. }
  323. else
  324. {
  325. outSimName = "(unknown region)";
  326. }
  327. return (sim_info != NULL);
  328. }
  329. void LLWorldMap::reloadItems(bool force)
  330. {
  331. //LL_INFOS("World Map") << "LLWorldMap::reloadItems()" << LL_ENDL;
  332. if (clearItems(force))
  333. {
  334. LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_TELEHUB);
  335. LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_PG_EVENT);
  336. LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_MATURE_EVENT);
  337. LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_ADULT_EVENT);
  338. LLWorldMapMessage::getInstance()->sendItemRequest(MAP_ITEM_LAND_FOR_SALE);
  339. }
  340. }
  341. // static public
  342. // Insert a region in the region map
  343. // returns true if region inserted, false otherwise
  344. bool LLWorldMap::insertRegion(U32 x_world, U32 y_world, std::string& name, LLUUID& image_id, U32 accesscode, U32 region_flags)
  345. {
  346. // This region doesn't exist
  347. if (accesscode == 255)
  348. {
  349. // Checks if the track point is in it and invalidates it if it is
  350. if (LLWorldMap::getInstance()->isTrackingInRectangle( x_world, y_world, x_world + REGION_WIDTH_UNITS, y_world + REGION_WIDTH_UNITS))
  351. {
  352. LLWorldMap::getInstance()->setTrackingInvalid();
  353. }
  354. // return failure to insert
  355. return false;
  356. }
  357. else
  358. {
  359. U64 handle = to_region_handle(x_world, y_world);
  360. //LL_INFOS("World Map") << "Map sim : " << name << ", ID : " << image_id.getString() << LL_ENDL;
  361. // Insert the region in the region map of the world map
  362. // Loading the LLSimInfo object with what we got and insert it in the map
  363. LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
  364. if (siminfo == NULL)
  365. {
  366. siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle);
  367. }
  368. siminfo->setName(name);
  369. siminfo->setAccess(accesscode);
  370. siminfo->setRegionFlags(region_flags);
  371. // siminfo->setWaterHeight((F32) water_height);
  372. siminfo->setLandForSaleImage(image_id);
  373. // Handle the location tracking (for teleport, UI feedback and info display)
  374. if (LLWorldMap::getInstance()->isTrackingInRectangle( x_world, y_world, x_world + REGION_WIDTH_UNITS, y_world + REGION_WIDTH_UNITS))
  375. {
  376. if (siminfo->isDown())
  377. {
  378. // We were tracking this location, but it's no available
  379. LLWorldMap::getInstance()->setTrackingInvalid();
  380. }
  381. else
  382. {
  383. // We were tracking this location, and it does exist and is available
  384. LLWorldMap::getInstance()->setTrackingValid();
  385. }
  386. }
  387. // return insert region success
  388. return true;
  389. }
  390. }
  391. // static public
  392. // Insert an item in the relevant region map
  393. // returns true if item inserted, false otherwise
  394. bool LLWorldMap::insertItem(U32 x_world, U32 y_world, std::string& name, LLUUID& uuid, U32 type, S32 extra, S32 extra2)
  395. {
  396. // Create an item record for the received object
  397. LLItemInfo new_item((F32)x_world, (F32)y_world, name, uuid);
  398. // Compute a region handle based on the objects coordinates
  399. LLVector3d pos((F32)x_world, (F32)y_world, 40.0);
  400. U64 handle = to_region_handle(pos);
  401. // Get the region record for that handle or NULL if we haven't browsed it yet
  402. LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
  403. if (siminfo == NULL)
  404. {
  405. siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle);
  406. }
  407. //LL_INFOS("World Map") << "Process item : type = " << type << LL_ENDL;
  408. switch (type)
  409. {
  410. case MAP_ITEM_TELEHUB: // telehubs
  411. {
  412. /* Merov: we are not using the hub color anymore for display so commenting that out
  413. // Telehub color
  414. U32 X = x_world / REGION_WIDTH_UNITS;
  415. U32 Y = y_world / REGION_WIDTH_UNITS;
  416. F32 red = fmod((F32)X * 0.11f, 1.f) * 0.8f;
  417. F32 green = fmod((F32)Y * 0.11f, 1.f) * 0.8f;
  418. F32 blue = fmod(1.5f * (F32)(X + Y) * 0.11f, 1.f) * 0.8f;
  419. F32 add_amt = (X % 2) ? 0.15f : -0.15f;
  420. add_amt += (Y % 2) ? -0.15f : 0.15f;
  421. LLColor4 color(red + add_amt, green + add_amt, blue + add_amt);
  422. new_item.setColor(color);
  423. */
  424. // extra2 specifies whether this is an infohub or a telehub.
  425. if (extra2)
  426. {
  427. siminfo->insertInfoHub(new_item);
  428. }
  429. else
  430. {
  431. siminfo->insertTeleHub(new_item);
  432. }
  433. break;
  434. }
  435. case MAP_ITEM_PG_EVENT: // events
  436. case MAP_ITEM_MATURE_EVENT:
  437. case MAP_ITEM_ADULT_EVENT:
  438. {
  439. std::string timeStr = "["+ LLTrans::getString ("TimeHour")+"]:["
  440. +LLTrans::getString ("TimeMin")+"] ["
  441. +LLTrans::getString ("TimeAMPM")+"]";
  442. LLSD substitution;
  443. substitution["datetime"] = (S32) extra;
  444. LLStringUtil::format (timeStr, substitution);
  445. new_item.setTooltip(timeStr);
  446. // HACK: store Z in extra2
  447. new_item.setElevation((F64)extra2);
  448. if (type == MAP_ITEM_PG_EVENT)
  449. {
  450. siminfo->insertPGEvent(new_item);
  451. }
  452. else if (type == MAP_ITEM_MATURE_EVENT)
  453. {
  454. siminfo->insertMatureEvent(new_item);
  455. }
  456. else if (type == MAP_ITEM_ADULT_EVENT)
  457. {
  458. siminfo->insertAdultEvent(new_item);
  459. }
  460. break;
  461. }
  462. case MAP_ITEM_LAND_FOR_SALE: // land for sale
  463. case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale
  464. {
  465. static LLUIString tooltip_fmt = LLTrans::getString("worldmap_item_tooltip_format");
  466. tooltip_fmt.setArg("[AREA]", llformat("%d", extra));
  467. tooltip_fmt.setArg("[PRICE]", llformat("%d", extra2));
  468. new_item.setTooltip(tooltip_fmt.getString());
  469. if (type == MAP_ITEM_LAND_FOR_SALE)
  470. {
  471. siminfo->insertLandForSale(new_item);
  472. }
  473. else if (type == MAP_ITEM_LAND_FOR_SALE_ADULT)
  474. {
  475. siminfo->insertLandForSaleAdult(new_item);
  476. }
  477. break;
  478. }
  479. case MAP_ITEM_CLASSIFIED: // classifieds
  480. {
  481. //DEPRECATED: no longer used
  482. break;
  483. }
  484. case MAP_ITEM_AGENT_LOCATIONS: // agent locations
  485. {
  486. // LL_INFOS("World Map") << "New Location " << new_item.mName << LL_ENDL;
  487. if (extra > 0)
  488. {
  489. new_item.setCount(extra);
  490. siminfo->insertAgentLocation(new_item);
  491. }
  492. break;
  493. }
  494. default:
  495. break;
  496. }
  497. return true;
  498. }
  499. bool LLWorldMap::isTrackingInRectangle(F64 x0, F64 y0, F64 x1, F64 y1)
  500. {
  501. if (!mIsTrackingLocation)
  502. return false;
  503. return ((mTrackingLocation[0] >= x0) && (mTrackingLocation[0] < x1) && (mTrackingLocation[1] >= y0) && (mTrackingLocation[1] < y1));
  504. }
  505. // Drop priority of all images being fetched by the map
  506. void LLWorldMap::dropImagePriorities()
  507. {
  508. // Drop the download of tiles priority to nil
  509. mWorldMipmap.dropBoostLevels();
  510. // Same for the "land for sale" tiles per region
  511. for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
  512. {
  513. LLSimInfo* info = it->second;
  514. info->dropImagePriority();
  515. }
  516. }
  517. // Load all regions in a given rectangle (in region grid coordinates, i.e. world / 256 meters)
  518. void LLWorldMap::updateRegions(S32 x0, S32 y0, S32 x1, S32 y1)
  519. {
  520. // Convert those boundaries to the corresponding (MAP_BLOCK_SIZE x MAP_BLOCK_SIZE) block coordinates
  521. x0 = x0 / MAP_BLOCK_SIZE;
  522. x1 = x1 / MAP_BLOCK_SIZE;
  523. y0 = y0 / MAP_BLOCK_SIZE;
  524. y1 = y1 / MAP_BLOCK_SIZE;
  525. // Load the region info those blocks
  526. for (S32 block_x = llmax(x0, 0); block_x <= llmin(x1, MAP_BLOCK_RES-1); ++block_x)
  527. {
  528. for (S32 block_y = llmax(y0, 0); block_y <= llmin(y1, MAP_BLOCK_RES-1); ++block_y)
  529. {
  530. S32 offset = block_x | (block_y * MAP_BLOCK_RES);
  531. if (!mMapBlockLoaded[offset])
  532. {
  533. //LL_INFOS("World Map") << "Loading Block (" << block_x << "," << block_y << ")" << LL_ENDL;
  534. 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);
  535. mMapBlockLoaded[offset] = true;
  536. }
  537. }
  538. }
  539. }
  540. void LLWorldMap::dump()
  541. {
  542. LL_INFOS("World Map") << "LLWorldMap::dump()" << LL_ENDL;
  543. for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
  544. {
  545. LLSimInfo* info = it->second;
  546. if (info)
  547. {
  548. info->dump();
  549. }
  550. }
  551. }