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