diff --git a/indra/llcharacter/llheadrotmotion.cpp b/indra/llcharacter/llheadrotmotion.cpp
index 88cd77f7afc3b9bad2607bad16eff60e6e4182be..0ee378f3b8205c85f285d5452ddad46cd8579d67 100644
--- a/indra/llcharacter/llheadrotmotion.cpp
+++ b/indra/llcharacter/llheadrotmotion.cpp
@@ -251,10 +251,13 @@ BOOL LLHeadRotMotion::onUpdate(F32 time, U8* joint_mask)
 	mLastHeadRot = head_rot_local;
 
 	// Set the head rotation.
-	LLQuaternion torsoRotLocal =  mNeckState->getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld;
-	head_rot_local = head_rot_local * ~torsoRotLocal;
-	mNeckState->setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) );
-	mHeadState->setRotation( nlerp(1.f - NECK_LAG, LLQuaternion::DEFAULT, head_rot_local));
+	if(mNeckState->getJoint() && mNeckState->getJoint()->getParent())
+	{
+		LLQuaternion torsoRotLocal =  mNeckState->getJoint()->getParent()->getWorldRotation() * currentInvRootRotWorld;
+		head_rot_local = head_rot_local * ~torsoRotLocal;
+		mNeckState->setRotation( nlerp(NECK_LAG, LLQuaternion::DEFAULT, head_rot_local) );
+		mHeadState->setRotation( nlerp(1.f - NECK_LAG, LLQuaternion::DEFAULT, head_rot_local));
+	}
 
 	return TRUE;
 }
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index 669afc53303121b99d9bec164ffc7f8d5f57bdc7..ed70b1d9f28809a274f06e44e62043a4157eb8f7 100644
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -57,7 +57,7 @@ void ll_init_apr()
 
 	if(!LLAPRFile::sAPRFilePoolp)
 	{
-		LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool() ;
+		LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
 	}
 }
 
@@ -99,13 +99,12 @@ void ll_cleanup_apr()
 //
 //LLAPRPool
 //
-LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 
-{
-	mParent = parent ;
-	mReleasePoolFlag = releasePoolFlag ;
-	mMaxSize = size ;
-	mPool = NULL ;
-
+LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 	
+	: mParent(parent),
+	mReleasePoolFlag(releasePoolFlag),
+	mMaxSize(size),
+	mPool(NULL)
+{	
 	createAPRPool() ;
 }
 
@@ -148,31 +147,65 @@ void LLAPRPool::releaseAPRPool()
 	}
 }
 
+//virtual
 apr_pool_t* LLAPRPool::getAPRPool() 
+{	
+	return mPool ; 
+}
+
+LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 
+				  : LLAPRPool(parent, size, releasePoolFlag),
+				  mNumActiveRef(0),
+				  mNumTotalRef(0),
+				  mMutexPool(NULL),
+				  mMutexp(NULL)
 {
-	if(!mPool)
+	//create mutex
+	if(!is_local) //not a local apr_pool, that is: shared by multiple threads.
 	{
-		createAPRPool() ;
+		apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex
+		apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool);
 	}
-	
-	return mPool ; 
 }
-LLVolatileAPRPool::LLVolatileAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 
-				  : LLAPRPool(parent, size, releasePoolFlag)
+
+LLVolatileAPRPool::~LLVolatileAPRPool()
 {
-	mNumActiveRef = 0 ;
-	mNumTotalRef = 0 ;
+	//delete mutex
+	if(mMutexp)
+	{
+		apr_thread_mutex_destroy(mMutexp);
+		apr_pool_destroy(mMutexPool);
+	}
 }
 
-apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() 
+//
+//define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
+//
+//virtual 
+apr_pool_t* LLVolatileAPRPool::getAPRPool() 
 {
+	return LLVolatileAPRPool::getVolatileAPRPool() ;
+}
+
+apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() 
+{	
+	LLScopedLock lock(mMutexp) ;
+
 	mNumTotalRef++ ;
 	mNumActiveRef++ ;
-	return getAPRPool() ;
+
+	if(!mPool)
+	{
+		createAPRPool() ;
+	}
+	
+	return mPool ;
 }
 
 void LLVolatileAPRPool::clearVolatileAPRPool() 
 {
+	LLScopedLock lock(mMutexp) ;
+
 	if(mNumActiveRef > 0)
 	{
 		mNumActiveRef--;
@@ -251,10 +284,9 @@ void LLScopedLock::unlock()
 bool ll_apr_warn_status(apr_status_t status)
 {
 	if(APR_SUCCESS == status) return false;
-#ifndef LL_WINDOWS
 	char buf[MAX_STRING];	/* Flawfinder: ignore */
-	LL_WARNS_ONCE("APR") << "APR: " << apr_strerror(status, buf, MAX_STRING) << LL_ENDL;
-#endif
+	apr_strerror(status, buf, MAX_STRING);
+	LL_WARNS("APR") << "APR: " << buf << LL_ENDL;
 	return true;
 }
 
@@ -268,10 +300,18 @@ void ll_apr_assert_status(apr_status_t status)
 // LLAPRFile functions
 //
 LLAPRFile::LLAPRFile()
+	: mFile(NULL),
+	  mCurrentFilePoolp(NULL)
+{
+}
+
+LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool)
+	: mFile(NULL),
+	  mCurrentFilePoolp(NULL)
 {
-	mFile = NULL ;
-	mCurrentFilePoolp = NULL ;
+	open(filename, flags, pool);
 }
+
 LLAPRFile::~LLAPRFile()
 {
 	close() ;
@@ -295,11 +335,40 @@ apr_status_t LLAPRFile::close()
 	return ret ;
 }
 
-apr_status_t LLAPRFile::open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep)
+apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep)
 {
 	apr_status_t s ;
-	s = open(filename, flags, pool ? pool->getVolatileAPRPool() : NULL, sizep) ;
+
+	//check if already open some file
+	llassert_always(!mFile) ;
+	llassert_always(!mCurrentFilePoolp) ;
 	
+	apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ;
+	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool));
+
+	if (s != APR_SUCCESS || !mFile)
+	{
+		mFile = NULL ;
+		
+		if (sizep)
+		{
+			*sizep = 0;
+		}
+	}
+	else if (sizep)
+	{
+		S32 file_size = 0;
+		apr_off_t offset = 0;
+		if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS)
+		{
+			llassert_always(offset <= 0x7fffffff);
+			file_size = (S32)offset;
+			offset = 0;
+			apr_file_seek(mFile, APR_SET, &offset);
+		}
+		*sizep = file_size;
+	}
+
 	if(!mCurrentFilePoolp)
 	{
 		mCurrentFilePoolp = pool ;
@@ -312,40 +381,25 @@ apr_status_t LLAPRFile::open(LLVolatileAPRPool* pool, const std::string& filenam
 
 	return s ;
 }
-apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool, S32* sizep)
+
+//use gAPRPoolp.
+apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
 {
 	apr_status_t s;
 
 	//check if already open some file
 	llassert_always(!mFile) ;
 	llassert_always(!mCurrentFilePoolp) ;
+	llassert_always(use_global_pool) ; //be aware of using gAPRPoolp.
 	
-	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(pool));
+	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp);
 	if (s != APR_SUCCESS || !mFile)
 	{
 		mFile = NULL ;
 		close() ;
-		if (sizep)
-		{
-			*sizep = 0;
-		}
 		return s;
 	}
 
-	if (sizep)
-	{
-		S32 file_size = 0;
-		apr_off_t offset = 0;
-		if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS)
-		{
-			llassert_always(offset <= 0x7fffffff);
-			file_size = (S32)offset;
-			offset = 0;
-			apr_file_seek(mFile, APR_SET, &offset);
-		}
-		*sizep = file_size;
-	}
-
 	return s;
 }
 
@@ -369,6 +423,7 @@ S32 LLAPRFile::read(void *buf, S32 nbytes)
 	apr_status_t s = apr_file_read(mFile, buf, &sz);
 	if (s != APR_SUCCESS)
 	{
+		ll_apr_warn_status(s);
 		return 0;
 	}
 	else
@@ -386,6 +441,7 @@ S32 LLAPRFile::write(const void *buf, S32 nbytes)
 	apr_status_t s = apr_file_write(mFile, buf, &sz);
 	if (s != APR_SUCCESS)
 	{
+		ll_apr_warn_status(s);
 		return 0;
 	}
 	else
@@ -434,6 +490,8 @@ apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool
 	s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());
 	if (s != APR_SUCCESS || !file_handle)
 	{
+		ll_apr_warn_status(s);
+		LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL;
 		file_handle = NULL ;
 		close(file_handle, pool) ;
 		return NULL;
@@ -464,6 +522,7 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)
 	}
 	if (s != APR_SUCCESS)
 	{
+		ll_apr_warn_status(s);
 		return -1;
 	}
 	else
@@ -501,6 +560,8 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb
 		apr_status_t s = apr_file_read(file_handle, buf, &bytes_read);
 		if (s != APR_SUCCESS)
 		{
+			LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL;
+			ll_apr_warn_status(s);
 			bytes_read = 0;
 		}
 		else
@@ -549,6 +610,8 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n
 		apr_status_t s = apr_file_write(file_handle, buf, &bytes_written);
 		if (s != APR_SUCCESS)
 		{
+			LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL;
+			ll_apr_warn_status(s);
 			bytes_written = 0;
 		}
 		else
@@ -575,8 +638,8 @@ bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)
 
 	if (s != APR_SUCCESS)
 	{
-		LL_DEBUGS("APR") << "LLAPRFile::remove failed on file: " << filename << LL_ENDL;
 		ll_apr_warn_status(s);
+		LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL;
 		return false;
 	}
 	return true;
@@ -593,8 +656,8 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname,
 	
 	if (s != APR_SUCCESS)
 	{
-		LL_DEBUGS("APR") << "LLAPRFile::rename failed on file: " << filename << LL_ENDL;
 		ll_apr_warn_status(s);
+		LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL;
 		return false;
 	}
 	return true;
@@ -667,8 +730,8 @@ bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)
 		
 	if (s != APR_SUCCESS)
 	{
-		LL_DEBUGS("APR") << "LLAPRFile::makeDir failed on file: " << dirname << LL_ENDL;
 		ll_apr_warn_status(s);
+		LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL;
 		return false;
 	}
 	return true;
@@ -685,8 +748,8 @@ bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)
 	
 	if (s != APR_SUCCESS)
 	{
-		LL_DEBUGS("APR") << "LLAPRFile::removeDir failed on file: " << dirname << LL_ENDL;
 		ll_apr_warn_status(s);
+		LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL;
 		return false;
 	}
 	return true;
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 63130a89fcd1d3f5f7d557642c159aacced9a925..a1a4c6db4a9dfadfeab686937ff5d8152849dd32 100644
--- a/indra/llcommon/llapr.h
+++ b/indra/llcommon/llapr.h
@@ -70,9 +70,9 @@ class LLAPRPool
 {
 public:
 	LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
-	~LLAPRPool() ;
+	virtual ~LLAPRPool() ;
 
-	apr_pool_t* getAPRPool() ;
+	virtual apr_pool_t* getAPRPool() ;
 	apr_status_t getStatus() {return mStatus ; }
 
 protected:
@@ -95,18 +95,21 @@ class LLAPRPool
 class LLVolatileAPRPool : public LLAPRPool
 {
 public:
-	LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
-	~LLVolatileAPRPool(){}
+	LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
+	virtual ~LLVolatileAPRPool();
 
-	apr_pool_t* getVolatileAPRPool() ;
-	
+	/*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool().
+	apr_pool_t* getVolatileAPRPool() ;	
 	void        clearVolatileAPRPool() ;
 
 	BOOL        isFull() ;
-	BOOL        isEmpty() {return !mNumActiveRef ;}
+	
 private:
 	S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
-	S32 mNumTotalRef ;  //number of total pointers pointing to the apr_pool since last creating.   
+	S32 mNumTotalRef ;  //number of total pointers pointing to the apr_pool since last creating.  
+
+	apr_thread_mutex_t *mMutexp;
+	apr_pool_t         *mMutexPool;
 } ;
 
 /** 
@@ -192,18 +195,21 @@ typedef LLAtomic32<S32> LLAtomicS32;
 //      1, a temperary pool passed to an APRFile function, which is used within this function and only once.
 //      2, a global pool.
 //
-class LLAPRFile
+
+class LLAPRFile : boost::noncopyable
 {
+	// make this non copyable since a copy closes the file
 private:
 	apr_file_t* mFile ;
 	LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. 
 
 public:
 	LLAPRFile() ;
+	LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL);
 	~LLAPRFile() ;
-
-	apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
-	apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
+	
+	apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL);
+	apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp.
 	apr_status_t close() ;
 
 	// Returns actual offset, -1 if seek fails
@@ -217,8 +223,8 @@ class LLAPRFile
 	apr_file_t* getFileHandle() {return mFile;}	
 
 private:
-	apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
-
+	apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;	
+	
 //
 //*******************************************************************************************************************************
 //static components
diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp
index 3db5c365454ed056156f3a773068113412acd958..395d29888740ff60f06e3ee304181317adecabf4 100644
--- a/indra/llcommon/llqueuedthread.cpp
+++ b/indra/llcommon/llqueuedthread.cpp
@@ -42,7 +42,8 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
 	LLThread(name),
 	mThreaded(threaded),
 	mIdleThread(TRUE),
-	mNextHandle(0)
+	mNextHandle(0),
+	mStarted(FALSE)
 {
 	if (mThreaded)
 	{
@@ -53,6 +54,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
 // MAIN THREAD
 LLQueuedThread::~LLQueuedThread()
 {
+	if (!mThreaded)
+	{
+		endThread();
+	}
 	shutdown();
 	// ~LLThread() will be called here
 }
@@ -106,6 +111,11 @@ void LLQueuedThread::shutdown()
 // virtual
 S32 LLQueuedThread::update(U32 max_time_ms)
 {
+	if (!mStarted)
+	{
+		startThread();
+		mStarted = TRUE;
+	}
 	return updateQueue(max_time_ms);
 }
 
@@ -452,26 +462,12 @@ S32 LLQueuedThread::processNextRequest()
 		}
 	}
 
-	S32 res;
 	S32 pending = getPending();
-	if (pending == 0)
-	{
-		if (isQuitting())
-		{
-			res = -1; // exit thread
-		}
-		else
-		{
-			res = 0;
-		}
-	}
-	else
-	{
-		res = pending;
-	}
-	return res;
+
+	return pending;
 }
 
+// virtual
 bool LLQueuedThread::runCondition()
 {
 	// mRunCondition must be locked here
@@ -481,35 +477,53 @@ bool LLQueuedThread::runCondition()
 		return true;
 }
 
+// virtual
 void LLQueuedThread::run()
 {
+	// call checPause() immediately so we don't try to do anything before the class is fully constructed
+	checkPause();
+	startThread();
+	mStarted = TRUE;
+	
 	while (1)
 	{
 		// this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state.
 		checkPause();
 		
-		if(isQuitting())
+		if (isQuitting())
+		{
+			endThread();
 			break;
-
-		//llinfos << "QUEUED THREAD RUNNING, queue size = " << mRequestQueue.size() << llendl;
+		}
 
 		mIdleThread = FALSE;
+
+		threadedUpdate();
 		
 		int res = processNextRequest();
 		if (res == 0)
 		{
 			mIdleThread = TRUE;
+			ms_sleep(1);
 		}
-		
-		if (res < 0) // finished working and want to exit
-		{
-			break;
-		}
-
 		//LLThread::yield(); // thread should yield after each request		
 	}
+	llinfos << "LLQueuedThread " << mName << " EXITING." << llendl;
+}
 
-	llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl;
+// virtual
+void LLQueuedThread::startThread()
+{
+}
+
+// virtual
+void LLQueuedThread::endThread()
+{
+}
+
+// virtual
+void LLQueuedThread::threadedUpdate()
+{
 }
 
 //============================================================================
diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h
index 3ba43e1e070db57c3ffa3d7b15744163e45b3988..bcd154da0b5a3690801386d90ee2552ba6eadc74 100644
--- a/indra/llcommon/llqueuedthread.h
+++ b/indra/llcommon/llqueuedthread.h
@@ -165,6 +165,9 @@ class LLQueuedThread : public LLThread
 
 	virtual bool runCondition(void);
 	virtual void run(void);
+	virtual void startThread(void);
+	virtual void endThread(void);
+	virtual void threadedUpdate(void);
 
 protected:
 	handle_t generateHandle();
@@ -199,6 +202,7 @@ class LLQueuedThread : public LLThread
 	
 protected:
 	BOOL mThreaded;  // if false, run on main thread and do updates during update()
+	BOOL mStarted;  // required when mThreaded is false to call startThread() from update()
 	LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
 	
 	typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index f25339f48d124ce2d8baf9d77984bcaa0afcb69e..1470dca14c51556aed919ad2ec45723748ce6a08 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -33,9 +33,7 @@
 #ifndef LL_LLTHREAD_H
 #define LL_LLTHREAD_H
 
-#include "llapr.h"
 #include "llapp.h"
-
 #include "apr_thread_cond.h"
 
 class LLThread;
diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp
index 5dda60075534e902230bdf28a28a3e847c8e758c..82c736266db63eddb435f0e9d197130a499283a2 100644
--- a/indra/llcommon/llworkerthread.cpp
+++ b/indra/llcommon/llworkerthread.cpp
@@ -201,6 +201,7 @@ LLWorkerClass::~LLWorkerClass()
 {
 	llassert_always(!(mWorkFlags & WCF_WORKING));
 	llassert_always(mWorkFlags & WCF_DELETE_REQUESTED);
+	llassert_always(!mMutex.isLocked());
 	if (mRequestHandle != LLWorkerThread::nullHandle())
 	{
 		LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle);
diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h
index 19407f4463886b922163d9857a2bed49457db130..4a4cd6c85f8958043d991e3a09e0ff9aed57c10a 100644
--- a/indra/llcommon/llworkerthread.h
+++ b/indra/llcommon/llworkerthread.h
@@ -52,6 +52,7 @@ class LLWorkerClass;
 
 class LLWorkerThread : public LLQueuedThread
 {
+	friend class LLWorkerClass;
 public:
 	class WorkRequest : public LLQueuedThread::QueuedRequest
 	{
@@ -92,8 +93,11 @@ class LLWorkerThread : public LLQueuedThread
 	
 	handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL);
 	
-	void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
 	S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug
+
+private:
+	void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion
+	
 };
 
 //============================================================================
diff --git a/indra/llimage/CMakeLists.txt b/indra/llimage/CMakeLists.txt
index 0635ddd5f5c2ed6da1e3f96b41ffa857b7cfdf7b..22be4078a1b034280a4ae36b07ee86eb396d9e8c 100644
--- a/indra/llimage/CMakeLists.txt
+++ b/indra/llimage/CMakeLists.txt
@@ -3,6 +3,7 @@
 project(llimage)
 
 include(00-Common)
+include(LLAddBuildTest)
 include(LLCommon)
 include(LLImage)
 include(LLMath)
@@ -59,3 +60,6 @@ target_link_libraries(llimage
     ${PNG_LIBRARIES}
     ${ZLIB_LIBRARIES}
     )
+
+# Add tests
+#ADD_BUILD_TEST(llimageworker llimage)
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 9bbc55509dd8f48809426d69cbfbe0d0c9bf5d0d..9cb005898d1e080a08d89f2b700f8e22bb1212f0 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -55,13 +55,9 @@ std::string LLImage::sLastErrorMessage;
 LLMutex* LLImage::sMutex = NULL;
 
 //static
-void LLImage::initClass(LLWorkerThread* workerthread)
+void LLImage::initClass()
 {
 	sMutex = new LLMutex(NULL);
-	if (workerthread)
-	{
-		LLImageWorker::initImageWorker(workerthread);
-	}
 	LLImageJ2C::openDSO();
 }
 
@@ -69,7 +65,6 @@ void LLImage::initClass(LLWorkerThread* workerthread)
 void LLImage::cleanupClass()
 {
 	LLImageJ2C::closeDSO();
-	LLImageWorker::cleanupImageWorker();
 	delete sMutex;
 	sMutex = NULL;
 }
@@ -316,6 +311,21 @@ void LLImageRaw::deleteData()
 	LLImageBase::deleteData();
 }
 
+void LLImageRaw::setDataAndSize(U8 *data, S32 width, S32 height, S8 components) 
+{ 
+	if(data == getData())
+	{
+		return ;
+	}
+
+	deleteData();
+
+	LLImageBase::setSize(width, height, components) ;
+	LLImageBase::setDataAndSize(data, width * height * components) ;
+	
+	sGlobalRawMemory += getDataSize();
+}
+
 BOOL LLImageRaw::resize(U16 width, U16 height, S8 components)
 {
 	if ((getWidth() == width) && (getHeight() == height) && (getComponents() == components))
@@ -816,6 +826,51 @@ void LLImageRaw::copyScaled( LLImageRaw* src )
 	}
 }
 
+//scale down image by not blending a pixel with its neighbors.
+BOOL LLImageRaw::scaleDownWithoutBlending( S32 new_width, S32 new_height)
+{
+	LLMemType mt1(mMemType);
+
+	S8 c = getComponents() ;
+	llassert((1 == c) || (3 == c) || (4 == c) );
+
+	S32 old_width = getWidth();
+	S32 old_height = getHeight();
+	
+	S32 new_data_size = old_width * new_height * c ;
+	llassert_always(new_data_size > 0);
+
+	F32 ratio_x = (F32)old_width / new_width ;
+	F32 ratio_y = (F32)old_height / new_height ;
+	if( ratio_x < 1.0f || ratio_y < 1.0f )
+	{
+		return TRUE;  // Nothing to do.
+	}
+	ratio_x -= 1.0f ;
+	ratio_y -= 1.0f ;
+
+	U8* new_data = new U8[new_data_size] ;
+	llassert_always(new_data != NULL) ;
+
+	U8* old_data = getData() ;
+	S32 i, j, k, s, t;
+	for(i = 0, s = 0, t = 0 ; i < new_height ; i++)
+	{
+		for(j = 0 ; j < new_width ; j++)
+		{
+			for(k = 0 ; k < c ; k++)
+			{
+				new_data[s++] = old_data[t++] ;
+			}
+			t += (S32)(ratio_x * c + 0.1f) ;
+		}
+		t += (S32)(ratio_y * old_width * c + 0.1f) ;
+	}
+
+	setDataAndSize(new_data, new_width, new_height, c) ;
+	
+	return TRUE ;
+}
 
 BOOL LLImageRaw::scale( S32 new_width, S32 new_height, BOOL scale_image_data )
 {
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index 81085531072dc7eda16fac65930999971f96063e..686f58388653fa1f5ff2e9814ea96ef46e889a0e 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -50,7 +50,8 @@ const S32 MAX_IMAGE_AREA = MAX_IMAGE_SIZE * MAX_IMAGE_SIZE;
 const S32 MAX_IMAGE_COMPONENTS = 8;
 const S32 MAX_IMAGE_DATA_SIZE = MAX_IMAGE_AREA * MAX_IMAGE_COMPONENTS;
 
-// Note!  These CANNOT be changed without invalidating the viewer VFS files, I think?
+// Note!  These CANNOT be changed without modifying simulator code
+// *TODO: change both to 1024 when SIM texture fetching is deprecated
 const S32 FIRST_PACKET_SIZE = 600;
 const S32 MAX_IMG_PACKET_SIZE = 1000;
 
@@ -61,7 +62,6 @@ const S32 MAX_IMG_PACKET_SIZE = 1000;
 class LLImageFormatted;
 class LLImageRaw;
 class LLColor4U;
-class LLWorkerThread;
 
 typedef enum e_image_codec
 {
@@ -82,7 +82,7 @@ typedef enum e_image_codec
 class LLImage
 {
 public:
-	static void initClass(LLWorkerThread* workerthread);
+	static void initClass();
 	static void cleanupClass();
 
 	static const std::string& getLastError();
@@ -131,7 +131,7 @@ class LLImageBase : public LLThreadSafeRefCount
 
 protected:
 	// special accessor to allow direct setting of mData and mDataSize by LLImageFormatted
-	void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; };
+	void setDataAndSize(U8 *data, S32 size) { mData = data; mDataSize = size; }
 	
 public:
 	static void generateMip(const U8 *indata, U8* mipdata, int width, int height, S32 nchannels);
@@ -192,6 +192,7 @@ class LLImageRaw : public LLImageBase
 	void contractToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE, BOOL scale_image = TRUE);
 	void biasedScaleToPowerOfTwo(S32 max_dim = MAX_IMAGE_SIZE);
 	BOOL scale( S32 new_width, S32 new_height, BOOL scale_image = TRUE );
+	BOOL scaleDownWithoutBlending( S32 new_width, S32 new_height) ;
 
 	// Fill the buffer with a constant color
 	void fill( const LLColor4U& color );
@@ -240,6 +241,8 @@ class LLImageRaw : public LLImageBase
 
 	U8	fastFractionalMult(U8 a,U8 b);
 
+	void setDataAndSize(U8 *data, S32 width, S32 height, S8 components) ;
+
 public:
 	static S32 sGlobalRawMemory;
 	static S32 sRawImageCount;
@@ -310,7 +313,7 @@ class LLImageFormatted : public LLImageBase
 protected:
 	S8 mCodec;
 	S8 mDecoding;
-	S8 mDecoded;
+	S8 mDecoded;  // unused, but changing LLImage layout requires recompiling static Mac/Linux libs. 2009-01-30 JC
 	S8 mDiscardLevel;
 	
 public:
diff --git a/indra/llimage/llimagedxt.cpp b/indra/llimage/llimagedxt.cpp
index 1ce4517a0d152b11fcb0ccba3a1ea9506dd58a41..0aa6840ff6aa99068e46d32e061ced5e3652aa18 100644
--- a/indra/llimage/llimagedxt.cpp
+++ b/indra/llimage/llimagedxt.cpp
@@ -264,6 +264,8 @@ void LLImageDXT::setFormat()
 // virtual
 BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
 {
+	// *TODO: Test! This has been tweaked since its intial inception,
+	//  but we don't use it any more!
 	llassert_always(raw_image);
 	
 	if (mFileFormat >= FORMAT_DXT1 && mFileFormat <= FORMAT_DXR5)
@@ -274,8 +276,17 @@ BOOL LLImageDXT::decode(LLImageRaw* raw_image, F32 time)
 	
 	S32 width = getWidth(), height = getHeight();
 	S32 ncomponents = getComponents();
+	U8* data = NULL;
+	if (mDiscardLevel >= 0)
+	{
+		data = getData() + getMipOffset(mDiscardLevel);
+		calcDiscardWidthHeight(mDiscardLevel, mFileFormat, width, height);
+	}
+	else
+	{
+		data = getData() + getMipOffset(0);
+	}
 	S32 image_size = formatBytes(mFileFormat, width, height);
-	U8* data = getData() + getMipOffset(0);
 	
 	if ((!getData()) || (data + image_size > getData() + getDataSize()))
 	{
@@ -300,10 +311,8 @@ BOOL LLImageDXT::getMipData(LLPointer<LLImageRaw>& raw, S32 discard)
 		llerrs << "Request for invalid discard level" << llendl;
 	}
 	U8* data = getData() + getMipOffset(discard);
-	// I'm not sure these are the correct initial values for height and width,
-	// but previously they were being used uninitialized. JC
-	S32 width = raw->getWidth();
-	S32 height = raw->getHeight();
+	S32 width = 0;
+	S32 height = 0;
 	calcDiscardWidthHeight(discard, mFileFormat, width, height);
 	raw = new LLImageRaw(data, width, height, getComponents());
 	return TRUE;
diff --git a/indra/llimage/llimagej2c.cpp b/indra/llimage/llimagej2c.cpp
index 363486fb9c013caa8e9ec4141c412638171e9188..49017cc508a1bb56da154970564223cdb0788cfc 100644
--- a/indra/llimage/llimagej2c.cpp
+++ b/indra/llimage/llimagej2c.cpp
@@ -277,6 +277,7 @@ BOOL LLImageJ2C::decode(LLImageRaw *raw_imagep, F32 decode_time)
 }
 
 
+// Returns TRUE to mean done, whether successful or not.
 BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 first_channel, S32 max_channel_count )
 {
 	LLMemType mt1(mMemType);
@@ -289,7 +290,7 @@ BOOL LLImageJ2C::decodeChannels(LLImageRaw *raw_imagep, F32 decode_time, S32 fir
 	if (!getData() || (getDataSize() < 16))
 	{
 		setLastError("LLImageJ2C uninitialized");
-		res = FALSE;
+		res = TRUE; // done
 	}
 	else
 	{
@@ -342,7 +343,7 @@ BOOL LLImageJ2C::encode(const LLImageRaw *raw_imagep, const char* comment_text,
 //static
 S32 LLImageJ2C::calcHeaderSizeJ2C()
 {
-	return 600; //2048; // ??? hack... just needs to be >= actual header size...
+	return FIRST_PACKET_SIZE; // Hack. just needs to be >= actual header size...
 }
 
 //static
diff --git a/indra/llimage/llimagejpeg.cpp b/indra/llimage/llimagejpeg.cpp
index fa0dd3ff050f3d32afe911147da47985ec7c90a7..79ea79cc070f52cbb29f92223c4661ffb622bdd0 100644
--- a/indra/llimage/llimagejpeg.cpp
+++ b/indra/llimage/llimagejpeg.cpp
@@ -188,6 +188,7 @@ void LLImageJPEG::decodeTermSource (j_decompress_ptr cinfo)
 }
 
 
+// Returns true when done, whether or not decode was successful.
 BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
 {
 	llassert_always(raw_image);
@@ -198,7 +199,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
 	if (!getData() || (0 == getDataSize()))
 	{
 		setLastError("LLImageJPEG trying to decode an image with no data!");
-		return FALSE;
+		return TRUE;  // done
 	}
 	
 	S32 row_stride = 0;
@@ -226,7 +227,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
 	if(setjmp(sSetjmpBuffer))
 	{
 		jpeg_destroy_decompress(&cinfo);
-		return FALSE;
+		return TRUE; // done
 	}
 	try
 	{
@@ -320,7 +321,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
 	catch (int)
 	{
 		jpeg_destroy_decompress(&cinfo);
-		return FALSE;
+		return TRUE; // done
 	}
 
 	// Check to see whether any corrupt-data warnings occurred
@@ -328,7 +329,7 @@ BOOL LLImageJPEG::decode(LLImageRaw* raw_image, F32 decode_time)
 	{
 		// TODO: extract the warning to find out what went wrong.
 		setLastError( "Unable to decode JPEG image.");
-		return FALSE;
+		return TRUE; // done
 	}
 
 	return TRUE;
diff --git a/indra/llimage/llimageworker.cpp b/indra/llimage/llimageworker.cpp
index 532e996188d5f5d2c1a577a217eef24858a96c11..86d41515e7ce85912925dc878d946a367033ac79 100644
--- a/indra/llimage/llimageworker.cpp
+++ b/indra/llimage/llimageworker.cpp
@@ -37,152 +37,138 @@
 
 //----------------------------------------------------------------------------
 
-//static
-LLWorkerThread* LLImageWorker::sWorkerThread = NULL;
-S32 LLImageWorker::sCount = 0;
+// MAIN THREAD
+LLImageDecodeThread::LLImageDecodeThread(bool threaded)
+	: LLQueuedThread("imagedecode", threaded)
+{
+	mCreationMutex = new LLMutex(getAPRPool());
+}
 
-//static
-void LLImageWorker::initImageWorker(LLWorkerThread* workerthread)
+// MAIN THREAD
+// virtual
+S32 LLImageDecodeThread::update(U32 max_time_ms)
 {
-	sWorkerThread = workerthread;
+	LLMutexLock lock(mCreationMutex);
+	for (creation_list_t::iterator iter = mCreationList.begin();
+		 iter != mCreationList.end(); ++iter)
+	{
+		creation_info& info = *iter;
+		ImageRequest* req = new ImageRequest(info.handle, info.image,
+											 info.priority, info.discard, info.needs_aux,
+											 info.responder);
+		addRequest(req);
+	}
+	mCreationList.clear();
+	S32 res = LLQueuedThread::update(max_time_ms);
+	return res;
 }
 
-//static
-void LLImageWorker::cleanupImageWorker()
+LLImageDecodeThread::handle_t LLImageDecodeThread::decodeImage(LLImageFormatted* image, 
+	U32 priority, S32 discard, BOOL needs_aux, Responder* responder)
+{
+	LLMutexLock lock(mCreationMutex);
+	handle_t handle = generateHandle();
+	mCreationList.push_back(creation_info(handle, image, priority, discard, needs_aux, responder));
+	return handle;
+}
+
+// Used by unit test only
+// Returns the size of the mutex guarded list as an indication of sanity
+S32 LLImageDecodeThread::tut_size()
+{
+	LLMutexLock lock(mCreationMutex);
+	S32 res = mCreationList.size();
+	return res;
+}
+
+LLImageDecodeThread::Responder::~Responder()
 {
 }
 
 //----------------------------------------------------------------------------
 
-LLImageWorker::LLImageWorker(LLImageFormatted* image, U32 priority,
-							 S32 discard,
-							 LLPointer<LLResponder> responder)
-	: LLWorkerClass(sWorkerThread, "Image"),
+LLImageDecodeThread::ImageRequest::ImageRequest(handle_t handle, LLImageFormatted* image, 
+												U32 priority, S32 discard, BOOL needs_aux,
+												LLImageDecodeThread::Responder* responder)
+	: LLQueuedThread::QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE),
 	  mFormattedImage(image),
-	  mDecodedType(-1),
 	  mDiscardLevel(discard),
-	  mPriority(priority),
+	  mNeedsAux(needs_aux),
+	  mDecodedRaw(FALSE),
+	  mDecodedAux(FALSE),
 	  mResponder(responder)
 {
-	++sCount;
 }
 
-LLImageWorker::~LLImageWorker()
+LLImageDecodeThread::ImageRequest::~ImageRequest()
 {
-	mDecodedImage = NULL;
+	mDecodedImageRaw = NULL;
+	mDecodedImageAux = NULL;
 	mFormattedImage = NULL;
-	--sCount;
 }
 
 //----------------------------------------------------------------------------
 
-//virtual, main thread
-void LLImageWorker::startWork(S32 param)
-{
-	llassert_always(mDecodedImage.isNull());
-	mDecodedType = -1;
-}
 
-bool LLImageWorker::doWork(S32 param)
+// Returns true when done, whether or not decode was successful.
+bool LLImageDecodeThread::ImageRequest::processRequest()
 {
-	bool decoded = false;
-	if(mDecodedImage.isNull())
+	const F32 decode_time_slice = .1f;
+	bool done = true;
+	if (!mDecodedRaw && mFormattedImage.notNull())
 	{
-		if (!mFormattedImage->updateData())
-		{
-			mDecodedType = -2; // failed
-			return true;
-		}
-		if (mDiscardLevel >= 0)
+		// Decode primary channels
+		if (mDecodedImageRaw.isNull())
 		{
-			mFormattedImage->setDiscardLevel(mDiscardLevel);
-		}
-		if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
-		{
-			decoded = true; // failed
-		}
-		else
-		{
-			mDecodedImage = new LLImageRaw(); // allow possibly smaller size set during decoding
+			// parse formatted header
+			if (!mFormattedImage->updateData())
+			{
+				return true; // done (failed)
+			}
+			if (!(mFormattedImage->getWidth() * mFormattedImage->getHeight() * mFormattedImage->getComponents()))
+			{
+				return true; // done (failed)
+			}
+			if (mDiscardLevel >= 0)
+			{
+				mFormattedImage->setDiscardLevel(mDiscardLevel);
+			}
+			mDecodedImageRaw = new LLImageRaw(mFormattedImage->getWidth(),
+											  mFormattedImage->getHeight(),
+											  mFormattedImage->getComponents());
 		}
+		done = mFormattedImage->decode(mDecodedImageRaw, decode_time_slice); // 1ms
+		mDecodedRaw = done;
 	}
-	if (!decoded)
+	if (done && mNeedsAux && !mDecodedAux && mFormattedImage.notNull())
 	{
-		if (param == 0)
-		{
-			// Decode primary channels
-			decoded = mFormattedImage->decode(mDecodedImage, .1f); // 1ms
-		}
-		else
+		// Decode aux channel
+		if (!mDecodedImageAux)
 		{
-			// Decode aux channel
-			decoded = mFormattedImage->decodeChannels(mDecodedImage, .1f, param, param); // 1ms
+			mDecodedImageAux = new LLImageRaw(mFormattedImage->getWidth(),
+											  mFormattedImage->getHeight(),
+											  1);
 		}
+		done = mFormattedImage->decodeChannels(mDecodedImageAux, decode_time_slice, 4, 4); // 1ms
+		mDecodedAux = done;
 	}
-	if (decoded)
-	{
-		// Call the callback immediately; endWork doesn't get called until ckeckWork
-		if (mResponder.notNull())
-		{
-			bool success = (!wasAborted() && mDecodedImage.notNull() && mDecodedImage->getDataSize() != 0);
-			mResponder->completed(success);
-		}
-	}
-	return decoded;
-}
 
-void LLImageWorker::endWork(S32 param, bool aborted)
-{
-	if (mDecodedType != -2)
-	{
-		mDecodedType = aborted ? -2 : param;
-	}
+	return done;
 }
 
-//----------------------------------------------------------------------------
-
-
-BOOL LLImageWorker::requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard)
+void LLImageDecodeThread::ImageRequest::finishRequest(bool completed)
 {
-	// For most codecs, only mDiscardLevel data is available.
-	//  (see LLImageDXT for exception)
-	if (discard >= 0 && discard != mFormattedImage->getDiscardLevel())
-	{
-		llerrs << "Request for invalid discard level" << llendl;
-	}
-	checkWork();
-	if (mDecodedType == -2)
+	if (mResponder.notNull())
 	{
-		return TRUE; // aborted, done
-	}
-	if (mDecodedType != channel)
-	{
-		if (!haveWork())
-		{
-			addWork(channel, mPriority);
-		}
-		return FALSE;
-	}
-	else
-	{
-		llassert_always(!haveWork());
-		llassert_always(mDecodedType == channel);
-		raw = mDecodedImage; // smart pointer acquires ownership of data
-		mDecodedImage = NULL;
-		return TRUE;
+		bool success = completed && mDecodedRaw && (!mNeedsAux || mDecodedAux);
+		mResponder->completed(success, mDecodedImageRaw, mDecodedImageAux);
 	}
+	// Will automatically be deleted
 }
 
-BOOL LLImageWorker::requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard)
+// Used by unit test only
+// Checks that a responder exists for this instance so that something can happen when completion is reached
+bool LLImageDecodeThread::ImageRequest::tut_isOK()
 {
-	if (mFormattedImage->getCodec() == IMG_CODEC_DXT)
-	{
-		// special case
-		LLImageDXT* imagedxt = (LLImageDXT*)((LLImageFormatted*)mFormattedImage);
-		return imagedxt->getMipData(raw, discard);
-	}
-	else
-	{
-		return requestDecodedAuxData(raw, 0, discard);
-	}
+	return mResponder.notNull();
 }
diff --git a/indra/llimage/llimageworker.h b/indra/llimage/llimageworker.h
index 0d66695d6ecfc7e09c7a25a37875fd1bed295fc2..6a5b86a277940cf2bf28d2358d9c480cf122d142 100644
--- a/indra/llimage/llimageworker.h
+++ b/indra/llimage/llimageworker.h
@@ -37,49 +37,72 @@
 #include "llpointer.h"
 #include "llworkerthread.h"
 
-class LLImageWorker : public LLWorkerClass
+class LLImageDecodeThread : public LLQueuedThread
 {
 public:
-	static void initImageWorker(LLWorkerThread* workerthread);
-	static void cleanupImageWorker();
-	
-public:
-	static LLWorkerThread* getWorkerThread() { return sWorkerThread; }
-
-	// LLWorkerThread
-public:
-	LLImageWorker(LLImageFormatted* image, U32 priority, S32 discard,
-				  LLPointer<LLResponder> responder);
-	~LLImageWorker();
-
-	// called from WORKER THREAD, returns TRUE if done
-	/*virtual*/ bool doWork(S32 param);
-	
-	BOOL requestDecodedData(LLPointer<LLImageRaw>& raw, S32 discard = -1);
-	BOOL requestDecodedAuxData(LLPointer<LLImageRaw>& raw, S32 channel, S32 discard = -1);
-	void releaseDecodedData();
-	void cancelDecode();
+	class Responder : public LLThreadSafeRefCount
+	{
+	protected:
+		virtual ~Responder();
+	public:
+		virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux) = 0;
+	};
 
-private:
-	// called from MAIN THREAD
-	/*virtual*/ void startWork(S32 param); // called from addWork()
-	/*virtual*/ void endWork(S32 param, bool aborted); // called from doWork()
+	class ImageRequest : public LLQueuedThread::QueuedRequest
+	{
+	protected:
+		virtual ~ImageRequest(); // use deleteRequest()
+		
+	public:
+		ImageRequest(handle_t handle, LLImageFormatted* image,
+					 U32 priority, S32 discard, BOOL needs_aux,
+					 LLImageDecodeThread::Responder* responder);
 
-protected:
-	LLPointer<LLImageFormatted> mFormattedImage;
-	LLPointer<LLImageRaw> mDecodedImage;
-	S32 mDecodedType;
-	S32 mDiscardLevel;
+		/*virtual*/ bool processRequest();
+		/*virtual*/ void finishRequest(bool completed);
 
-private:
-	U32 mPriority;
-	LLPointer<LLResponder> mResponder;
+		// Used by unit tests to check the consitency of the request instance
+		bool tut_isOK();
+		
+	private:
+		// input
+		LLPointer<LLImageFormatted> mFormattedImage;
+		S32 mDiscardLevel;
+		BOOL mNeedsAux;
+		// output
+		LLPointer<LLImageRaw> mDecodedImageRaw;
+		LLPointer<LLImageRaw> mDecodedImageAux;
+		BOOL mDecodedRaw;
+		BOOL mDecodedAux;
+		LLPointer<LLImageDecodeThread::Responder> mResponder;
+	};
 	
-protected:
-	static LLWorkerThread* sWorkerThread;
-
 public:
-	static S32 sCount;
+	LLImageDecodeThread(bool threaded = true);
+	handle_t decodeImage(LLImageFormatted* image,
+						 U32 priority, S32 discard, BOOL needs_aux,
+						 Responder* responder);
+	S32 update(U32 max_time_ms);
+
+	// Used by unit tests to check the consistency of the thread instance
+	S32 tut_size();
+	
+private:
+	struct creation_info
+	{
+		handle_t handle;
+		LLPointer<LLImageFormatted> image;
+		U32 priority;
+		S32 discard;
+		BOOL needs_aux;
+		LLPointer<Responder> responder;
+		creation_info(handle_t h, LLImageFormatted* i, U32 p, S32 d, BOOL aux, Responder* r)
+			: handle(h), image(i), priority(p), discard(d), needs_aux(aux), responder(r)
+		{}
+	};
+	typedef std::list<creation_info> creation_list_t;
+	creation_list_t mCreationList;
+	LLMutex* mCreationMutex;
 };
 
 #endif
diff --git a/indra/llimage/tests/llimageworker_test.cpp b/indra/llimage/tests/llimageworker_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cc44696a453b9f3cfaabee57867f26f510c86593
--- /dev/null
+++ b/indra/llimage/tests/llimageworker_test.cpp
@@ -0,0 +1,260 @@
+/** 
+ * @file llimageworker_test.cpp
+ * @author Merov Linden
+ * @date 2009-04-28
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-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$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include <list>
+#include <map>
+#include <algorithm>
+// Class to test
+#include "../llimageworker.h"
+// For timer class
+#include "../llcommon/lltimer.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes: 
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+LLImageBase::LLImageBase() {}
+LLImageBase::~LLImageBase() {}
+void LLImageBase::dump() { }
+void LLImageBase::sanityCheck() { }
+void LLImageBase::deleteData() { }
+U8* LLImageBase::allocateData(S32 size) { return NULL; }
+U8* LLImageBase::reallocateData(S32 size) { return NULL; }
+
+LLImageRaw::LLImageRaw(U16 width, U16 height, S8 components) { }
+LLImageRaw::~LLImageRaw() { }
+void LLImageRaw::deleteData() { }
+U8* LLImageRaw::allocateData(S32 size) { return NULL; }
+U8* LLImageRaw::reallocateData(S32 size) { return NULL; }
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+	// Test wrapper declarations
+
+	// Note: We derive the responder class for 2 reasons:
+	// 1. It's a pure virtual class and we can't compile without completed() being implemented
+	// 2. We actually need a responder to test that the thread work test completed
+	// We implement this making no assumption on what's done in the thread or worker
+	// though, just that the responder's completed() method is called in the end.
+	// Note on responders: responders are ref counted and *will* be deleted by the request they are 
+	// attached to when the queued request is deleted. The recommended way of using them is to 
+	// create them when creating a request, put a callback method in completed() and not rely on 
+	// anything to survive in the responder object once completed() has been called. Let the request
+	// do the deletion and clean up itself.
+	class responder_test : public LLImageDecodeThread::Responder
+	{
+		public:
+			responder_test(bool* res)
+			{ 
+				done = res;
+				*done = false;
+			}
+			virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
+			{
+				*done = true;
+			}
+		private:
+			// This is what can be thought of as the minimal implementation of a responder
+			// Done will be switched to true when completed() is called and can be tested
+			// outside the responder. A better way of doing this is to store a callback here.
+			bool* done;
+	};
+
+	// Test wrapper declaration : decode thread
+	struct imagedecodethread_test
+	{
+		// Instance to be tested
+		LLImageDecodeThread* mThread;
+
+		// Constructor and destructor of the test wrapper
+		imagedecodethread_test()
+		{
+			mThread = NULL;
+		}
+		~imagedecodethread_test()
+		{
+			delete mThread;
+		}
+	};
+
+	// Test wrapper declaration : image worker
+	// Note: this class is not meant to be instantiated outside an LLImageDecodeThread instance
+	// but it's not a bad idea to get its public API a good shake as part of a thorough unit test set.
+	// Some gotcha with the destructor though (see below).
+	struct imagerequest_test
+	{
+		// Instance to be tested
+		LLImageDecodeThread::ImageRequest* mRequest;
+		bool done;
+
+		// Constructor and destructor of the test wrapper
+		imagerequest_test()
+		{
+			done = false;
+			mRequest = new LLImageDecodeThread::ImageRequest(0, 0,
+											 LLQueuedThread::PRIORITY_NORMAL, 0, FALSE,
+											 new responder_test(&done));
+		}
+		~imagerequest_test()
+		{
+			// We should delete the object *but*, because its destructor is protected, that cannot be
+			// done from outside an LLImageDecodeThread instance... So we leak memory here... It's fine...
+			//delete mRequest;
+		}
+	};
+
+	// Tut templating thingamagic: test group, object and test instance
+	typedef test_group<imagedecodethread_test> imagedecodethread_t;
+	typedef imagedecodethread_t::object imagedecodethread_object_t;
+	tut::imagedecodethread_t tut_imagedecodethread("imagedecodethread");
+
+	typedef test_group<imagerequest_test> imagerequest_t;
+	typedef imagerequest_t::object imagerequest_object_t;
+	tut::imagerequest_t tut_imagerequest("imagerequest");
+
+	// ---------------------------------------------------------------------------------------
+	// Test functions
+	// Notes:
+	// * Test as many as you possibly can without requiring a full blown simulation of everything
+	// * The tests are executed in sequence so the test instance state may change between calls
+	// * Remember that you cannot test private methods with tut
+	// ---------------------------------------------------------------------------------------
+
+	// ---------------------------------------------------------------------------------------
+	// Test the LLImageDecodeThread interface
+	// ---------------------------------------------------------------------------------------
+	//
+	// Note on Unit Testing Queued Thread Classes
+	//
+	// Since methods on such a class are called on a separate loop and that we can't insert tut
+	// ensure() calls in there, we exercise the class with 2 sets of tests:
+	// - 1: Test as a single threaded instance: We declare the class but ask for no thread
+	//   to be spawned (easy with LLThreads since there's a boolean argument on the constructor
+	//   just for that). We can then unit test each public method like we do on a normal class.
+	// - 2: Test as a threaded instance: We let the thread launch and check that its external 
+	//   behavior is as expected (i.e. it runs, can accept a work order and processes
+	//   it). Typically though there's no guarantee that this exercises all the methods of the
+	//   class which is why we also need the previous "non threaded" set of unit tests for
+	//   complete coverage.
+	//
+	// ---------------------------------------------------------------------------------------
+
+	template<> template<>
+	void imagedecodethread_object_t::test<1>()
+	{
+		// Test a *non threaded* instance of the class
+		mThread = new LLImageDecodeThread(false);
+		ensure("LLImageDecodeThread: non threaded constructor failed", mThread != NULL);
+		// Test that we start with an empty list right at creation
+		ensure("LLImageDecodeThread: non threaded init state incorrect", mThread->tut_size() == 0);
+		// Insert something in the queue
+		bool done = false;
+		LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
+		// Verifies we got a valid handle
+		ensure("LLImageDecodeThread: non threaded decodeImage(), returned handle is null", decodeHandle != 0);
+		// Verifies that we do now have something in the queued list
+		ensure("LLImageDecodeThread: non threaded decodeImage() insertion in threaded list failed", mThread->tut_size() == 1);
+		// Trigger queue handling "manually" (on a threaded instance, this is done on the thread loop)
+		S32 res = mThread->update(0);
+		// Verifies that we successfully handled the list
+		ensure("LLImageDecodeThread: non threaded update() list handling test failed", res == 0);
+		// Verifies that the list is now empty
+		ensure("LLImageDecodeThread: non threaded update() list emptying test failed", mThread->tut_size() == 0);
+	}
+
+	template<> template<>
+	void imagedecodethread_object_t::test<2>()
+	{
+		// Test a *threaded* instance of the class
+		mThread = new LLImageDecodeThread(true);
+		ensure("LLImageDecodeThread: threaded constructor failed", mThread != NULL);
+		// Test that we start with an empty list right at creation
+		ensure("LLImageDecodeThread: threaded init state incorrect", mThread->tut_size() == 0);
+		// Insert something in the queue
+		bool done = false;
+		LLImageDecodeThread::handle_t decodeHandle = mThread->decodeImage(NULL, LLQueuedThread::PRIORITY_NORMAL, 0, FALSE, new responder_test(&done));
+		// Verifies we get back a valid handle
+		ensure("LLImageDecodeThread:  threaded decodeImage(), returned handle is null", decodeHandle != 0);
+		// Wait a little so to simulate the main thread doing something on its main loop...
+		ms_sleep(500);		// 500 milliseconds
+		// Verifies that the responder has *not* been called yet in the meantime
+		ensure("LLImageDecodeThread: responder creation failed", done == false);
+		// Ask the thread to update: that means tells the queue to check itself and creates work requests
+		mThread->update(1);
+		// Wait till the thread has time to handle the work order (though it doesn't do much per work order...)
+		const U32 INCREMENT_TIME = 500;				// 500 milliseconds
+		const U32 MAX_TIME = 20 * INCREMENT_TIME;	// Do the loop 20 times max, i.e. wait 10 seconds but no more
+		U32 total_time = 0;
+		while ((done == false) && (total_time < MAX_TIME))
+		{
+			ms_sleep(INCREMENT_TIME);
+			total_time += INCREMENT_TIME;
+		}
+		// Verifies that the responder has now been called
+		ensure("LLImageDecodeThread: threaded work unit not processed", done == true);
+	}
+
+	// ---------------------------------------------------------------------------------------
+	// Test the LLImageDecodeThread::ImageRequest interface
+	// ---------------------------------------------------------------------------------------
+	
+	template<> template<>
+	void imagerequest_object_t::test<1>()
+	{
+		// Test that we start with a correct request at creation
+		ensure("LLImageDecodeThread::ImageRequest::ImageRequest() constructor test failed", mRequest->tut_isOK());
+		bool res = mRequest->processRequest();
+		// Verifies that we processed the request successfully
+		ensure("LLImageDecodeThread::ImageRequest::processRequest() processing request test failed", res == true);
+		// Check that we can call the finishing call safely
+		try {
+			mRequest->finishRequest(false);
+		} catch (...) {
+			fail("LLImageDecodeThread::ImageRequest::finishRequest() test failed");
+		}
+	}
+}
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index b8ef92f9a989df96f04c4e1a088ac63f5db62d59..df4c618ac10e187cad7aee71b970e880b970baae 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -3582,7 +3582,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
 	if (face == -1) // ALL_SIDES
 	{
 		start_face = 0;
-		end_face = getNumFaces() - 1;
+		end_face = getNumVolumeFaces() - 1;
 	}
 	else
 	{
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index b3087bcc3f80883972c895bc542ac8512d94519e..0ab10812006c41c75ca77569927e9966bafafee4 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -64,6 +64,9 @@ const LLUUID CATEGORIZE_LOST_AND_FOUND_ID(std::string("00000000-0000-0000-0000-0
 
 const U64 TOXIC_ASSET_LIFETIME = (120 * 1000000);		// microseconds
 
+LLTempAssetStorage::~LLTempAssetStorage()
+{
+}
 
 ///----------------------------------------------------------------------------
 /// LLAssetInfo
diff --git a/indra/llmessage/llassetstorage.h b/indra/llmessage/llassetstorage.h
index 56adbd5ccfe84f0f1f34428ad2c8481947dd1176..83cfdf6110f990c2fe75fe6d491c2f683be5fbad 100644
--- a/indra/llmessage/llassetstorage.h
+++ b/indra/llmessage/llassetstorage.h
@@ -204,7 +204,16 @@ typedef std::map<LLUUID,U64,lluuid_less> toxic_asset_map_t;
 typedef void (*LLGetAssetCallback)(LLVFS *vfs, const LLUUID &asset_id,
 										 LLAssetType::EType asset_type, void *user_data, S32 status, LLExtStat ext_status);
 
-class LLAssetStorage
+class LLTempAssetStorage
+{
+public:
+	virtual ~LLTempAssetStorage() =0;
+	virtual void addTempAssetData(const LLUUID& asset_id,
+								  const LLUUID& agent_id,
+								  const std::string& host_name) = 0;
+};
+
+class LLAssetStorage : public LLTempAssetStorage
 {
 public:
 	// VFS member is public because static child methods need it :(
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index a4af8e989ba7436c067ae67105c197feb19af458..14771ef6dd8a1fa483fd9a919c04f4b97a58c1aa 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -220,7 +220,7 @@ class LLCurl::Easy
 	U32 report(CURLcode);
 	void getTransferInfo(LLCurl::TransferInfo* info);
 
-	void prepRequest(const std::string& url, ResponderPtr, bool post = false);
+	void prepRequest(const std::string& url, const std::vector<std::string>& headers, ResponderPtr, bool post = false);
 	
 	const char* getErrorBuffer();
 
@@ -432,7 +432,9 @@ size_t curlHeaderCallback(void* data, size_t size, size_t nmemb, void* user_data
 	return n;
 }
 
-void LLCurl::Easy::prepRequest(const std::string& url, ResponderPtr responder, bool post)
+void LLCurl::Easy::prepRequest(const std::string& url,
+							   const std::vector<std::string>& headers,
+							   ResponderPtr responder, bool post)
 {
 	resetState();
 	
@@ -465,8 +467,13 @@ void LLCurl::Easy::prepRequest(const std::string& url, ResponderPtr responder, b
 	{
 		slist_append("Connection: keep-alive");
 		slist_append("Keep-alive: 300");
+		// Accept and other headers
+		for (std::vector<std::string>::const_iterator iter = headers.begin();
+			 iter != headers.end(); ++iter)
+		{
+			slist_append((*iter).c_str());
+		}
 	}
-	// *FIX: should have ACCEPT headers
 }
 
 ////////////////////////////////////////////////////////////////////////////
@@ -676,15 +683,18 @@ LLCurlRequest::LLCurlRequest() :
 	mActiveMulti(NULL),
 	mActiveRequestCount(0)
 {
+	mThreadID = LLThread::currentID();
 }
 
 LLCurlRequest::~LLCurlRequest()
 {
+	llassert_always(mThreadID == LLThread::currentID());
 	for_each(mMultiSet.begin(), mMultiSet.end(), DeletePointer());
 }
 
 void LLCurlRequest::addMulti()
 {
+	llassert_always(mThreadID == LLThread::currentID());
 	LLCurl::Multi* multi = new LLCurl::Multi();
 	mMultiSet.insert(multi);
 	mActiveMulti = multi;
@@ -714,17 +724,20 @@ bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
 
 void LLCurlRequest::get(const std::string& url, LLCurl::ResponderPtr responder)
 {
-	getByteRange(url, 0, -1, responder);
+	getByteRange(url, headers_t(), 0, -1, responder);
 }
 	
-bool LLCurlRequest::getByteRange(const std::string& url, S32 offset, S32 length, LLCurl::ResponderPtr responder)
+bool LLCurlRequest::getByteRange(const std::string& url,
+								 const headers_t& headers,
+								 S32 offset, S32 length,
+								 LLCurl::ResponderPtr responder)
 {
 	LLCurl::Easy* easy = allocEasy();
 	if (!easy)
 	{
 		return false;
 	}
-	easy->prepRequest(url, responder);
+	easy->prepRequest(url, headers, responder);
 	easy->setopt(CURLOPT_HTTPGET, 1);
 	if (length > 0)
 	{
@@ -736,14 +749,17 @@ bool LLCurlRequest::getByteRange(const std::string& url, S32 offset, S32 length,
 	return res;
 }
 
-bool LLCurlRequest::post(const std::string& url, const LLSD& data, LLCurl::ResponderPtr responder)
+bool LLCurlRequest::post(const std::string& url,
+						 const headers_t& headers,
+						 const LLSD& data,
+						 LLCurl::ResponderPtr responder)
 {
 	LLCurl::Easy* easy = allocEasy();
 	if (!easy)
 	{
 		return false;
 	}
-	easy->prepRequest(url, responder);
+	easy->prepRequest(url, headers, responder);
 
 	LLSDSerialize::toXML(data, easy->getInput());
 	S32 bytes = easy->getInput().str().length();
@@ -763,6 +779,7 @@ bool LLCurlRequest::post(const std::string& url, const LLSD& data, LLCurl::Respo
 // Note: call once per frame
 S32 LLCurlRequest::process()
 {
+	llassert_always(mThreadID == LLThread::currentID());
 	S32 res = 0;
 	for (curlmulti_set_t::iterator iter = mMultiSet.begin();
 		 iter != mMultiSet.end(); )
@@ -782,6 +799,7 @@ S32 LLCurlRequest::process()
 
 S32 LLCurlRequest::getQueued()
 {
+	llassert_always(mThreadID == LLThread::currentID());
 	S32 queued = 0;
 	for (curlmulti_set_t::iterator iter = mMultiSet.begin();
 		 iter != mMultiSet.end(); )
@@ -1002,7 +1020,7 @@ void LLCurl::initClass()
 	S32 mutex_count = CRYPTO_num_locks();
 	for (S32 i=0; i<mutex_count; i++)
 	{
-		sSSLMutex.push_back(new LLMutex(gAPRPoolp));
+		sSSLMutex.push_back(new LLMutex(NULL));
 	}
 	CRYPTO_set_id_callback(&LLCurl::ssl_thread_id);
 	CRYPTO_set_locking_callback(&LLCurl::ssl_locking_callback);
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index fbd3077cbf75eddadebadb6ecb535fb7757ee8cd..32637b200e8434decf013ea3fc8b7712a7216061 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -188,12 +188,14 @@ namespace boost
 class LLCurlRequest
 {
 public:
+	typedef std::vector<std::string> headers_t;
+	
 	LLCurlRequest();
 	~LLCurlRequest();
 
 	void get(const std::string& url, LLCurl::ResponderPtr responder);
-	bool getByteRange(const std::string& url, S32 offset, S32 length, LLCurl::ResponderPtr responder);
-	bool post(const std::string& url, const LLSD& data, LLCurl::ResponderPtr responder);
+	bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
+	bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder);
 	S32  process();
 	S32  getQueued();
 
@@ -207,6 +209,7 @@ class LLCurlRequest
 	curlmulti_set_t mMultiSet;
 	LLCurl::Multi* mActiveMulti;
 	S32 mActiveRequestCount;
+	U32 mThreadID; // debug
 };
 
 class LLCurlEasyRequest
diff --git a/indra/llmessage/tests/llcurl_stub.cpp b/indra/llmessage/tests/llcurl_stub.cpp
index 5dc5932fde9db420c408ac4a0747a92e34cc01c7..db5ffaf3eeeee6c9146bf91af360aaf0915508c3 100644
--- a/indra/llmessage/tests/llcurl_stub.cpp
+++ b/indra/llmessage/tests/llcurl_stub.cpp
@@ -20,8 +20,9 @@
  */
 
 #include "linden_common.h"
+#include "llcurl.h"
 
-LLCurl::Responder::Responder()
+LLCurl::Responder::Responder() : mReferenceCount(0)
 {
 }
 
diff --git a/indra/llmessage/tests/llhttpclientadapter_test.cpp b/indra/llmessage/tests/llhttpclientadapter_test.cpp
index 250fa100b67b7a5e7fb1e838502ea34846fda2cc..7065c9d7e4afb2986677c346ca511432261f7c4a 100644
--- a/indra/llmessage/tests/llhttpclientadapter_test.cpp
+++ b/indra/llmessage/tests/llhttpclientadapter_test.cpp
@@ -50,7 +50,7 @@ std::vector<std::string> put_urls;
 std::vector<LLSD> put_body;
 std::vector<boost::intrusive_ptr<LLCurl::Responder> > put_responders;
 
-void LLHTTPClient::put(std::string const &url, LLSD const &body, boost::intrusive_ptr<LLCurl::Responder> responder,float) 
+void LLHTTPClient::put(const std::string& url, const LLSD& body, boost::intrusive_ptr<LLCurl::Responder> responder, const LLSD& headers, const F32 timeout)
 {
 	put_urls.push_back(url);
 	put_responders.push_back(responder);
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index e5fea5b995ee192a80d413ba3731b530e0cb9fd0..f8d7ea00e0cf1ac473ad6ee63b5c835676498ce2 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -43,7 +43,6 @@
 #include "llmath.h"
 #include "llgl.h"
 #include "llrender.h"
-
 //----------------------------------------------------------------------------
 const F32 MIN_TEXTURE_LIFETIME = 10.f;
 
@@ -60,21 +59,34 @@ std::list<U32> LLImageGL::sDeadTextureList;
 
 BOOL LLImageGL::sGlobalUseAnisotropic	= FALSE;
 F32 LLImageGL::sLastFrameTime			= 0.f;
+BOOL LLImageGL::sAllowReadBackRaw       = FALSE ;
 LLImageGL* LLImageGL::sDefaultGLTexture = NULL ;
+
 std::set<LLImageGL*> LLImageGL::sImageList;
 
-#if !LL_RELEASE_FOR_DOWNLOAD
+//****************************************************************************************************
+//The below for texture auditing use only
+//****************************************************************************************************
 //-----------------------
 //debug use
+BOOL gAuditTexture = FALSE ;
 #define MAX_TEXTURE_LOG_SIZE 22 //2048 * 2048
 std::vector<S32> LLImageGL::sTextureLoadedCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
 std::vector<S32> LLImageGL::sTextureBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
 std::vector<S32> LLImageGL::sTextureCurBoundCounter(MAX_TEXTURE_LOG_SIZE + 1) ;
 S32 LLImageGL::sCurTexSizeBar = -1 ;
 S32 LLImageGL::sCurTexPickSize = -1 ;
-LLPointer<LLImageGL> LLImageGL::sDefaultTexturep = NULL;
+LLPointer<LLImageGL> LLImageGL::sHighlightTexturep = NULL;
+S32 LLImageGL::sMaxCatagories = 1 ;
+
+std::vector<S32> LLImageGL::sTextureMemByCategory;
+std::vector<S32> LLImageGL::sTextureMemByCategoryBound ;
+std::vector<S32> LLImageGL::sTextureCurMemByCategoryBound ;
 //------------------------
-#endif
+//****************************************************************************************************
+//End for texture auditing use only
+//****************************************************************************************************
+
 //**************************************************************************************
 //below are functions for debug use
 //do not delete them even though they are not currently being used.
@@ -144,6 +156,60 @@ void LLImageGL::checkTexSize() const
 //**************************************************************************************
 
 //----------------------------------------------------------------------------
+BOOL is_little_endian()
+{
+	S32 a = 0x12345678;
+    U8 *c = (U8*)(&a);
+    
+	return (*c == 0x78) ;
+}
+//static 
+void LLImageGL::initClass(S32 num_catagories) 
+{
+	sMaxCatagories = num_catagories ;
+
+	sTextureMemByCategory.resize(sMaxCatagories);
+	sTextureMemByCategoryBound.resize(sMaxCatagories) ;
+	sTextureCurMemByCategoryBound.resize(sMaxCatagories) ;
+}
+
+//static 
+void LLImageGL::cleanupClass() 
+{	
+	sTextureMemByCategory.clear() ;
+	sTextureMemByCategoryBound.clear() ;
+	sTextureCurMemByCategoryBound.clear() ;
+}
+
+//static 
+void LLImageGL::setHighlightTexture(S32 category) 
+{
+	const S32 dim = 128;
+	sHighlightTexturep = new LLImageGL() ;
+	LLPointer<LLImageRaw> image_raw = new LLImageRaw(dim,dim,3);
+	U8* data = image_raw->getData();
+	for (S32 i = 0; i<dim; i++)
+	{
+		for (S32 j = 0; j<dim; j++)
+		{
+			const S32 border = 2;
+			if (i<border || j<border || i>=(dim-border) || j>=(dim-border))
+			{
+				*data++ = 0xff;
+				*data++ = 0xff;
+				*data++ = 0xff;
+			}
+			else
+			{
+				*data++ = 0xff;
+				*data++ = 0xff;
+				*data++ = 0x00;
+			}
+		}
+	}
+	sHighlightTexturep->createGLTexture(0, image_raw, 0, TRUE, category);
+	image_raw = NULL;
+}
 
 //static
 S32 LLImageGL::dataFormatBits(S32 dataformat)
@@ -211,19 +277,31 @@ void LLImageGL::updateStats(F32 current_time)
 	sBoundTextureMemoryInBytes = sCurBoundTextureMemory;
 	sCurBoundTextureMemory = 0;
 
-#if !LL_RELEASE_FOR_DOWNLOAD
-	for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++)
+	if(gAuditTexture)
 	{
-		sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ;
-		sTextureCurBoundCounter[i] = 0 ;
+		for(U32 i = 0 ; i < sTextureCurBoundCounter.size() ; i++)
+		{
+			sTextureBoundCounter[i] = sTextureCurBoundCounter[i] ;
+			sTextureCurBoundCounter[i] = 0 ;
+		}
+		for(U32 i = 0 ; i < sTextureCurMemByCategoryBound.size() ; i++)
+		{
+			sTextureMemByCategoryBound[i] = sTextureCurMemByCategoryBound[i] ;
+			sTextureCurMemByCategoryBound[i] = 0 ;
+		}
 	}
-#endif
 }
 
 //static
-S32 LLImageGL::updateBoundTexMem(const S32 delta)
+S32 LLImageGL::updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category)
 {
-	LLImageGL::sCurBoundTextureMemory += delta;
+	if(gAuditTexture && ncomponents > 0 && category > -1)
+	{
+		sTextureCurBoundCounter[getTextureCounterIndex(mem / ncomponents)]++ ;
+		sTextureCurMemByCategoryBound[category] += mem ;
+	}
+	
+	LLImageGL::sCurBoundTextureMemory += mem ;
 	return LLImageGL::sCurBoundTextureMemory;
 }
 
@@ -237,6 +315,7 @@ void LLImageGL::destroyGL(BOOL save_state)
 		gGL.getTexUnit(stage)->unbind(LLTexUnit::TT_TEXTURE);
 	}
 	
+	sAllowReadBackRaw = true ;
 	for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
 		 iter != sImageList.end(); iter++)
 	{
@@ -246,7 +325,7 @@ void LLImageGL::destroyGL(BOOL save_state)
 			if (save_state && glimage->isGLTextureCreated() && glimage->mComponents)
 			{
 				glimage->mSaveData = new LLImageRaw;
-				if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false))
+				if(!glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false)) //necessary, keep it.
 				{
 					glimage->mSaveData = NULL ;
 				}
@@ -256,6 +335,7 @@ void LLImageGL::destroyGL(BOOL save_state)
 			stop_glerror();
 		}
 	}
+	sAllowReadBackRaw = false ;
 }
 
 //static 
@@ -273,7 +353,7 @@ void LLImageGL::restoreGL()
 		{
 			if (glimage->getComponents() && glimage->mSaveData->getComponents())
 			{
-				glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData);
+				glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData, 0, TRUE, glimage->getCategory());
 				stop_glerror();
 			}
 			glimage->mSaveData = NULL; // deletes data
@@ -355,7 +435,7 @@ void LLImageGL::init(BOOL usemipmaps)
 	mPickMask		  = NULL;
 	mTextureMemory    = 0;
 	mLastBindTime     = 0.f;
-
+	
 	mTarget			  = GL_TEXTURE_2D;
 	mBindTarget		  = LLTexUnit::TT_TEXTURE;
 	mUseMipMaps		  = usemipmaps;
@@ -381,7 +461,11 @@ void LLImageGL::init(BOOL usemipmaps)
 	mHasExplicitFormat = FALSE;
 
 	mGLTextureCreated = FALSE ;
+
 	mIsMask = FALSE;
+	mCategory = -1 ;
+	mAlphaStride = 0 ;
+	mAlphaOffset = 0 ;
 	mNeedsAlphaAndPickMask = TRUE ;
 
 	mDiscardLevelInAtlas = -1 ;
@@ -486,6 +570,10 @@ void LLImageGL::dump()
 }
 
 //----------------------------------------------------------------------------
+void LLImageGL::forceUpdateBindStats(void) const
+{
+	mLastBindTime = sLastFrameTime;
+}
 
 BOOL LLImageGL::updateBindStats(S32 tex_mem) const
 {	
@@ -499,7 +587,7 @@ BOOL LLImageGL::updateBindStats(S32 tex_mem) const
 		{
 			// we haven't accounted for this texture yet this frame
 			sUniqueCount++;
-			updateBoundTexMem(tex_mem);
+			updateBoundTexMem(tex_mem, mComponents, mCategory);
 			mLastBindTime = sLastFrameTime;
 
 			return TRUE ;
@@ -525,6 +613,8 @@ void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_for
 	else
 		mFormatType = type_format;
 	mFormatSwapBytes = swap_bytes;
+
+	calcAlphaChannelOffsetAndStride() ;
 }
 
 //----------------------------------------------------------------------------
@@ -540,7 +630,6 @@ void LLImageGL::setImage(const LLImageRaw* imageraw)
 
 void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 {
-	llpushcallstacks ;
 	bool is_compressed = false;
 	if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
 	{
@@ -749,7 +838,6 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 	}
 	stop_glerror();
 	mGLTextureCreated = true;
-	llpushcallstacks ;
 }
 
 BOOL LLImageGL::preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image)
@@ -840,7 +928,6 @@ void LLImageGL::postAddToAtlas()
 
 BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update)
 {
-	llpushcallstacks ;
 	if (!width || !height)
 	{
 		return TRUE;
@@ -930,7 +1017,6 @@ BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S3
 		stop_glerror();
 		mGLTextureCreated = true;
 	}
-	llpushcallstacks ;
 	return TRUE;
 }
 
@@ -942,8 +1028,9 @@ BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S3
 // Copy sub image from frame buffer
 BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height)
 {
-	if (gGL.getTexUnit(0)->bind(this))
+	if (gGL.getTexUnit(0)->bind(this, false, true))
 	{
+		//checkTexSize() ;
 		glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
 		mGLTextureCreated = true;
 		stop_glerror();
@@ -1007,7 +1094,7 @@ BOOL LLImageGL::createGLTexture()
 	return TRUE ;
 }
 
-BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/)
+BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename/*=0*/, BOOL to_create, S32 category)
 {
 	if (gGLManager.mIsDisabled)
 	{
@@ -1027,8 +1114,10 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 	discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
 
 	// Actual image width/height = raw image width/height * 2^discard_level
-	S32 w = imageraw->getWidth() << discard_level;
-	S32 h = imageraw->getHeight() << discard_level;
+	S32 raw_w = imageraw->getWidth() ;
+	S32 raw_h = imageraw->getHeight() ;
+	S32 w = raw_w << discard_level;
+	S32 h = raw_h << discard_level;
 
 	// setSize may call destroyGLTexture if the size does not match
 	setSize(w, h, imageraw->getComponents());
@@ -1062,15 +1151,25 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S
 		  default:
 			llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
 		}
+
+		calcAlphaChannelOffsetAndStride() ;
 	}
 
+	if(!to_create) //not create a gl texture
+	{
+		destroyGLTexture();
+		mCurrentDiscardLevel = discard_level;	
+		mLastBindTime = sLastFrameTime;
+		return TRUE ;
+	}
+
+	setCategory(category) ;
  	const U8* rawdata = imageraw->getData();
 	return createGLTexture(discard_level, rawdata, FALSE, usename);
 }
 
 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
 {
-	llpushcallstacks ;
 	llassert(data_in);
 
 	if (discard_level < 0)
@@ -1137,11 +1236,14 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 	if (old_name != 0)
 	{
 		sGlobalTextureMemoryInBytes -= mTextureMemory;
-#if !LL_RELEASE_FOR_DOWNLOAD
-		decTextureCounter(mTextureMemory / mComponents) ;
-#endif
+
+		if(gAuditTexture)
+		{
+			decTextureCounter(mTextureMemory, mComponents, mCategory) ;
+		}
 
 		LLImageGL::deleteTextures(1, &old_name);
+
 		stop_glerror();
 	}
 
@@ -1149,82 +1251,20 @@ BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_
 	sGlobalTextureMemoryInBytes += mTextureMemory;
 	mTexelsInGLTexture = getWidth() * getHeight() ;
 
-#if !LL_RELEASE_FOR_DOWNLOAD
-	incTextureCounter(mTextureMemory / mComponents) ;
-#endif
-
+	if(gAuditTexture)
+	{
+		incTextureCounter(mTextureMemory, mComponents, mCategory) ;
+	}
 	// mark this as bound at this point, so we don't throw it out immediately
 	mLastBindTime = sLastFrameTime;
-
-	llpushcallstacks ;
 	return TRUE;
 }
 
-BOOL LLImageGL::setDiscardLevel(S32 discard_level)
-{
-	llassert(discard_level >= 0);
-	llassert(mCurrentDiscardLevel >= 0);
-
-	discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);	
-
-	if (discard_level == mCurrentDiscardLevel)
-	{
-		// nothing to do
-		return FALSE;
-	}
-	else if (discard_level < mCurrentDiscardLevel)
-	{
-		// larger image
-		dump();
-		llerrs << "LLImageGL::setDiscardLevel() called with larger discard level; use createGLTexture()" << llendl;
-		return FALSE;
-	}
-	else if (mUseMipMaps)
-	{
-		LLPointer<LLImageRaw> imageraw = new LLImageRaw;
-		while(discard_level > mCurrentDiscardLevel)
-		{
-			if (readBackRaw(discard_level, imageraw, false))
-			{
-				break;
-			}
-			discard_level--;
-		}
-		if (discard_level == mCurrentDiscardLevel)
-		{
-			// unable to increase the discard level
-			return FALSE;
-		}
-		return createGLTexture(discard_level, imageraw);
-	}
-	else
-	{
-#if !LL_LINUX && !LL_SOLARIS
-		 // *FIX: This should not be skipped for the linux client.
-		llerrs << "LLImageGL::setDiscardLevel() called on image without mipmaps" << llendl;
-#endif
-		return FALSE;
-	}
-}
-
-BOOL LLImageGL::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents)
-{
-	assert_glerror();
-	S32 gl_discard = discard_level - mCurrentDiscardLevel;
-	LLGLint glwidth = 0;
-	glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth);
-	LLGLint glheight = 0;
-	glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_HEIGHT, (GLint*)&glheight);
-	LLGLint glcomponents = 0 ;
-	glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_INTERNAL_FORMAT, (GLint*)&glcomponents);
-	assert_glerror();
-
-	return glwidth >= image_width && glheight >= image_height && (GL_RGB8 == glcomponents || GL_RGBA8 == glcomponents) ;
-}
-
 BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
 {
-	llpushcallstacks ;
+	llassert_always(sAllowReadBackRaw) ;
+	//llerrs << "should not call this function!" << llendl ;
+	
 	if (discard_level < 0)
 	{
 		discard_level = mCurrentDiscardLevel;
@@ -1327,7 +1367,7 @@ BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compre
 		return FALSE ;
 	}
 	//-----------------------------------------------------------------------------------------------
-	llpushcallstacks ;
+
 	return TRUE ;
 }
 
@@ -1345,25 +1385,26 @@ void LLImageGL::deleteDeadTextures()
 				stop_glerror();
 			}
 		}
-
+		
 		glDeleteTextures(1, &tex);
 		stop_glerror();
 	}
 }
-
+		
 void LLImageGL::destroyGLTexture()
 {
 	if (mTexName != 0)
 	{
 		if(mTextureMemory)
 		{
-#if !LL_RELEASE_FOR_DOWNLOAD
-			decTextureCounter(mTextureMemory / mComponents) ;
-#endif
+			if(gAuditTexture)
+			{
+				decTextureCounter(mTextureMemory, mComponents, mCategory) ;
+			}
 			sGlobalTextureMemoryInBytes -= mTextureMemory;
 			mTextureMemory = 0;
 		}
-
+		
 		LLImageGL::deleteTextures(1, &mTexName);			
 		mTexName = 0;
 		mCurrentDiscardLevel = -1 ; //invalidate mCurrentDiscardLevel.
@@ -1479,6 +1520,11 @@ S32 LLImageGL::getMipBytes(S32 discard_level) const
 	return res;
 }
 
+BOOL LLImageGL::isJustBound() const
+{
+	return (BOOL)(sLastFrameTime - mLastBindTime < 0.5f);
+}
+
 BOOL LLImageGL::getBoundRecently() const
 {
 	return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME);
@@ -1490,44 +1536,104 @@ void LLImageGL::setTarget(const LLGLenum target, const LLTexUnit::eTextureType b
 	mBindTarget = bind_target;
 }
 
-void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
+const S8 INVALID_OFFSET = -99 ;
+void LLImageGL::setNeedsAlphaAndPickMask(BOOL need_mask) 
 {
-	if(!mNeedsAlphaAndPickMask)
+	if(mNeedsAlphaAndPickMask != need_mask)
 	{
-		return ;
+		mNeedsAlphaAndPickMask = need_mask;
+
+		if(mNeedsAlphaAndPickMask)
+		{
+			mAlphaOffset = 0 ;
+		}
+		else //do not need alpha mask
+		{
+			mAlphaOffset = INVALID_OFFSET ;
+			mIsMask = FALSE;
+		}
 	}
+}
 
-	if (mFormatType != GL_UNSIGNED_BYTE)
+void LLImageGL::calcAlphaChannelOffsetAndStride()
+{
+	if(mAlphaOffset == INVALID_OFFSET)//do not need alpha mask
 	{
-		llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl;
+		return ;
 	}
 
-	U32 stride = 0;
+	mAlphaStride = -1 ;
 	switch (mFormatPrimary)
 	{
 	case GL_LUMINANCE:
 	case GL_ALPHA:
-		stride = 1;
+		mAlphaStride = 1;
 		break;
 	case GL_LUMINANCE_ALPHA:
-		stride = 2;
+		mAlphaStride = 2;
 		break;
 	case GL_RGB:
-		//no alpha
+		mNeedsAlphaAndPickMask = FALSE ;
 		mIsMask = FALSE;
-		return;
+		return ; //no alpha channel.
 	case GL_RGBA:
-		stride = 4;
+		mAlphaStride = 4;
 		break;
 	case GL_BGRA_EXT:
-		stride = 4;
+		mAlphaStride = 4;
 		break;
 	default:
-		return;
+		break;
+	}
+
+	mAlphaOffset = -1 ;
+	if (mFormatType == GL_UNSIGNED_BYTE)
+	{
+		mAlphaOffset = mAlphaStride - 1 ;
+	}
+	else if(is_little_endian())
+	{
+		if (mFormatType == GL_UNSIGNED_INT_8_8_8_8)
+		{
+			mAlphaOffset = 0 ;
+		}
+		else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV)
+		{
+			mAlphaOffset = 3 ;
+		}
+	}
+	else //big endian
+	{
+		if (mFormatType == GL_UNSIGNED_INT_8_8_8_8)
+		{
+			mAlphaOffset = 3 ;
+		}
+		else if (mFormatType == GL_UNSIGNED_INT_8_8_8_8_REV)
+		{
+			mAlphaOffset = 0 ;
+		}
+	}
+
+	if( mAlphaStride < 1 || //unsupported format
+		mAlphaOffset < 0 || //unsupported type
+		(mFormatPrimary == GL_BGRA_EXT && mFormatType != GL_UNSIGNED_BYTE)) //unknown situation
+	{
+		llwarns << "Cannot analyze alpha for image with format type " << std::hex << mFormatType << std::dec << llendl;
+
+		mNeedsAlphaAndPickMask = FALSE ;
+		mIsMask = FALSE;
+	}
+}
+
+void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
+{
+	if(!mNeedsAlphaAndPickMask)
+	{
+		return ;
 	}
 
 	U32 length = w * h;
-	const GLubyte* current = ((const GLubyte*) data_in)+stride-1;
+	const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset ;
 	
 	S32 sample[16];
 	memset(sample, 0, sizeof(S32)*16);
@@ -1535,7 +1641,7 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
 	for (U32 i = 0; i < length; i++)
 	{
 		++sample[*current/16];
-		current += stride;
+		current += mAlphaStride ;
 	}
 
 	U32 total = 0;
@@ -1638,8 +1744,30 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
 	return res;
 }
 
-//----------------------------------------------------------------------------
-#if !LL_RELEASE_FOR_DOWNLOAD
+void LLImageGL::setCategory(S32 category) 
+{
+	if(!gAuditTexture)
+	{
+		return ;
+	}
+	if(mCategory != category)
+	{		
+		if(mCategory > -1)
+		{
+			sTextureMemByCategory[mCategory] -= mTextureMemory ;
+		}
+		if(category > -1 && category < sMaxCatagories)
+		{
+			sTextureMemByCategory[category] += mTextureMemory ;		
+			mCategory = category;
+		}
+		else
+		{
+			mCategory = -1 ;
+		}
+	}
+}
+
 //for debug use 
 //val is a "power of two" number
 S32 LLImageGL::getTextureCounterIndex(U32 val) 
@@ -1663,18 +1791,33 @@ S32 LLImageGL::getTextureCounterIndex(U32 val)
 		return ret ;
 	}
 }
-void LLImageGL::incTextureCounter(U32 val) 
+
+//static
+void LLImageGL::incTextureCounter(U32 val, S32 ncomponents, S32 category) 
 {
 	sTextureLoadedCounter[getTextureCounterIndex(val)]++ ;
+	sTextureMemByCategory[category] += (S32)val * ncomponents ;
 }
-void LLImageGL::decTextureCounter(U32 val) 
+
+//static
+void LLImageGL::decTextureCounter(U32 val, S32 ncomponents, S32 category) 
 {
 	sTextureLoadedCounter[getTextureCounterIndex(val)]-- ;
+	sTextureMemByCategory[category] += (S32)val * ncomponents ;
 }
-void LLImageGL::setCurTexSizebar(S32 index)
+
+void LLImageGL::setCurTexSizebar(S32 index, BOOL set_pick_size)
 {
 	sCurTexSizeBar = index ;
-	sCurTexPickSize = (1 << index) ;
+
+	if(set_pick_size)
+	{
+		sCurTexPickSize = (1 << index) ;
+	}
+	else
+	{
+		sCurTexPickSize = -1 ;
+	}
 }
 void LLImageGL::resetCurTexSizebar()
 {
@@ -1682,7 +1825,9 @@ void LLImageGL::resetCurTexSizebar()
 	sCurTexPickSize = -1 ;
 }
 //----------------------------------------------------------------------------
-#endif
+
+//----------------------------------------------------------------------------
+
 
 // Manual Mip Generation
 /*
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index a094605607cef83ccaca0985cc3debe40ce9d5b9..937065043c1d5480a3bba1800d66587f912883d8 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -47,7 +47,6 @@ class LLTextureAtlas ;
 #define MEGA_BYTES_TO_BYTES(x) ((x) << 20)
 
 //============================================================================
-
 class LLImageGL : public LLRefCount
 {
 	friend class LLTexUnit;
@@ -63,6 +62,7 @@ class LLImageGL : public LLRefCount
 
 	BOOL updateBindStats(S32 tex_mem) const ;
 	F32 getTimePassedSinceLastBound();
+	void forceUpdateBindStats(void) const;
 
 	// needs to be called every frame
 	static void updateStats(F32 current_time);
@@ -71,8 +71,9 @@ class LLImageGL : public LLRefCount
 	static void destroyGL(BOOL save_state = TRUE);
 	static void restoreGL();
 
-	// Sometimes called externally for textures not using LLImageGL (should go away...)
-	static S32 updateBoundTexMem(const S32 delta);
+	// Sometimes called externally for textures not using LLImageGL (should go away...)	
+	static S32 updateBoundTexMem(const S32 mem, const S32 ncomponents, S32 category) ;
+	
 	static bool checkSize(S32 width, S32 height);
 
 	//for server side use only.
@@ -91,6 +92,7 @@ class LLImageGL : public LLRefCount
 	virtual ~LLImageGL();
 
 	void analyzeAlpha(const void* data_in, S32 w, S32 h);
+	void calcAlphaChannelOffsetAndStride();
 
 public:
 	virtual void dump();	// debugging info to llinfos
@@ -105,14 +107,15 @@ class LLImageGL : public LLRefCount
 	static void setManualImage(U32 target, S32 miplevel, S32 intformat, S32 width, S32 height, U32 pixformat, U32 pixtype, const void *pixels);
 
 	BOOL createGLTexture() ;
-	BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0);
+	BOOL createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, 
+		S32 category = sMaxCatagories - 1);
 	BOOL createGLTexture(S32 discard_level, const U8* data, BOOL data_hasmips = FALSE, S32 usename = 0);
 	void setImage(const LLImageRaw* imageraw);
 	void setImage(const U8* data_in, BOOL data_hasmips = FALSE);
 	BOOL setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE);
 	BOOL setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height, BOOL force_fast_update = FALSE);
 	BOOL setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height);
-	BOOL setDiscardLevel(S32 discard_level);
+	
 	// Read back a raw image for this discard level, if it exists
 	BOOL readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;
 	void destroyGLTexture();
@@ -131,6 +134,7 @@ class LLImageGL : public LLRefCount
 	S32  getBytes(S32 discard_level = -1) const;
 	S32  getMipBytes(S32 discard_level = -1) const;
 	BOOL getBoundRecently() const;
+	BOOL isJustBound() const;
 	LLGLenum getPrimaryFormat() const { return mFormatPrimary; }
 	LLGLenum getFormatType() const { return mFormatType; }
 
@@ -150,8 +154,6 @@ class LLImageGL : public LLRefCount
 	BOOL getUseMipMaps() const { return mUseMipMaps; }
 	void setUseMipMaps(BOOL usemips) { mUseMipMaps = usemips; }	
 
-	BOOL isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ;
-
 	void updatePickMask(S32 width, S32 height, const U8* data_in);
 	BOOL getMask(const LLVector2 &tc);
 
@@ -178,7 +180,7 @@ class LLImageGL : public LLRefCount
 	void init(BOOL usemipmaps);
 	virtual void cleanup(); // Clean up the LLImageGL so it can be reinitialized.  Be careful when using this in derived class destructors
 
-	void setNeedsAlphaAndPickMask(BOOL need_mask) {mNeedsAlphaAndPickMask = need_mask;}
+	void setNeedsAlphaAndPickMask(BOOL need_mask);
 
 	BOOL preAddToAtlas(S32 discard_level, const LLImageRaw* raw_image);
 	void postAddToAtlas() ;	
@@ -187,7 +189,7 @@ class LLImageGL : public LLRefCount
 	// Various GL/Rendering options
 	S32 mTextureMemory;
 	mutable F32  mLastBindTime;	// last time this was bound, by discard level
-
+	
 private:
 	LLPointer<LLImageRaw> mSaveData; // used for destroyGL/restoreGL
 	U8* mPickMask;  //downsampled bitmap approximation of alpha channel.  NULL if no alpha channel
@@ -197,13 +199,15 @@ class LLImageGL : public LLRefCount
 
 	BOOL mIsMask;
 	BOOL mNeedsAlphaAndPickMask;
-	
+	S8   mAlphaStride ;
+	S8   mAlphaOffset ;
+
 	bool     mGLTextureCreated ;
 	LLGLuint mTexName;
 	U16      mWidth;
 	U16      mHeight;	
 	S8       mCurrentDiscardLevel;
-
+	
 	S8       mDiscardLevelInAtlas;
 	U32      mTexelsInAtlas ;
 	U32      mTexelsInGLTexture;
@@ -233,7 +237,7 @@ class LLImageGL : public LLRefCount
 	static S32 sCount;
 	
 	static F32 sLastFrameTime;
-
+	
 	static LLGLuint sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS]; // Currently bound texture ID
 
 	// Global memory statistics
@@ -246,30 +250,61 @@ class LLImageGL : public LLRefCount
 	static LLImageGL* sDefaultGLTexture ;	
 	static BOOL sAutomatedTest;
 
-#if !LL_RELEASE_FOR_DOWNLOAD
+#if DEBUG_MISS
+	BOOL mMissed; // Missed on last bind?
+	BOOL getMissed() const { return mMissed; };
+#else
+	BOOL getMissed() const { return FALSE; };
+#endif
+
+public:
+	static void initClass(S32 num_catagories) ;
+	static void cleanupClass() ;
+private:
+	static S32 sMaxCatagories ;
+
+	//the flag to allow to call readBackRaw(...).
+	//can be removed if we do not use that function at all.
+	static BOOL sAllowReadBackRaw ;
+//
+//****************************************************************************************************
+//The below for texture auditing use only
+//****************************************************************************************************
+private:
+	S32 mCategory ;
+public:		
+	void setCategory(S32 category) ;
+	S32  getCategory()const {return mCategory ;}
+
 	//for debug use: show texture size distribution 
 	//----------------------------------------
-	static LLPointer<LLImageGL> sDefaultTexturep; //default texture to replace normal textures
+	static LLPointer<LLImageGL> sHighlightTexturep; //default texture to replace normal textures
 	static std::vector<S32> sTextureLoadedCounter ;
 	static std::vector<S32> sTextureBoundCounter ;
 	static std::vector<S32> sTextureCurBoundCounter ;
 	static S32 sCurTexSizeBar ;
 	static S32 sCurTexPickSize ;
-	
+
+	static void setHighlightTexture(S32 category) ;
 	static S32 getTextureCounterIndex(U32 val) ;
-	static void incTextureCounter(U32 val) ;
-	static void decTextureCounter(U32 val) ;
-	static void setCurTexSizebar(S32 index) ;
+	static void incTextureCounter(U32 val, S32 ncomponents, S32 category) ;
+	static void decTextureCounter(U32 val, S32 ncomponents, S32 category) ;
+	static void setCurTexSizebar(S32 index, BOOL set_pick_size = TRUE) ;
 	static void resetCurTexSizebar();
 	//----------------------------------------
-#endif
 
-#if DEBUG_MISS
-	BOOL mMissed; // Missed on last bind?
-	BOOL getMissed() const { return mMissed; };
-#else
-	BOOL getMissed() const { return FALSE; };
-#endif
+	//for debug use: show texture category distribution 
+	//----------------------------------------		
+	
+	static std::vector<S32> sTextureMemByCategory;
+	static std::vector<S32> sTextureMemByCategoryBound ;
+	static std::vector<S32> sTextureCurMemByCategoryBound ;
+	//----------------------------------------	
+//****************************************************************************************************
+//End of definitions for texture auditing use only
+//****************************************************************************************************
+
 };
 
+extern BOOL gAuditTexture;
 #endif // LL_LLIMAGEGL_H
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index b74d824c9e4ba83e2a4f5ae0602adf95416775d1..fc45df8153908e2fbe0c273d20d06541818b1138 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -179,7 +179,7 @@ void LLTexUnit::disable(void)
 	}
 }
 
-bool LLTexUnit::bind(LLTexture* texture, bool forceBind)
+bool LLTexUnit::bind(LLTexture* texture, bool for_rendering, bool forceBind)
 {
 	stop_glerror();
 	if (mIndex < 0) return false;
@@ -198,9 +198,19 @@ bool LLTexUnit::bind(LLTexture* texture, bool forceBind)
 		//if deleted, will re-generate it immediately
 		texture->forceImmediateUpdate() ;
 
+		gl_tex->forceUpdateBindStats() ;
 		return texture->bindDefaultImage(mIndex);
 	}
 
+	//in audit, replace the selected texture by the default one.
+	if(gAuditTexture && for_rendering && LLImageGL::sCurTexPickSize > 0)
+	{
+		if(texture->getWidth() * texture->getHeight() == LLImageGL::sCurTexPickSize)
+		{
+			gl_tex->updateBindStats(gl_tex->mTextureMemory);
+			return bind(LLImageGL::sHighlightTexturep.get());
+		}
+	}
 	if ((mCurrTexture != gl_tex->getTexName()) || forceBind)
 	{
 		activate();
@@ -223,7 +233,7 @@ bool LLTexUnit::bind(LLTexture* texture, bool forceBind)
 	return true;
 }
 
-bool LLTexUnit::bind(LLImageGL* texture, bool forceBind)
+bool LLTexUnit::bind(LLImageGL* texture, bool for_rendering, bool forceBind)
 {
 	stop_glerror();
 	if (mIndex < 0) return false;
@@ -260,6 +270,7 @@ bool LLTexUnit::bind(LLImageGL* texture, bool forceBind)
 			setTextureFilteringOption(texture->mFilterOption);
 		}
 	}
+
 	return true;
 }
 
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index cb2a4d445076c72ef746af12d682b68f9379c5c5..0121a190ee5d052b5ae3d6fe2d412c75eb56a15d 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -149,8 +149,8 @@ class LLTexUnit
 	
 	// Binds the LLImageGL to this texture unit 
 	// (automatically enables the unit for the LLImageGL's texture type)
-	bool bind(LLImageGL* texture, bool forceBind = false);
-	bool bind(LLTexture* texture, bool forceBind = false);
+	bool bind(LLImageGL* texture, bool for_rendering = false, bool forceBind = false);
+	bool bind(LLTexture* texture, bool for_rendering = false, bool forceBind = false);
 
 	// Binds a cubemap to this texture unit 
 	// (automatically enables the texture unit for cubemaps)
diff --git a/indra/llrender/lltexture.h b/indra/llrender/lltexture.h
index c18917b66346296b862584875fb58f9a34d1ccf8..6495fb9859dbd85b7ecfcd7654aa2dcef5955e01 100644
--- a/indra/llrender/lltexture.h
+++ b/indra/llrender/lltexture.h
@@ -61,7 +61,7 @@ class LLTexture : public LLRefCount
 	//
 	//interfaces to access LLViewerTexture
 	//
-	virtual bool       bindDefaultImage(const S32 stage = 0) const = 0 ;
+	virtual bool       bindDefaultImage(const S32 stage = 0) = 0 ;
 	virtual void       forceImmediateUpdate() = 0 ;
 	virtual void       setActive() = 0 ;
 	virtual S32	       getWidth(S32 discard_level = -1) const = 0 ;
diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp
index 704e1ab14274d0c51af38e375e3f59a9d404d863..e85cc437f40c83e6d1b494fcf5ce09a6f724bc86 100644
--- a/indra/llvfs/lllfsthread.cpp
+++ b/indra/llvfs/lllfsthread.cpp
@@ -189,7 +189,7 @@ bool LLLFSThread::Request::processRequest()
 	{
 		llassert(mOffset >= 0);
 		LLAPRFile infile ;
-		infile.open(mThread->getLocalAPRFilePool(), mFileName, LL_APR_RB);
+		infile.open(mFileName, LL_APR_RB, mThread->getLocalAPRFilePool());
 		if (!infile.getFileHandle())
 		{
 			llwarns << "LLLFS: Unable to read file: " << mFileName << llendl;
@@ -213,7 +213,7 @@ bool LLLFSThread::Request::processRequest()
 		if (mOffset < 0)
 			flags |= APR_APPEND;
 		LLAPRFile outfile ;
-		outfile.open(mThread->getLocalAPRFilePool(), mFileName, flags);
+		outfile.open(mFileName, flags, mThread->getLocalAPRFilePool());
 		if (!outfile.getFileHandle())
 		{
 			llwarns << "LLLFS: Unable to write file: " << mFileName << llendl;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index f27d949faf4a4e63ed1a8e5c11b8cc52aa422cb6..38622d206ffd0f2959e1a974a537edb9d0dcb409 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -265,7 +265,6 @@ set(viewer_SOURCE_FILES
     llmaniprotate.cpp
     llmanipscale.cpp
     llmaniptranslate.cpp
-    llmapresponders.cpp
     llmediactrl.cpp
     llmediadataclient.cpp
     llmediaremotectrl.cpp
@@ -387,6 +386,10 @@ set(viewer_SOURCE_FILES
     lltexturecache.cpp
     lltexturectrl.cpp
     lltexturefetch.cpp
+    lltextureinfo.cpp
+    lltextureinfodetails.cpp
+    lltexturestats.cpp
+    lltexturestatsuploader.cpp
     lltextureview.cpp
     lltoast.cpp
     lltoastalertpanel.cpp
@@ -508,6 +511,8 @@ set(viewer_SOURCE_FILES
     llwlparamset.cpp
     llworld.cpp
     llworldmap.cpp
+    llworldmapmessage.cpp
+    llworldmipmap.cpp
     llworldmapview.cpp
     llxmlrpctransaction.cpp
     noise.cpp
@@ -738,7 +743,6 @@ set(viewer_HEADER_FILES
     llmaniprotate.h
     llmanipscale.h
     llmaniptranslate.h
-    llmapresponders.h
     llmediadataclient.h
     llmediaremotectrl.h
     llmemoryview.h
@@ -859,6 +863,10 @@ set(viewer_HEADER_FILES
     lltexturecache.h
     lltexturectrl.h
     lltexturefetch.h
+    lltextureinfo.h
+    lltextureinfodetails.h
+    lltexturestats.h
+    lltexturestatsuploader.h
     lltextureview.h
     lltoast.h
     lltoastalertpanel.h
@@ -982,6 +990,8 @@ set(viewer_HEADER_FILES
     llwlparamset.h
     llworld.h
     llworldmap.h
+    llworldmapmessage.h
+    llworldmipmap.h
     llworldmapview.h
     llxmlrpctransaction.h
     macmain.h
@@ -1574,6 +1584,12 @@ LL_ADD_INTEGRATION_TEST(llcapabilitylistener
   )
 
 #ADD_VIEWER_BUILD_TEST(llmemoryview viewer)
+#ADD_VIEWER_BUILD_TEST(llagentaccess viewer)
+#ADD_VIEWER_BUILD_TEST(llworldmap viewer)
+#ADD_VIEWER_BUILD_TEST(llworldmipmap viewer)
+#ADD_VIEWER_BUILD_TEST(lltextureinfo viewer)
+#ADD_VIEWER_BUILD_TEST(lltextureinfodetails viewer)
+#ADD_VIEWER_BUILD_TEST(lltexturestatsuploader viewer)
 
 
 # Don't do these for DARWIN or LINUX here -- they're taken care of by viewer_manifest.py
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7e368b0c9c80308dfcfa1d6ea6b0d79c27963b14..aa43f8cd9cc4c5df28f154201cdaf14810df81f4 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -309,7 +309,18 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>AutoAcceptNewInventory</key>
+  <key>AuditTexture</key>
+  <map>
+    <key>Comment</key>
+    <string>Enable texture auditting.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+  <key>AutoAcceptNewInventory</key>
     <map>
       <key>Comment</key>
       <string>Automatically accept new notecards/textures/landmarks</string>
@@ -4545,6 +4556,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>MiniMapPrimMaxRadius</key>
+    <map>
+      <key>Comment</key>
+      <string>Radius of the largest prim to show on the MiniMap. Increasing beyond 256 may cause client lag.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>F32</string>
+      <key>Value</key>
+      <real>256.0</real>
+    </map>
     <key>MiniMapRotate</key>
     <map>
       <key>Comment</key>
@@ -4559,7 +4581,7 @@
     <key>MiniMapScale</key>
     <map>
       <key>Comment</key>
-      <string>Miniature world map zoom levle (pixels per region)</string>
+      <string>Miniature world map zoom level (pixels per region)</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -8468,6 +8490,28 @@
       <key>Value</key>
       <real>20.0</real>
     </map>
+    <key>TextureDisable</key>
+    <map>
+      <key>Comment</key>
+      <string>If TRUE, do not load textures for in-world content</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>TextureLoadFullRes</key>
+    <map>
+      <key>Comment</key>
+      <string>If TRUE, always load textures at full resolution (discard = 0)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>TextureMemory</key>
     <map>
       <key>Comment</key>
@@ -10537,5 +10581,38 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-  </map>
+    <key>LogTextureDownloadsToViewerLog</key>
+    <map>
+      <key>Comment</key>
+      <string>Send texture download details to the viewer log</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>LogTextureDownloadsToSimulator</key>
+    <map>
+      <key>Comment</key>
+      <string>Send a digest of texture info to the sim</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
+    <key>TextureLoggingThreshold</key>
+    <map>
+      <key>Comment</key>
+      <string>Specifies the byte threshold at which texture download data should be sent to the sim.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>U32</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+</map>
 </llsd>
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 0fa3b1f04df573a0dc1997ba326f5b35ea923ea4..e182228ab3b819f7b31b03e6f8b84ea0720cd712 100644
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -74,6 +74,8 @@
 #include "llstatusbar.h"
 #include "llteleportflags.h"
 #include "llteleporthistory.h"
+#include "lltexturestats.h"
+#include "lltexturestats.h"
 #include "lltool.h"
 #include "lltoolcomp.h"
 #include "lltoolmgr.h"
@@ -6087,17 +6089,16 @@ void LLAgent::teleportCancel()
 void LLAgent::teleportViaLocation(const LLVector3d& pos_global)
 {
 	LLViewerRegion* regionp = getRegion();
-	LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
+	U64 handle = to_region_handle(pos_global);
+	LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
 	if(regionp && info)
 	{
-		U32 x_pos;
-		U32 y_pos;
-		from_region_handle(info->mHandle, &x_pos, &y_pos);
+		LLVector3d region_origin = info->getGlobalOrigin();
 		LLVector3 pos_local(
-			(F32)(pos_global.mdV[VX] - x_pos),
-			(F32)(pos_global.mdV[VY] - y_pos),
+			(F32)(pos_global.mdV[VX] - region_origin.mdV[VX]),
+			(F32)(pos_global.mdV[VY] - region_origin.mdV[VY]),
 			(F32)(pos_global.mdV[VZ]));
-		teleportRequest(info->mHandle, pos_local);
+		teleportRequest(handle, pos_local);
 	}
 	else if(regionp && 
 		teleportCore(regionp->getHandle() == to_region_handle_global((F32)pos_global.mdV[VX], (F32)pos_global.mdV[VY])))
@@ -6514,3 +6515,4 @@ LLAgentQueryManager::~LLAgentQueryManager()
 }
 
 // EOF
+
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index c673db2034f4c67b151d072a8dc60e01d0f9517d..87d081b27c78397d9384ea835c25394e392afd1b 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -58,6 +58,8 @@
 #include "llallocator.h"
 #include "llares.h" 
 #include "llcurl.h"
+#include "lltexturestats.h"
+#include "lltexturestats.h"
 #include "llviewerwindow.h"
 #include "llviewerdisplay.h"
 #include "llviewermedia.h"
@@ -248,9 +250,6 @@ F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
 
 BOOL				gDisconnected = FALSE;
 
-// Map scale in pixels per region
-F32 				gMapScale = 128.f;
-
 // used to restore texture state after a mode switch
 LLFrameTimer	gRestoreGLTimer;
 BOOL			gRestoreGL = FALSE;
@@ -413,7 +412,7 @@ static void settings_to_globals()
 	gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
 	gAllowTapTapHoldRun = gSavedSettings.getBOOL("AllowTapTapHoldRun");
 	gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
-	gMapScale = gSavedSettings.getF32("MapScale");
+	LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale");
 
 	LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
 }
@@ -426,7 +425,7 @@ static void settings_modify()
 	LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
 	gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
 	gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
-	
+	gAuditTexture = gSavedSettings.getBOOL("AuditTexture");
 #if LL_VECTORIZE
 	if (gSysCPU.hasAltivec())
 	{
@@ -547,7 +546,7 @@ LLAppViewer* LLAppViewer::sInstance = NULL;
 const std::string LLAppViewer::sGlobalSettingsName = "Global"; 
 
 LLTextureCache* LLAppViewer::sTextureCache = NULL; 
-LLWorkerThread* LLAppViewer::sImageDecodeThread = NULL; 
+LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL; 
 LLTextureFetch* LLAppViewer::sTextureFetch = NULL; 
 
 LLAppViewer::LLAppViewer() : 
@@ -639,6 +638,9 @@ bool LLAppViewer::init()
 	//////////////////////////////////////////////////////////////////////////////
 	// *FIX: The following code isn't grouped into functions yet.
 
+	// Statistics / debug timer initialization
+	init_statistics();
+	
 	//
 	// Various introspection concerning the libs we're using - particularly
         // the libs involved in getting to a full login screen.
@@ -1596,14 +1598,14 @@ bool LLAppViewer::initThreads()
 		LLWatchdog::getInstance()->init(watchdog_killer_callback);
 	}
 
-	LLVFSThread::initClass(enable_threads && true);
-	LLLFSThread::initClass(enable_threads && true);
+	LLVFSThread::initClass(enable_threads && false);
+	LLLFSThread::initClass(enable_threads && false);
 
 	// Image decoding
-	LLAppViewer::sImageDecodeThread = new LLWorkerThread("ImageDecode", enable_threads && true);
+	LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
 	LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
-	LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), enable_threads && false);
-	LLImage::initClass(LLAppViewer::getImageDecodeThread());
+	LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(), sImageDecodeThread, enable_threads && true);
+	LLImage::initClass();
 
 	if (LLFastTimer::sLog || LLFastTimer::sMetricLog)
 	{
@@ -2397,7 +2399,7 @@ void LLAppViewer::cleanupSavedSettings()
 		}
 	}
 
-	gSavedSettings.setF32("MapScale", gMapScale );
+	gSavedSettings.setF32("MapScale", LLWorldMapView::sMapScale );
 
 	// Some things are cached in LLAgent.
 	if (gAgent.mInitialized)
@@ -2723,7 +2725,7 @@ void LLAppViewer::initMarkerFile()
 	
 	// Create the marker file for this execution & lock it
 	apr_status_t s;
-	s = mMarkerFile.open(mMarkerFileName, LL_APR_W, gAPRPoolp);	
+	s = mMarkerFile.open(mMarkerFileName, LL_APR_W, TRUE);	
 
 	if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
 	{
@@ -4109,3 +4111,4 @@ void LLAppViewer::handleLoginComplete()
 
 	writeDebugInfo();
 }
+
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index 646b67726497c98d5f3e28a618fb12228436f51e..d07ee6e94fffa6095d93347f7c91b9847ece5e70 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -41,12 +41,10 @@ class LLCommandLineParser;
 class LLFrameTimer;
 class LLPumpIO;
 class LLTextureCache;
+class LLImageDecodeThread;
 class LLTextureFetch;
-class LLTimer;
-class LLVFS;
 class LLWatchdogTimeout;
-class LLWorkerThread;
-
+class LLCommandLineParser;
 
 class LLAppViewer : public LLApp
 {
@@ -98,7 +96,7 @@ class LLAppViewer : public LLApp
     
 	// Thread accessors
 	static LLTextureCache* getTextureCache() { return sTextureCache; }
-	static LLWorkerThread* getImageDecodeThread() { return sImageDecodeThread; }
+	static LLImageDecodeThread* getImageDecodeThread() { return sImageDecodeThread; }
 	static LLTextureFetch* getTextureFetch() { return sTextureFetch; }
 
 	const std::string& getSerialNumber() { return mSerialNumber; }
@@ -228,7 +226,7 @@ class LLAppViewer : public LLApp
 
 	// Thread objects.
 	static LLTextureCache* sTextureCache; 
-	static LLWorkerThread* sImageDecodeThread; 
+	static LLImageDecodeThread* sImageDecodeThread; 
 	static LLTextureFetch* sTextureFetch;
 
 	S32 mNumSessions;
@@ -322,9 +320,6 @@ extern F32 gSimFrames;
 
 extern BOOL		gDisconnected;
 
-// Map scale in pixels per region
-extern F32 gMapScale;
-
 extern LLFrameTimer	gRestoreGLTimer;
 extern BOOL			gRestoreGL;
 extern BOOL		gUseWireframe;
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index ea3809d58d6839a8621be1bb340330e0a8940918..f117e7d975bc66d7a95be397ed05f01daf9094f6 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -368,7 +368,7 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
 	std::string result = content["state"];
 	LLUUID new_id = content["new_asset"];
 
-	llinfos << "LLSendTexLayerResponder::result from capabilities: " << result << llendl;
+	llinfos << "result: " << result << "new_id:" << new_id << llendl;
 	if (result == "complete"
 		&& mBakedUploadData != NULL)
 	{	// Invoke 
@@ -382,6 +382,14 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
 	}
 }
 
+void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason)
+{
+	llinfos << "status: " << statusNum << " reason: " << reason << llendl;
+	
+	// Invoke the original callback with an error result
+	LLTexLayerSetBuffer::onTextureUploadComplete(LLUUID(), (void*) mBakedUploadData, -1, LL_EXSTAT_NONE);
+	mBakedUploadData = NULL;	// deleted in onTextureUploadComplete()
+}
 
 LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data,
 																 const LLUUID& vfile_id,
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
index a08d70213c3f8d5f6eb6e5a6c31837cee0c0873e..e656351305639603b4800fd8b96cd901b919866c 100644
--- a/indra/newview/llassetuploadresponders.h
+++ b/indra/newview/llassetuploadresponders.h
@@ -84,6 +84,7 @@ class LLSendTexLayerResponder : public LLAssetUploadResponder
 	~LLSendTexLayerResponder();
 
 	virtual void uploadComplete(const LLSD& content);
+	virtual void error(U32 statusNum, const std::string& reason);
 
 	LLBakedUploadData * mBakedUploadData;
 };
diff --git a/indra/newview/llcolorswatch.cpp b/indra/newview/llcolorswatch.cpp
index 7b75c77a1e35577680c07e2641b34bcbea91edeb..5d27595a5933d828d567ed74e8723d3f37b1fff6 100644
--- a/indra/newview/llcolorswatch.cpp
+++ b/indra/newview/llcolorswatch.cpp
@@ -228,7 +228,7 @@ void LLColorSwatchCtrl::draw()
 	{
 		if (!mFallbackImageName.empty())
 		{
-			LLPointer<LLViewerTexture> fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+			LLPointer<LLViewerFetchedTexture> fallback_image = LLViewerTextureManager::getFetchedTextureFromFile(mFallbackImageName, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
 			if( fallback_image->getComponents() == 4 )
 			{	
 				gl_rect_2d_checkerboard( interior );
diff --git a/indra/newview/lldebugview.cpp b/indra/newview/lldebugview.cpp
index 24a57cb0c1b27725652a549a18e2af790b02b089..9057d84f63c9a44464a9e80f62f18e0ee0f0559b 100644
--- a/indra/newview/lldebugview.cpp
+++ b/indra/newview/lldebugview.cpp
@@ -45,7 +45,7 @@
 #include "llviewerwindow.h"
 #include "llappviewer.h"
 #include "llmemoryview.h"
-
+#include "llviewertexture.h"
 //
 // Globals
 //
@@ -102,17 +102,29 @@ LLDebugView::LLDebugView(const LLDebugView::Params& p)
 	gTextureView = LLUICtrlFactory::create<LLTextureView>(tvp);
 	addChild(gTextureView);
 	//gTextureView->reshape(r.getWidth(), r.getHeight(), TRUE);
-#if !LL_RELEASE_FOR_DOWNLOAD
-	r.set(150, rect.getHeight() - 50, 900 + LLImageGL::sTextureLoadedCounter.size() * 30, 100);
-	LLTextureSizeView::Params tsvp;
-	tsvp.name("gTextureSizeView");
-	tsvp.rect(r);
-	tsvp.follows.flags(FOLLOWS_BOTTOM|FOLLOWS_LEFT);
-	tsvp.visible(false);
-	gTextureSizeView = LLUICtrlFactory::create<LLTextureSizeView>(tsvp);
-	addChild(gTextureSizeView);
-#endif
 
+	if(gAuditTexture)
+	{
+		r.set(150, rect.getHeight() - 50, 900 + LLImageGL::sTextureLoadedCounter.size() * 30, 100);
+		LLTextureSizeView::Params tsv ;
+		tsv.name("gTextureSizeView");
+		tsv.rect(r);
+		tsv.follows.flags(FOLLOWS_BOTTOM|FOLLOWS_LEFT);
+		tsv.visible(false);
+		gTextureSizeView = LLUICtrlFactory::create<LLTextureSizeView>(tsv);
+		addChild(gTextureSizeView);
+		gTextureSizeView->setType(LLTextureSizeView::TEXTURE_MEM_OVER_SIZE) ;
+
+		r.set(150, rect.getHeight() - 50, 900 + LLViewerTexture::getTotalNumOfCategories() * 30, 100);
+		LLTextureSizeView::Params tcv ;
+		tcv.name("gTextureCategoryView");
+		tcv.rect(r);
+		tcv.follows.flags(FOLLOWS_BOTTOM|FOLLOWS_LEFT);
+		tcv.visible(false);
+		gTextureCategoryView = LLUICtrlFactory::create<LLTextureSizeView>(tcv);
+		gTextureCategoryView->setType(LLTextureSizeView::TEXTURE_MEM_OVER_CATEGORY);
+		addChild(gTextureCategoryView);
+	}
 }
 
 
@@ -122,5 +134,6 @@ LLDebugView::~LLDebugView()
 	gDebugView = NULL;
 	gTextureView = NULL;
 	gTextureSizeView = NULL;
+	gTextureCategoryView = NULL;
 }
 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 069155c25590b2c208b7eeaa2e71a339087cbd48..03a3f2b43de2434606adc8c2e7d16d4cb1b127d6 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -105,7 +105,7 @@ void LLDrawable::init()
 	mVObjp   = NULL;
 	// mFaces
 	mSpatialGroupp = NULL;
-	mVisible = 0;
+	mVisible = sCurVisible - 2;//invisible for the current frame and the last frame.
 	mRadius = 0.f;
 	
 	mGeneration = -1;
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 976f02eeb7f8262b90ebbab32362a1ad59bcf876..1b46e0a4787ec20632055cb786fee8ed6e5b0e62 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -279,7 +279,7 @@ S32 LLFacePool::drawLoopSetTex(face_array_t& face_list, S32 stage)
 			 iter != face_list.end(); iter++)
 		{
 			LLFace *facep = *iter;
-			gGL.getTexUnit(stage)->bind(facep->getTexture());
+			gGL.getTexUnit(stage)->bind(facep->getTexture(), TRUE) ;
 			gGL.getTexUnit(0)->activate();
 			res += facep->renderIndexed();
 		}
@@ -474,17 +474,13 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 	{
 		if (params.mTexture.notNull())
 		{
-			gGL.getTexUnit(0)->bind(params.mTexture.get());
+			gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ;
 			if (params.mTextureMatrix)
 			{
 				glMatrixMode(GL_TEXTURE);
 				glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
 				gPipeline.mTextureMatrixOps++;
 			}
-			if(params.mTexture.notNull())//will be removed.
-			{
-				params.mTexture->addTextureStats(params.mVSize);
-			}
 		}
 		else
 		{
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index a5a29dea7b2200d412f474e2d08223816fee440c..6d7736141494967cfee8e6aa2aab8f54e5aad250 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -219,7 +219,7 @@ void LLDrawPoolAlpha::render(S32 pass)
 		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
 		glColor4f(1,0,0,1);
 		LLViewerFetchedTexture::sSmokeImagep->addTextureStats(1024.f*1024.f);
-		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep) ;
+		gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sSmokeImagep, TRUE) ;
 		renderAlphaHighlight(LLVertexBuffer::MAP_VERTEX |
 							LLVertexBuffer::MAP_TEXCOORD0);
 	}
diff --git a/indra/newview/lldrawpooltree.cpp b/indra/newview/lldrawpooltree.cpp
index 8d2cbc583c1df113161898aecc85adc49a3b0086..5521fb05a82fcf7b87ae500afca251e2b7105bb7 100644
--- a/indra/newview/lldrawpooltree.cpp
+++ b/indra/newview/lldrawpooltree.cpp
@@ -253,7 +253,7 @@ void LLDrawPoolTree::renderTree(BOOL selecting)
 	LLGLState normalize(GL_NORMALIZE, TRUE);
 	
 	// Bind the texture for this tree.
-	gGL.getTexUnit(sDiffTex)->bind(mTexturep.get());
+	gGL.getTexUnit(sDiffTex)->bind(mTexturep.get(), TRUE);
 		
 	U32 indices_drawn = 0;
 
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index 0bb5edf3f995ae9b9a0e1b0ceecd4a807d7abf54..e41c4104ebe4000b92ff1c6bcf210d57808872f3 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -104,7 +104,7 @@ void LLViewerDynamicTexture::generateGLTexture(LLGLint internal_format, LLGLenum
 	{
 		setExplicitFormat(internal_format, primary_format, type_format, swap_bytes);
 	}
-	createGLTexture(0, raw_image);
+	createGLTexture(0, raw_image, 0, TRUE, LLViewerTexture::DYNAMIC_TEX);
 	setAddressMode((mClamp) ? LLTexUnit::TAM_CLAMP : LLTexUnit::TAM_WRAP);
 	mGLTexturep->setGLTextureCreated(false);
 }
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 4246cbc27f24d4322154878239318554513e0e96..edadc3dcf777d68fd9a25dbc0e402fbc7bd4638c 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -52,6 +52,7 @@
 #include "llvovolume.h"
 #include "pipeline.h"
 #include "llviewerregion.h"
+#include "llviewerwindow.h"
 
 #define LL_MAX_INDICES_COUNT 1000000
 
@@ -175,6 +176,9 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	mLastIndicesCount = mIndicesCount;
 	mLastIndicesIndex = mIndicesIndex;
 
+	mImportanceToCamera = 0.f ;
+	mBoundingSphereRadius = 0.0f ;
+
 	mAtlasInfop = NULL ;
 	mUsingAtlas  = FALSE ;
 }
@@ -186,6 +190,7 @@ void LLFace::destroy()
 	{
 		mTexture->removeFace(this) ;
 	}
+	
 	if (mDrawPoolp)
 	{
 		mDrawPoolp->removeFace(this);
@@ -207,7 +212,7 @@ void LLFace::destroy()
 			}
 		}
 	}
-
+	
 	setDrawInfo(NULL);
 	
 	removeAtlas();
@@ -256,6 +261,7 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep)
 		}
 		mDrawPoolp = new_pool;
 	}
+	
 	setTexture(texturep) ;
 }
 
@@ -750,7 +756,9 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 		}
 
 		mCenterLocal = (newMin+newMax)*0.5f;
-		
+		LLVector3 tmp = (newMin - newMax) ;
+		mBoundingSphereRadius = tmp.length() * 0.5f ;
+
 		updateCenterAgent();
 	}
 
@@ -1305,6 +1313,151 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	return TRUE;
 }
 
+const F32 LEAST_IMPORTANCE = 0.05f ;
+const F32 LEAST_IMPORTANCE_FOR_LARGE_IMAGE = 0.3f ;
+
+F32 LLFace::getTextureVirtualSize()
+{
+	F32 radius;
+	F32 cos_angle_to_view_dir;
+	mPixelArea = calcPixelArea(cos_angle_to_view_dir, radius);
+
+	if (mPixelArea <= 0)
+	{
+		return 0.f;
+	}
+
+	//get area of circle in texture space
+	LLVector2 tdim = mTexExtents[1] - mTexExtents[0];
+	F32 texel_area = (tdim * 0.5f).lengthSquared()*3.14159f;
+	if (texel_area <= 0)
+	{
+		// Probably animated, use default
+		texel_area = 1.f;
+	}
+
+	//apply texel area to face area to get accurate ratio
+	//face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
+	F32 face_area = mPixelArea / llclamp(texel_area, 0.015625f, 128.f);
+
+	if(face_area > LLViewerTexture::sMaxSmallImageSize)
+	{
+		if(mImportanceToCamera < LEAST_IMPORTANCE) //if the face is not important, do not load hi-res.
+		{
+			static const F32 MAX_LEAST_IMPORTANCE_IMAGE_SIZE = 128.0f * 128.0f ;
+			face_area = llmin(face_area * 0.5f, MAX_LEAST_IMPORTANCE_IMAGE_SIZE) ;
+		}
+		else if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
+		{
+			if(mImportanceToCamera < LEAST_IMPORTANCE_FOR_LARGE_IMAGE)//if the face is not important, do not load hi-res.
+			{
+				face_area = LLViewerTexture::sMinLargeImageSize ;
+			}	
+			else if(mTexture.notNull() && mTexture->isLargeImage())
+			{		
+				face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius );
+			}			
+		}
+	}
+
+	return face_area;
+}
+
+F32 LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
+{
+	//get area of circle around face
+	LLVector3 center = getPositionAgent();
+	LLVector3 size = (mExtents[1] - mExtents[0]) * 0.5f;
+	
+	LLVector3 lookAt = center - LLViewerCamera::getInstance()->getOrigin();
+	F32 dist = lookAt.normVec() ;
+
+	//get area of circle around node
+	F32 app_angle = atanf(size.length()/dist);
+	radius = app_angle*LLDrawable::sCurPixelAngle;
+	F32 face_area = radius*radius * 3.14159f;
+
+	if(dist < mBoundingSphereRadius) //camera is very close
+	{
+		cos_angle_to_view_dir = 1.0f ;
+		mImportanceToCamera = 1.0f ;
+	}
+	else
+	{
+		cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ;	
+		mImportanceToCamera = LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist) ;
+	}
+
+	return face_area ;
+}
+
+//the projection of the face partially overlaps with the screen
+F32 LLFace::adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius )
+{
+	F32 screen_radius = (F32)llmax(gViewerWindow->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight()) ;
+	F32 center_angle = acosf(cos_angle_to_view_dir) ;
+	F32 d = center_angle * LLDrawable::sCurPixelAngle ;
+
+	if(d + radius > screen_radius + 5.f)
+	{
+		//----------------------------------------------
+		//calculate the intersection area of two circles
+		//F32 radius_square = radius * radius ;
+		//F32 d_square = d * d ;
+		//F32 screen_radius_square = screen_radius * screen_radius ;
+		//face_area = 
+		//	radius_square * acosf((d_square + radius_square - screen_radius_square)/(2 * d * radius)) +
+		//	screen_radius_square * acosf((d_square + screen_radius_square - radius_square)/(2 * d * screen_radius)) -
+		//	0.5f * sqrtf((-d + radius + screen_radius) * (d + radius - screen_radius) * (d - radius + screen_radius) * (d + radius + screen_radius)) ;			
+		//----------------------------------------------
+
+		//the above calculation is too expensive
+		//the below is a good estimation: bounding box of the bounding sphere:
+		F32 alpha = 0.5f * (radius + screen_radius - d) / radius ;
+		alpha = llclamp(alpha, 0.f, 1.f) ;
+		return alpha * alpha ;
+	}
+	return 1.0f ;
+}
+
+const S8 FACE_IMPORTANCE_LEVEL = 4 ;
+const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL][2] = //{distance, importance_weight}
+	{{16.1f, 1.0f}, {32.1f, 0.5f}, {48.1f, 0.2f}, {96.1f, 0.05f} } ;
+const F32 FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[FACE_IMPORTANCE_LEVEL][2] =    //{cos(angle), importance_weight}
+	{{0.985f /*cos(10 degrees)*/, 1.0f}, {0.94f /*cos(20 degrees)*/, 0.8f}, {0.866f /*cos(30 degrees)*/, 0.64f}, {0.0f, 0.36f}} ;
+
+//static 
+F32 LLFace::calcImportanceToCamera(F32 cos_angle_to_view_dir, F32 dist)
+{
+	F32 importance = 0.f ;
+	
+	if(cos_angle_to_view_dir > LLViewerCamera::getInstance()->getCosHalfFov() && 
+		dist < FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[FACE_IMPORTANCE_LEVEL - 1][0]) 
+	{
+		F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ;
+		F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed();
+
+		if(camera_moving_speed > 10.0f || camera_angular_speed > 1.0f)
+		{
+			//if camera moves or rotates too fast, ignore the importance factor
+			return 0.f ;
+		}
+		
+		//F32 camera_relative_speed = camera_moving_speed * (lookAt * LLViewerCamera::getInstance()->getVelocityDir()) ;
+		
+		S32 i = 0 ;
+		for(i = 0; i < FACE_IMPORTANCE_LEVEL && dist > FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][0]; ++i);
+		i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ;
+		F32 dist_factor = FACE_IMPORTANCE_TO_CAMERA_OVER_DISTANCE[i][1] ;
+		
+		for(i = 0; i < FACE_IMPORTANCE_LEVEL && cos_angle_to_view_dir < FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][0] ; ++i) ;
+		i = llmin(i, FACE_IMPORTANCE_LEVEL - 1) ;
+		importance = dist_factor * FACE_IMPORTANCE_TO_CAMERA_OVER_ANGLE[i][1] ;
+	}
+
+	return importance ;
+}
+
 BOOL LLFace::verify(const U32* indices_array) const
 {
 	BOOL ok = TRUE;
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index d734b327d95f86c7e90b69c573da4f82101d67ea..68eee061b8bafcfa0d0ba8b891367186a516e891 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -188,6 +188,9 @@ class LLFace
 	void		setIndicesIndex(S32 idx) { mIndicesIndex = idx; }
 	void		setDrawInfo(LLDrawInfo* draw_info);
 
+	F32         getTextureVirtualSize() ;
+	F32         getImportanceToCamera()const {return mImportanceToCamera ;}
+
 	//for atlas
 	LLTextureAtlasSlot*   getAtlasInfo() ;
 	void                  setAtlasInUse(BOOL flag);
@@ -200,6 +203,12 @@ class LLFace
 	void                  removeAtlas() ;
 	BOOL                  switchTexture() ;
 
+private:	
+	F32         adjustPartialOverlapPixelArea(F32 cos_angle_to_view_dir, F32 radius );
+	F32         calcPixelArea(F32& cos_angle_to_view_dir, F32& radius) ;
+public:
+	static F32  calcImportanceToCamera(F32 to_view_dir, F32 dist);
+
 public:
 	
 	LLVector3		mCenterLocal;
@@ -214,7 +223,7 @@ class LLFace
 	LLMatrix4*	mTextureMatrix;
 	LLDrawInfo* mDrawInfo;
 
-protected:
+private:
 	friend class LLGeometryManager;
 	friend class LLVolumeGeometryManager;
 
@@ -244,9 +253,16 @@ class LLFace
 	F32			mVSize;
 	F32			mPixelArea;
 
+	//importance factor, in the range [0, 1.0].
+	//1.0: the most important.
+	//based on the distance from the face to the view point and the angle from the face center to the view direction.
+	F32         mImportanceToCamera ; 
+	F32         mBoundingSphereRadius ;
+
+
 	//atlas
 	LLPointer<LLTextureAtlasSlot> mAtlasInfop ;
-	BOOL                              mUsingAtlas ;
+	BOOL                          mUsingAtlas ;
 	
 protected:
 	static BOOL	sSafeRenderSelect;
diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp
index 0c9a759f32036b3db475c2b604e6137426cd5679..3fe711a1664d4f1c972271a7755b33033cfe7afe 100644
--- a/indra/newview/llfloatermap.cpp
+++ b/indra/newview/llfloatermap.cpp
@@ -50,12 +50,27 @@
 #include "lltextbox.h"
 #include "llviewermenu.h"
 
+//
+// Constants
+//
+const F32 MAP_MINOR_DIR_THRESHOLD = 0.08f;
+
 //
 // Member functions
 //
 
 LLFloaterMap::LLFloaterMap(const LLSD& key) 
-	: LLFloater(key)
+	: LLFloater(key),
+	  mPopupMenu(NULL),
+	  mTextBoxEast(NULL),
+	  mTextBoxNorth(NULL),
+	  mTextBoxWest(NULL),
+	  mTextBoxSouth(NULL),
+	  mTextBoxSouthEast(NULL),
+	  mTextBoxNorthEast(NULL),
+	  mTextBoxNorthWest(NULL),
+	  mTextBoxSouthWest(NULL),
+	  mMap(NULL)
 {
 	//Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_map.xml", FALSE);
 }
@@ -92,6 +107,8 @@ BOOL LLFloaterMap::postBuild()
 		mPopupMenu->setItemEnabled ("Stop Tracking", false);
 	}
 
+	updateMinorDirections();
+
 	// Get the drag handle all the way in back
 	sendChildToBack(getDragHandle());
 
@@ -139,6 +156,23 @@ void LLFloaterMap::setDirectionPos( LLTextBox* text_box, F32 rotation )
 		llround(map_half_height - text_half_height + radius * sin( rotation )) );
 }
 
+void LLFloaterMap::updateMinorDirections()
+{
+	if (mTextBoxNorthEast == NULL)
+	{
+		return;
+	}
+
+	// Hide minor directions if they cover too much of the map
+	bool show_minors = mTextBoxNorthEast->getRect().getHeight() < MAP_MINOR_DIR_THRESHOLD *
+		llmin(getRect().getWidth(), getRect().getHeight());
+
+	mTextBoxNorthEast->setVisible(show_minors);
+	mTextBoxNorthWest->setVisible(show_minors);
+	mTextBoxSouthWest->setVisible(show_minors);
+	mTextBoxSouthEast->setVisible(show_minors);
+}
+
 // virtual
 void LLFloaterMap::draw()
 {
@@ -180,17 +214,23 @@ void LLFloaterMap::draw()
 	LLFloater::draw();
 }
 
+void LLFloaterMap::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+	LLFloater::reshape(width, height, called_from_parent);
+	updateMinorDirections();
+}
+
 void LLFloaterMap::handleZoom(const LLSD& userdata)
 {
 	std::string level = userdata.asString();
 	
 	F32 scale = 0.0f;
 	if (level == std::string("close"))
-		scale = MAP_SCALE_MAX;
+		scale = LLNetMap::MAP_SCALE_MAX;
 	else if (level == std::string("medium"))
-		scale = MAP_SCALE_MID;
+		scale = LLNetMap::MAP_SCALE_MID;
 	else if (level == std::string("far"))
-		scale = MAP_SCALE_MIN;
+		scale = LLNetMap::MAP_SCALE_MIN;
 	if (scale != 0.0f)
 	{
 		gSavedSettings.setF32("MiniMapScale", scale );
diff --git a/indra/newview/llfloatermap.h b/indra/newview/llfloatermap.h
index 501777ed0787fec381509c344931e6c6100ee286..6c9138c6a7ee99bb4d3c2e6e087ee0460b920833 100644
--- a/indra/newview/llfloatermap.h
+++ b/indra/newview/llfloatermap.h
@@ -51,12 +51,14 @@ class LLFloaterMap : public LLFloater
 	/*virtual*/ BOOL 	postBuild();
 	/*virtual*/ BOOL	handleDoubleClick( S32 x, S32 y, MASK mask );
 	/*virtual*/ BOOL	handleRightMouseDown( S32 x, S32 y, MASK mask );
+	/*virtual*/ void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 	/*virtual*/ void	draw();
 	
 private:
 	void handleZoom(const LLSD& userdata);
 	void handleStopTracking (const LLSD& userdata);
 	void setDirectionPos( LLTextBox* text_box, F32 rotation );
+	void updateMinorDirections();
 	
 	LLMenuGL*		mPopupMenu;
 
diff --git a/indra/newview/llfloaterreporter.cpp b/indra/newview/llfloaterreporter.cpp
index b146ed9b389ec19889234785718a9caacfc300d3..8e5a76bfae5d3de5401f86d0765d55fa659fff9a 100644
--- a/indra/newview/llfloaterreporter.cpp
+++ b/indra/newview/llfloaterreporter.cpp
@@ -790,7 +790,7 @@ void LLFloaterReporter::takeScreenshot()
 	// store in the image list so it doesn't try to fetch from the server
 	LLPointer<LLViewerFetchedTexture> image_in_list = 
 		LLViewerTextureManager::getFetchedTexture(mResourceDatap->mAssetInfo.mUuid, TRUE, FALSE, LLViewerTexture::FETCHED_TEXTURE);
-	image_in_list->createGLTexture(0, raw);
+	image_in_list->createGLTexture(0, raw, 0, TRUE, LLViewerTexture::OTHER);
 	
 	// the texture picker then uses that texture
 	LLTexturePicker* texture = getChild<LLTextureCtrl>("screenshot");
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index fbaf10d455350f668900bc18b43531b78eb8b18e..63560d2038ceee27940cad5c8cad11f74fb45e7c 100644
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -55,7 +55,6 @@
 #include "llregionhandle.h"
 #include "llscrolllistctrl.h"
 #include "llslurl.h"
-#include "lltabcontainer.h"
 #include "lltextbox.h"
 #include "lltracker.h"
 #include "lltrans.h"
@@ -63,7 +62,9 @@
 #include "llviewermenu.h"
 #include "llviewerregion.h"
 #include "llviewerstats.h"
+#include "llviewertexture.h"
 #include "llworldmap.h"
+#include "llworldmapmessage.h"
 #include "llworldmapview.h"
 #include "lluictrlfactory.h"
 #include "llappviewer.h"
@@ -79,6 +80,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,
@@ -160,11 +167,11 @@ LLFloaterWorldMap::LLFloaterWorldMap(const LLSD& key)
 	gFloaterWorldMap = this;
 	
 	mFactoryMap["objects_mapview"] = LLCallbackMap(createWorldMapView, NULL);
-	mFactoryMap["terrain_mapview"] = LLCallbackMap(createWorldMapView, NULL);
 	
 	//Called from floater reg: LLUICtrlFactory::getInstance()->buildFloater(this, "floater_world_map.xml", FALSE);
 	mCommitCallbackRegistrar.add("WMap.Location",		boost::bind(&LLFloaterWorldMap::onLocationCommit, this));
 	mCommitCallbackRegistrar.add("WMap.AvatarCombo",	boost::bind(&LLFloaterWorldMap::onAvatarComboCommit, this));
+	mCommitCallbackRegistrar.add("WMap.Landmark",		boost::bind(&LLFloaterWorldMap::onLandmarkComboCommit, this));
 	mCommitCallbackRegistrar.add("WMap.SearchResult",	boost::bind(&LLFloaterWorldMap::onCommitSearchResult, this));
 	mCommitCallbackRegistrar.add("WMap.CommitLocation",	boost::bind(&LLFloaterWorldMap::onCommitLocation, this));
 	mCommitCallbackRegistrar.add("WMap.GoHome",			boost::bind(&LLFloaterWorldMap::onGoHome, this));	
@@ -183,17 +190,7 @@ void* LLFloaterWorldMap::createWorldMapView(void* data)
 
 BOOL LLFloaterWorldMap::postBuild()
 {
-	mTabs = getChild<LLTabContainer>("maptab");
-	if (!mTabs) return FALSE;
-
-	mTabs->setCommitCallback(boost::bind(&LLFloaterWorldMap::onCommitBackground, 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();
+	mPanel = getChild<LLPanel>("objects_mapview");
 
 	LLComboBox *avatar_combo = getChild<LLComboBox>("friend combo");
 	if (avatar_combo)
@@ -221,8 +218,8 @@ BOOL LLFloaterWorldMap::postBuild()
 		landmark_combo->setTextEntryCallback( boost::bind(&LLFloaterWorldMap::onComboTextEntry, this) );
 	}
 
-	mCurZoomVal = log(gMapScale)/log(2.f);
-	childSetValue("zoom slider", gMapScale);
+	mCurZoomVal = log(LLWorldMapView::sMapScale)/log(2.f);
+	childSetValue("zoom slider", LLWorldMapView::sMapScale);
 
 	setDefaultBtn(NULL);
 
@@ -235,7 +232,7 @@ BOOL LLFloaterWorldMap::postBuild()
 LLFloaterWorldMap::~LLFloaterWorldMap()
 {
 	// All cleaned up by LLView destructor
-	mTabs = NULL;
+	mPanel = NULL;
 
 	// Inventory deletes all observers on shutdown
 	mInventory = NULL;
@@ -268,7 +265,7 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)
 	mIsClosing = FALSE;
 
 	LLWorldMapView* map_panel;
-	map_panel = (LLWorldMapView*)mTabs->getCurrentPanel();
+	map_panel = (LLWorldMapView*)gFloaterWorldMap->mPanel;
 	map_panel->clearLastClick();
 
 	{
@@ -279,15 +276,8 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)
 		}
 		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 = 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.
@@ -321,12 +311,9 @@ void LLFloaterWorldMap::onOpen(const LLSD& key)
 // static
 void LLFloaterWorldMap::reloadIcons(void*)
 {
-	LLWorldMap::getInstance()->eraseItems();
-
-	LLWorldMap::getInstance()->sendMapLayerRequest();
+	LLWorldMap::getInstance()->reloadItems();
 }
 
-
 // virtual
 BOOL LLFloaterWorldMap::handleHover(S32 x, S32 y, MASK mask)
 {
@@ -358,12 +345,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();
 }
 
 
@@ -445,7 +426,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);
@@ -465,6 +446,18 @@ void LLFloaterWorldMap::draw()
 	mCurZoomVal = lerp(mCurZoomVal, (F32)childGetValue("zoom slider").asReal(), interp);
 	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("telehub_chk", enable);
+	childSetEnabled("land_for_sale_chk", enable);
+	childSetEnabled("event_chk", enable);
+	childSetEnabled("event_mature_chk", enable);
+	childSetEnabled("event_adult_chk", enable);
 	
 	LLFloater::draw();
 }
@@ -553,14 +546,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");
 }
 
@@ -569,29 +562,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)", 
@@ -603,9 +594,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");
 }
@@ -718,9 +707,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();
 	}
 }
 
@@ -787,19 +776,12 @@ void LLFloaterWorldMap::buildAvatarIDList()
 
     // Delete all but the "None" entry
 	S32 list_size = list->getItemCount();
-	while (list_size > 1)
+	if (list_size > 1)
 	{
-		list->selectNthItem(1);
+		list->selectItemRange(1, -1);
 		list->operateOnSelection(LLCtrlListInterface::OP_DELETE);
-		--list_size;
 	}
 
-	LLSD default_column;
-	default_column["name"] = "friend name";
-	default_column["label"] = "Friend Name";
-	default_column["width"] = 500;
-	list->addColumn(default_column);
-
 	// Get all of the calling cards for avatar that are currently online
 	LLCollectMappableBuddies collector;
 	LLAvatarTracker::instance().applyFunctor(collector);
@@ -820,10 +802,7 @@ void LLFloaterWorldMap::buildAvatarIDList()
 void LLFloaterWorldMap::buildLandmarkIDLists()
 {
 	LLCtrlListInterface *list = childGetListInterface("landmark combo");
-	if (!list)
-	{
-		return;
-	}
+	if (!list) return;
 
     // Delete all but the "None" entry
 	S32 list_size = list->getItemCount();
@@ -864,7 +843,6 @@ void LLFloaterWorldMap::buildLandmarkIDLists()
 		mLandmarkAssetIDList.put( item->getAssetUUID() );
 		mLandmarkItemIDList.put( item->getUUID() );
 	}
-	list->sortByColumn(std::string("landmark name"), TRUE);
 
 	list->selectFirstItem();
 }
@@ -901,7 +879,7 @@ void LLFloaterWorldMap::clearLocationSelection(BOOL clear_ui)
 	{
 		childSetValue("spin z", 0);
 	}
-	LLWorldMap::getInstance()->mIsTrackingCommit = FALSE;
+	LLWorldMap::getInstance()->cancelTracking();
 	mCompletingRegionName = "";
 }
 
@@ -937,18 +915,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
@@ -1161,15 +1137,15 @@ void LLFloaterWorldMap::onLocationCommit()
 
 	LLStringUtil::toLower(str);
 	mCompletingRegionName = str;
-	LLWorldMap::getInstance()->mIsTrackingCommit = TRUE;
+	LLWorldMap::getInstance()->setTrackingCommit();
 	if (str.length() >= 3)
 	{
-		LLWorldMap::getInstance()->sendNamedRegionRequest(str);
+		LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str);
 	}
 	else
 	{
 		str += "#";
-		LLWorldMap::getInstance()->sendNamedRegionRequest(str);
+		LLWorldMapMessage::getInstance()->sendNamedRegionRequest(str);
 	}
 }
 
@@ -1177,8 +1153,8 @@ void LLFloaterWorldMap::onClearBtn()
 {
 	mTrackedStatus = LLTracker::TRACKING_NOTHING;
 	LLTracker::stopTracking((void *)(intptr_t)TRUE);
-	LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE;
-	mSLURL = "";				// Clear the SLURL since it's invalid
+	LLWorldMap::getInstance()->cancelTracking();
+	mSLURL = "";					// Clear the SLURL since it's invalid
 	mSetToUserPosition = TRUE;	// Revert back to the current user position
 }
 
@@ -1230,9 +1206,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
 	{
@@ -1240,8 +1216,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;
 }
@@ -1399,13 +1375,6 @@ void LLFloaterWorldMap::flyToAvatar()
 	}
 }
 
-void LLFloaterWorldMap::onCommitBackground()
-{
-	// Find my index
-	S32 index = mTabs->getCurrentPanelIndex();
-	LLWorldMap::getInstance()->setCurrentLayer(index);
-}
-
 void LLFloaterWorldMap::updateSims(bool found_null_sim)
 {
 	if (mCompletingRegionName == "")
@@ -1422,24 +1391,23 @@ void LLFloaterWorldMap::updateSims(bool found_null_sim)
 	
 	S32 num_results = 0;
 	std::map<U64, LLSimInfo*>::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 (sim_name_lower == mCompletingRegionName)
 			{
-				match = sim_name;
+				match = info->getName();
 			}
 			
 			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++;
 		}
@@ -1496,15 +1464,13 @@ void LLFloaterWorldMap::onCommitSearchResult()
 	LLStringUtil::toLower(sim_name);
 
 	std::map<U64, LLSimInfo*>::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 = childGetValue("spin x");
 			F64 local_y = childGetValue("spin y");
 			F64 local_z = childGetValue("spin z");
diff --git a/indra/newview/llfloaterworldmap.h b/indra/newview/llfloaterworldmap.h
index 20a8e6d32179685c466c362e66627fcd6ba4ef95..7feebb583d8ec81e01dd73aa229b44821a9589af 100644
--- a/indra/newview/llfloaterworldmap.h
+++ b/indra/newview/llfloaterworldmap.h
@@ -96,7 +96,7 @@ class LLFloaterWorldMap : public LLFloater
 	static const LLUUID& getHomeID() { return sHomeID; }
 
 	// A z_attenuation of 0.0f collapses the distance into the X-Y plane
-	F32			getDistanceToDestination(const LLVector3d& pos_global, F32 z_attenuation = 0.5f) const;
+	F32				getDistanceToDestination(const LLVector3d& pos_global, F32 z_attenuation = 0.5f) const;
 
 	void			clearLocationSelection(BOOL clear_ui = FALSE);
 	void			clearAvatarSelection(BOOL clear_ui = FALSE);
@@ -121,8 +121,6 @@ class LLFloaterWorldMap : public LLFloater
 	void			onAvatarComboPrearrange();
 	void		    onAvatarComboCommit();
 
-	void			onCommitBackground();
-
 	void			onComboTextEntry( );
 	void			onSearchTextEntry( LLLineEditor* ctrl );
 
@@ -155,10 +153,10 @@ class LLFloaterWorldMap : public LLFloater
 
 	void			cacheLandmarkPosition();
 
-protected:
-	LLTabContainer*	mTabs;
+private:
+	LLPanel*			mPanel;		// Panel displaying the map
 
-	// Sets gMapScale, in pixels per region
+	// Ties to LLWorldMapView::sMapScale, in pixels per region
 	F32						mCurZoomVal;
 	LLFrameTimer			mZoomTimer;
 
diff --git a/indra/newview/lllandmarkactions.cpp b/indra/newview/lllandmarkactions.cpp
index a341720aec3d75013b6658efb6aca68675a79ace..12796507cada96719f99d8233b54121862c8db6a 100644
--- a/indra/newview/lllandmarkactions.cpp
+++ b/indra/newview/lllandmarkactions.cpp
@@ -49,6 +49,7 @@
 #include "llstring.h"
 #include "llviewerinventory.h"
 #include "llviewerparcelmgr.h"
+#include "llworldmapmessage.h"
 #include "llviewerwindow.h"
 #include "llwindow.h"
 #include "llworldmap.h"
@@ -268,13 +269,13 @@ void LLLandmarkActions::getSLURLfromPosGlobal(const LLVector3d& global_pos, slur
 	{
 		U64 new_region_handle = to_region_handle(global_pos);
 
-		LLWorldMap::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseSLURL,
+		LLWorldMapMessage::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseSLURL,
 														cb,
 														global_pos,
 														escaped,
 														_2);
 
-		LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false);
+		LLWorldMapMessage::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false);
 	}
 }
 
@@ -285,18 +286,19 @@ void LLLandmarkActions::getRegionNameAndCoordsFromPosGlobal(const LLVector3d& gl
 	if (sim_infop)
 	{
 		LLVector3 pos = sim_infop->getLocalPos(global_pos);
-		cb(sim_infop->mName, llround(pos.mV[VX]), llround(pos.mV[VY]));
+		std::string name = sim_infop->getName() ;
+		cb(name, llround(pos.mV[VX]), llround(pos.mV[VY]));
 	}
 	else
 	{
 		U64 new_region_handle = to_region_handle(global_pos);
 
-		LLWorldMap::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseNameAndCoords,
+		LLWorldMapMessage::url_callback_t url_cb = boost::bind(&LLLandmarkActions::onRegionResponseNameAndCoords,
 														cb,
 														global_pos,
 														_1);
 
-		LLWorldMap::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false);
+		LLWorldMapMessage::getInstance()->sendHandleRegionRequest(new_region_handle, url_cb, std::string("unused"), false);
 	}
 }
 
@@ -328,7 +330,8 @@ void LLLandmarkActions::onRegionResponseNameAndCoords(region_name_and_coords_cal
 	if (sim_infop)
 	{
 		LLVector3 local_pos = sim_infop->getLocalPos(global_pos);
-		cb(sim_infop->mName, llround(local_pos.mV[VX]), llround(local_pos.mV[VY]));
+		std::string name = sim_infop->getName() ;
+		cb(name, llround(local_pos.mV[VX]), llround(local_pos.mV[VY]));
 	}
 }
 
diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index b91e23eace4ac9e0d6b63b1b4fef8f343864f7da..b60f0f12467c98c3681ec50aaa300ac7945ac2e9 100644
--- a/indra/newview/llnavigationbar.cpp
+++ b/indra/newview/llnavigationbar.cpp
@@ -51,7 +51,7 @@
 #include "llurlsimstring.h"
 #include "llviewerinventory.h"
 #include "llviewerparcelmgr.h"
-#include "llworldmap.h"
+#include "llworldmapmessage.h"
 #include "llappviewer.h"
 #include "llviewercontrol.h"
 #include "llfloatermediabrowser.h"
@@ -386,14 +386,13 @@ void LLNavigationBar::onLocationSelection()
 	
 	// Resolve the region name to its global coordinates.
 	// If resolution succeeds we'll teleport.
-	LLWorldMap::url_callback_t cb = boost::bind(
+	LLWorldMapMessage::url_callback_t cb = boost::bind(
 			&LLNavigationBar::onRegionNameResponse, this,
 			typed_location, region_name, local_coords, _1, _2, _3, _4);
 	// connect the callback each time, when user enter new location to get real location of agent after teleport
 	mTeleportFinishConnection = LLViewerParcelMgr::getInstance()->
 			setTeleportFinishedCallback(boost::bind(&LLNavigationBar::onTeleportFinished, this, _1,typed_location));
-	
-	LLWorldMap::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false);
+	LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name, cb, std::string("unused"), false);
 }
 
 void LLNavigationBar::onTeleportFinished(const LLVector3d& global_agent_pos, const std::string& typed_location)
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index b6b433c28f19d2e0790b0028448686075d5e29f1..4286582cdc5b6758b58604fd26f60673d96c0c40 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -65,9 +65,15 @@
 
 static LLDefaultChildRegistry::Register<LLNetMap> r1("net_map");
 
+const F32 LLNetMap::MAP_SCALE_MIN = 32;
+const F32 LLNetMap::MAP_SCALE_MID = 1024;
+const F32 LLNetMap::MAP_SCALE_MAX = 4096;
+
 const F32 MAP_SCALE_INCREMENT = 16;
-const F32 MAP_MIN_PICK_DIST = 4;
-const F32 MAX_PRIM_RADIUS = 256.0f; // Don't try to draw giant mega-prims on the mini map
+const F32 MAP_SCALE_ZOOM_FACTOR = 1.04f; // Zoom in factor per click of scroll wheel (4%)
+const F32 MIN_DOT_RADIUS = 3.5f;
+const F32 DOT_SCALE = 0.75f;
+const F32 MIN_PICK_SCALE = 2.f;
 
 LLNetMap::LLNetMap (const Params & p)
 :	LLUICtrl (p),
@@ -89,6 +95,7 @@ LLNetMap::LLNetMap (const Params & p)
 	mRotateMap(FALSE),
 	mToolTipMsg()
 {
+	mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
 }
 
 LLNetMap::~LLNetMap()
@@ -101,17 +108,18 @@ void LLNetMap::setScale( F32 scale )
 	
 	if (mObjectImagep.notNull())
 	{
-		F32 half_width = (F32)(getRect().getWidth() / 2);
-		F32 half_height = (F32)(getRect().getHeight() / 2);
-		F32 radius = sqrt( half_width * half_width + half_height * half_height );
-		F32 region_widths = (2.f*radius)/mScale;
+		F32 width = (F32)(getRect().getWidth());
+		F32 height = (F32)(getRect().getHeight());
+		F32 diameter = sqrt(width * width + height * height);
+		F32 region_widths = diameter / mScale;
 		F32 meters = region_widths * LLWorld::getInstance()->getRegionWidthInMeters();
 		F32 num_pixels = (F32)mObjectImagep->getWidth();
-		mObjectMapTPM = num_pixels/meters;
-		mObjectMapPixels = 2.f*radius;
+		mObjectMapTPM = num_pixels / meters;
+		mObjectMapPixels = diameter;
 	}
 
 	mPixelsPerMeter = mScale / REGION_WIDTH_METERS;
+	mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
 
 	mUpdateNow = TRUE;
 }
@@ -302,6 +310,7 @@ void LLNetMap::draw()
 		LLUI::getMousePositionLocal(this, &local_mouse_x, &local_mouse_y);
 		mClosestAgentToCursor.setNull();
 		F32 closest_dist = F32_MAX;
+		F32 min_pick_dist = mDotRadius * MIN_PICK_SCALE; 
 
 		// Draw avatars
 		for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
@@ -345,10 +354,10 @@ void LLNetMap::draw()
 				LLWorldMapView::drawAvatar(
 					pos_map.mV[VX], pos_map.mV[VY], 
 					show_as_friend ? map_avatar_friend_color : map_avatar_color, 
-					pos_map.mV[VZ]);
+					pos_map.mV[VZ], mDotRadius);
 
 				F32	dist_to_cursor = dist_vec(LLVector2(pos_map.mV[VX], pos_map.mV[VY]), LLVector2(local_mouse_x,local_mouse_y));
-				if(dist_to_cursor < MAP_MIN_PICK_DIST && dist_to_cursor < closest_dist)
+				if(dist_to_cursor < min_pick_dist && dist_to_cursor < closest_dist)
 				{
 					closest_dist = dist_to_cursor;
 					mClosestAgentToCursor = regionp->mMapAvatarIDs.get(i);
@@ -378,10 +387,12 @@ void LLNetMap::draw()
 		// Draw dot for self avatar position
 		pos_global = gAgent.getPositionGlobal();
 		pos_map = globalPosToView(pos_global);
-		LLUIImagePtr you = LLWorldMapView::sAvatarYouSmallImage;
-		you->draw(
-			llround(pos_map.mV[VX]) - you->getWidth()/2, 
-			llround(pos_map.mV[VY]) - you->getHeight()/2);
+		LLUIImagePtr you = LLWorldMapView::sAvatarYouLargeImage;
+		S32 dot_width = llround(mDotRadius * 2.f);
+		you->draw(llround(pos_map.mV[VX] - mDotRadius),
+				  llround(pos_map.mV[VY] - mDotRadius),
+				  dot_width,
+				  dot_width);
 
 		// Draw frustum
 		F32 meters_to_pixels = mScale/ LLWorld::getInstance()->getRegionWidthInMeters();
@@ -429,6 +440,12 @@ void LLNetMap::draw()
 	LLUICtrl::draw();
 }
 
+void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+	LLUICtrl::reshape(width, height, called_from_parent);
+	createObjectImage();
+}
+
 LLVector3 LLNetMap::globalPosToView( const LLVector3d& global_pos )
 {
 	LLVector3d relative_pos_global = global_pos - gAgent.getCameraPositionGlobal();
@@ -504,8 +521,12 @@ LLVector3d LLNetMap::viewPosToGlobal( S32 x, S32 y )
 
 BOOL LLNetMap::handleScrollWheel(S32 x, S32 y, S32 clicks)
 {
-	// note that clicks are reversed from what you'd think
-	setScale(llclamp(mScale - clicks*MAP_SCALE_INCREMENT, MAP_SCALE_MIN, MAP_SCALE_MAX));
+	// note that clicks are reversed from what you'd think: i.e. > 0  means zoom out, < 0 means zoom in
+	F32 scale = mScale;
+        
+	scale *= pow(MAP_SCALE_ZOOM_FACTOR, -clicks);
+	setScale(llclamp(scale, MAP_SCALE_MIN, MAP_SCALE_MAX));
+
 	return TRUE;
 }
 
@@ -567,9 +588,7 @@ void LLNetMap::renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &
 	LLVector3 local_pos;
 	local_pos.setVec( pos - mObjectImageCenterGlobal );
 
-	F32 radius_clamped = llmin(radius_meters, MAX_PRIM_RADIUS);
-	
-	S32 diameter_pixels = llround(2 * radius_clamped * mObjectMapTPM);
+	S32 diameter_pixels = llround(2 * radius_meters * mObjectMapTPM);
 	renderPoint( local_pos, color, diameter_pixels );
 }
 
@@ -662,13 +681,13 @@ void LLNetMap::renderPoint(const LLVector3 &pos_local, const LLColor4U &color,
 void LLNetMap::createObjectImage()
 {
 	// Find the size of the side of a square that surrounds the circle that surrounds getRect().
-	F32 half_width = (F32)(getRect().getWidth() / 2);
-	F32 half_height = (F32)(getRect().getHeight() / 2);
-	F32 radius = sqrt( half_width * half_width + half_height * half_height );
-	S32 square_size = S32( 2 * radius );
+	// ... which is, the diagonal of the rect.
+	F32 width = (F32)getRect().getWidth();
+	F32 height = (F32)getRect().getHeight();
+	S32 square_size = llround( sqrt(width*width + height*height) );
 
 	// Find the least power of two >= the minimum size.
-	const S32 MIN_SIZE = 32;
+	const S32 MIN_SIZE = 64;
 	const S32 MAX_SIZE = 256;
 	S32 img_size = MIN_SIZE;
 	while( (img_size*2 < square_size ) && (img_size < MAX_SIZE) )
@@ -684,7 +703,7 @@ void LLNetMap::createObjectImage()
 		U8* data = mObjectRawImagep->getData();
 		memset( data, 0, img_size * img_size * 4 );
 		mObjectImagep = LLViewerTextureManager::getLocalTexture( mObjectRawImagep.get(), FALSE);
-		setScale(mScale);
 	}
+	setScale(mScale);
 	mUpdateNow = TRUE;
 }
diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h
index 5ebdd13384642b811de03d6cee193d506188b597..7088ab3e70c08c965b8fec78e8845e831b81e909 100644
--- a/indra/newview/llnetmap.h
+++ b/indra/newview/llnetmap.h
@@ -70,9 +70,14 @@ class LLNetMap : public LLUICtrl
 public:
 	virtual ~LLNetMap();
 
+	static const F32 MAP_SCALE_MIN;
+	static const F32 MAP_SCALE_MID;
+	static const F32 MAP_SCALE_MAX;
+
 	/*virtual*/ void	draw();
 	/*virtual*/ BOOL	handleScrollWheel(S32 x, S32 y, S32 clicks);
 	/*virtual*/ BOOL	handleToolTip( S32 x, S32 y, MASK mask);
+	/*virtual*/ void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
 	
 	void			setScale( F32 scale );
 	void			setRotateMap( BOOL b ) { mRotateMap = b; }
@@ -94,16 +99,17 @@ class LLNetMap : public LLUICtrl
 	void			drawTracking( const LLVector3d& pos_global, 
 								  const LLColor4& color,
 								  BOOL draw_arrow = TRUE);
-
-	void			createObjectImage();
 	
+	void			createObjectImage();
+
 private:
 	LLUIColor		mBackgroundColor;
 
 	F32				mScale;					// Size of a region in pixels
 	F32				mPixelsPerMeter;		// world meters to map pixels
 	F32				mObjectMapTPM;			// texels per meter on map
-	F32				mObjectMapPixels;		// Width of object map in pixels;
+	F32				mObjectMapPixels;		// Width of object map in pixels
+	F32				mDotRadius;				// Size of avatar markers
 	F32				mTargetPanX;
 	F32				mTargetPanY;
 	F32				mCurPanX;
diff --git a/indra/newview/llpanelteleporthistory.cpp b/indra/newview/llpanelteleporthistory.cpp
index 7dd9df674c0c15302dbda39af77831e0187edc36..92040eb2e56ba24f3563b8252177159f9f84ad0c 100644
--- a/indra/newview/llpanelteleporthistory.cpp
+++ b/indra/newview/llpanelteleporthistory.cpp
@@ -357,7 +357,7 @@ void LLTeleportHistoryPanel::onCopySLURL()
 
 	U64 new_region_handle = to_region_handle(global_pos);
 
-	LLWorldMap::url_callback_t cb = boost::bind(
+	LLWorldMapMessage::url_callback_t cb = boost::bind(
 			&LLPanelPlacesTab::onRegionResponse, this,
 			global_pos, _1, _2, _3, _4);
 
diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index 9c21faa3be5d386ea38bcd604cf909b57bef7fe7..a44794122f661047d7fa4fd347888e5533460329 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -192,6 +192,11 @@ void LLPreviewTexture::draw()
 			// Pump the texture priority
 			F32 pixel_area = mLoadingFullImage ? (F32)MAX_IMAGE_AREA  : (F32)(interior.getWidth() * interior.getHeight() );
 			mImage->addTextureStats( pixel_area );
+			if(pixel_area > 0.f)
+			{
+				//boost the previewed image priority to the highest to make it to get loaded first.
+				mImage->setAdditionalDecodePriority(1.0f) ;
+			}
 
 			// Don't bother decoding more than we can display, unless
 			// we're loading the full image.
@@ -554,6 +559,7 @@ void LLPreviewTexture::loadAsset()
 {
 	mImage = LLViewerTextureManager::getFetchedTexture(mImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
 	mImage->setBoostLevel(LLViewerTexture::BOOST_PREVIEW);
+	mImage->forceToSaveRawImage(0) ;
 	mAssetStatus = PREVIEW_ASSET_LOADING;
 	updateDimensions();
 }
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 9f317803ce745c5cea1579136ad290b881227f29..5afb821d1572b88e01c27cb7242f9f348714fd00 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2679,8 +2679,7 @@ void renderTexturePriority(LLDrawable* drawable)
 		//LLViewerTexture* imagep = facep->getTexture();
 		//if (imagep)
 		{
-	
-			//F32 vsize = LLVOVolume::getTextureVirtualSize(facep);
+				
 			//F32 vsize = imagep->mMaxVirtualSize;
 			F32 vsize = facep->getPixelArea();
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 51b651d58eebcad1dc399d04031d8a8f1afcd28a..bfe753a0aa791c6f0d93c49da0f70f11ceff72e8 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -61,6 +61,7 @@
 #include "llfocusmgr.h"
 #include "llhttpsender.h"
 #include "lllocationhistory.h"
+#include "llimageworker.h"
 #include "llloginflags.h"
 #include "llmd5.h"
 #include "llmemorystream.h"
@@ -170,7 +171,7 @@
 #include "llvoclouds.h"
 #include "llweb.h"
 #include "llworld.h"
-#include "llworldmap.h"
+#include "llworldmapmessage.h"
 #include "llxfermanager.h"
 #include "pipeline.h"
 #include "llappviewer.h"
@@ -1812,6 +1813,7 @@ bool idle_startup()
 			gViewerWindow->moveProgressViewToFront();
 
 			LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
+			
 			// set initial visibility of debug console
 			gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
 		}
@@ -3266,9 +3268,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", &LLAvatarPropertiesProcessor::processPickInfoReply);
diff --git a/indra/newview/llsurface.cpp b/indra/newview/llsurface.cpp
index 5440b2c9adfe0c35c139ea9dd7928b3d2510443b..1d479bac8cabf4f7dea2dcb4bc66a149df9a2093 100644
--- a/indra/newview/llsurface.cpp
+++ b/indra/newview/llsurface.cpp
@@ -234,12 +234,7 @@ void LLSurface::createSTexture()
 {
 	if (!mSTexturep)
 	{
-		// Fill with dummy gray data.
-	
-		//mSTexturep =  LLViewerTextureManager::getLocalTexture(sTextureSize, sTextureSize, 3, FALSE);
-		//mSTexturep->dontDiscard();
-		//mSTexturep->setAddressMode(LLTexUnit::TAM_CLAMP);
-		
+		// Fill with dummy gray data.	
 		// GL NOT ACTIVE HERE
 		LLPointer<LLImageRaw> raw = new LLImageRaw(sTextureSize, sTextureSize, 3);
 		U8 *default_texture = raw->getData();
diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp
index 5d9046ac905c19af80d44ce21f2143d005218afe..4ff5906b7e06c477bb5238c507fce73a872a968a 100644
--- a/indra/newview/lltexlayer.cpp
+++ b/indra/newview/lltexlayer.cpp
@@ -1371,7 +1371,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, BOOL render_morph)
 
 					LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
 					
-					gGL.getTexUnit(0)->bind(tex);
+					gGL.getTexUnit(0)->bind(tex, TRUE);
 					gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 
 					gl_rect_2d_simple_tex( width, height );
@@ -1393,7 +1393,7 @@ BOOL LLTexLayer::render(S32 x, S32 y, S32 width, S32 height, BOOL render_morph)
 			LLViewerTexture* tex = LLTexLayerStaticImageList::getInstance()->getTexture(getInfo()->mStaticImageFileName, getInfo()->mStaticImageIsMask);
 			if( tex )
 			{
-				gGL.getTexUnit(0)->bind(tex);
+				gGL.getTexUnit(0)->bind(tex, TRUE);
 				gl_rect_2d_simple_tex( width, height );
 				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 			}
@@ -1506,7 +1506,7 @@ BOOL LLTexLayer::blendAlphaTexture(S32 x, S32 y, S32 width, S32 height)
 		if( tex )
 		{
 			LLGLSNoAlphaTest gls_no_alpha_test;
-			gGL.getTexUnit(0)->bind(tex);
+			gGL.getTexUnit(0)->bind(tex, TRUE);
 			gl_rect_2d_simple_tex( width, height );
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		}
@@ -1585,7 +1585,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
 
 				LLTexUnit::eTextureAddressMode old_mode = tex->getAddressMode();
 				
-				gGL.getTexUnit(0)->bind(tex);
+				gGL.getTexUnit(0)->bind(tex, TRUE);
 				gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 
 				gl_rect_2d_simple_tex( width, height );
@@ -1608,7 +1608,7 @@ BOOL LLTexLayer::renderMorphMasks(S32 x, S32 y, S32 width, S32 height, const LLC
 					( (tex->getComponents() == 1) && getInfo()->mStaticImageIsMask ) )
 				{
 					LLGLSNoAlphaTest gls_no_alpha_test;
-					gGL.getTexUnit(0)->bind(tex);
+					gGL.getTexUnit(0)->bind(tex, TRUE);
 					gl_rect_2d_simple_tex( width, height );
 					gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 				}
@@ -2034,7 +2034,7 @@ LLViewerTexture* LLTexLayerStaticImageList::getTexture(const std::string& file_n
 				// that once an image is a mask it's always a mask.
 				tex->setExplicitFormat( GL_ALPHA8, GL_ALPHA );
 			}
-			tex->createGLTexture(0, image_raw);
+			tex->createGLTexture(0, image_raw, 0, TRUE, LLViewerTexture::LOCAL);
 
 			gGL.getTexUnit(0)->bind(tex);
 			tex->setAddressMode(LLTexUnit::TAM_CLAMP);
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 1b249d75d15320c454ffd63d50059100c5cb0ed1..69a2d1d7a6bd914264658c3bff764ccabb5216e5 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -43,11 +43,17 @@
 // Included to allow LLTextureCache::purgeTextures() to pause watchdog timeout
 #include "llappviewer.h" 
 
-#define USE_LFS_READ 0
-#define USE_LFS_WRITE 0
-
-// Note: first 4 bytes store file size, rest is j2c data
-const S32 TEXTURE_CACHE_ENTRY_SIZE = FIRST_PACKET_SIZE; //1024;
+// Cache organization:
+// cache/texture.entries
+//  Unordered array of Entry structs
+// cache/texture.cache
+//  First TEXTURE_CACHE_ENTRY_SIZE bytes of each texture in texture.entries in same order
+// cache/textures/[0-F]/UUID.texture
+//  Actual texture body files
+
+const S32 TEXTURE_CACHE_ENTRY_SIZE = 1024;
+const F32 TEXTURE_CACHE_PURGE_AMOUNT = .20f; // % amount to reduce the cache by when it exceeds its limit
+const F32 TEXTURE_CACHE_LRU_SIZE = .10f; // % amount for LRU list (low overhead to regenerate)
 
 class LLTextureCacheWorker : public LLWorkerClass
 {
@@ -309,94 +315,75 @@ void LLTextureCacheWorker::startWork(S32 param)
 {
 }
 
+// This is where a texture is read from the cache system (header and body)
+// Current assumption are:
+// - the whole data are in a raw form, will be stored at mReadData
+// - the size of this raw data is mDataSize and can be smaller than TEXTURE_CACHE_ENTRY_SIZE (the size of a record in the header cache)
+// - the code supports offset reading but this is actually never exercised in the viewer
 bool LLTextureCacheRemoteWorker::doRead()
 {
+	bool done = false;
+	S32 idx = -1;
+
 	S32 local_size = 0;
 	std::string local_filename;
 	
+	// First state / stage : find out if the file is local
 	if (mState == INIT)
 	{
 		std::string filename = mCache->getLocalFileName(mID);	
-		local_filename = filename + ".j2c";
-		local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
-		if (local_size == 0)
+		// Is it a JPEG2000 file? 
 		{
-			local_filename = filename + ".tga";
+			local_filename = filename + ".j2c";
 			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
 			if (local_size > 0)
 			{
-				mImageFormat = IMG_CODEC_TGA;
-				mDataSize = local_size; // Only a complete .tga file is valid
+				mImageFormat = IMG_CODEC_J2C;
 			}
 		}
-		if (local_size > 0)
-		{
-			mState = LOCAL;
-		}
-		else
-		{
-			mState = CACHE;
-		}
-	}
-
-	if (mState == LOCAL)
-	{
-#if USE_LFS_READ
-		if (mFileHandle == LLLFSThread::nullHandle())
+		// If not, is it a jpeg file?
+		if (local_size == 0)
 		{
-			mImageLocal = TRUE;
-			mImageSize = local_size;
-			if (!mDataSize || mDataSize + mOffset > local_size)
+			local_filename = filename + ".jpg";
+			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
+			if (local_size > 0)
 			{
-				mDataSize = local_size - mOffset;
+				mImageFormat = IMG_CODEC_JPEG;
+				mDataSize = local_size; // Only a complete .jpg file is valid
 			}
-			if (mDataSize <= 0)
-			{
-				// no more data to read
-				mDataSize = 0;
-				return true;
-			}
-			mReadData = new U8[mDataSize];
-			mBytesRead = -1;
-			mBytesToRead = mDataSize;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-			mFileHandle = LLLFSThread::sLocal->read(local_filename, mReadData, mOffset, mDataSize,
-													new ReadResponder(mCache, mRequestHandle));
-			return false;
 		}
-		else
+		// Hmm... What about a targa file? (used for UI texture mostly)
+		if (local_size == 0)
 		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-// 					llwarns << "Error reading file from local cache: " << local_filename
-// 							<< " Bytes: " << mDataSize << " Offset: " << mOffset
-// 							<< " / " << mDataSize << llendl;
-					mDataSize = 0; // failed
-					delete[] mReadData;
-					mReadData = NULL;
-				}
-				return true;
-			}
-			else
+			local_filename = filename + ".tga";
+			local_size = LLAPRFile::size(local_filename, mCache->getLocalAPRFilePool());
+			if (local_size > 0)
 			{
-				return false;
+				mImageFormat = IMG_CODEC_TGA;
+				mDataSize = local_size; // Only a complete .tga file is valid
 			}
 		}
-#else
+		// Determine the next stage: if we found a file, then LOCAL else CACHE
+		mState = (local_size > 0 ? LOCAL : CACHE);
+	}
+
+	// Second state / stage : if the file is local, load it and leave
+	if (!done && (mState == LOCAL))
+	{
+		llassert(local_size != 0);	// we're assuming there is a non empty local file here...
 		if (!mDataSize || mDataSize > local_size)
 		{
 			mDataSize = local_size;
 		}
+		// Allocate read buffer
 		mReadData = new U8[mDataSize];
 		S32 bytes_read = LLAPRFile::readEx(local_filename, 
 											 mReadData, mOffset, mDataSize, mCache->getLocalAPRFilePool());
 		if (bytes_read != mDataSize)
 		{
-// 			llwarns << "Error reading file from local cache: " << local_filename
-// 					<< " Bytes: " << mDataSize << " Offset: " << mOffset
-// 					<< " / " << mDataSize << llendl;
+ 			llwarns << "Error reading file from local cache: " << local_filename
+ 					<< " Bytes: " << mDataSize << " Offset: " << mOffset
+ 					<< " / " << mDataSize << llendl;
 			mDataSize = 0;
 			delete[] mReadData;
 			mReadData = NULL;
@@ -406,405 +393,275 @@ bool LLTextureCacheRemoteWorker::doRead()
 			mImageSize = local_size;
 			mImageLocal = TRUE;
 		}
-		return true;
-#endif
+		// We're done...
+		done = true;
 	}
 
-	S32 idx = -1;
-	
-	if (mState == CACHE)
+	// Second state / stage : identify the cache or not...
+	if (!done && (mState == CACHE))
 	{
-		llassert_always(mImageSize == 0);
-		idx = mCache->getHeaderCacheEntry(mID, false, &mImageSize);
-		if (idx >= 0 && mImageSize > mOffset)
+		idx = mCache->getHeaderCacheEntry(mID, mImageSize);
+		if (idx < 0)
 		{
-			llassert_always(mImageSize > 0);
-			if (!mDataSize || mDataSize > mImageSize)
-			{
-				mDataSize = mImageSize;
-			}
-			mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
+			// The texture is *not* cached. We're done here...
+			mDataSize = 0; // no data 
+			done = true;
 		}
 		else
 		{
-			mDataSize = 0; // no data
-			return true;
+			// If the read offset is bigger than the header cache, we read directly from the body
+			// Note that currently, we *never* read with offset from the cache, so the result is *always* HEADER
+			mState = mOffset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
 		}
 	}
 
-	if (mState == HEADER)
+	// Third state / stage : read data from the header cache (texture.entries) file
+	if (!done && (mState == HEADER))
 	{
-#if USE_LFS_READ
-		if (mFileHandle == LLLFSThread::nullHandle())
-		{
-			llassert_always(idx >= 0);
-			llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
-			S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
-			S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-			llassert_always(mReadData == NULL);
-			mReadData = new U8[size];
-			mBytesRead = -1;
-			mBytesToRead = size;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-			mFileHandle = LLLFSThread::sLocal->read(mCache->mHeaderDataFileName,
-													mReadData, offset, mBytesToRead,
-													new ReadResponder(mCache, mRequestHandle));
-			return false;
-		}
-		else
-		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-// 					llwarns << "LLTextureCacheWorker: "  << mID
-// 							<< " incorrect number of bytes read from header: " << mBytesRead
-// 							<< " != " << mBytesToRead << llendl;
-					mDataSize = -1; // failed
-					return true;
-				}
-				if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
-				{
-					return true; // done
-				}
-				else
-				{
-					mFileHandle = LLLFSThread::nullHandle();
-					mState = BODY;
-				}
-			}
-			else
-			{
-				return false;
-			}
-		}
-#else
-		llassert_always(idx >= 0);
+		llassert_always(idx >= 0);	// we need an entry here or reading the header makes no sense
 		llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
 		S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
+		// Compute the size we need to read (in bytes)
 		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
+		size = llmin(size, mDataSize);
+		// Allocate the read buffer
 		mReadData = new U8[size];
 		S32 bytes_read = LLAPRFile::readEx(mCache->mHeaderDataFileName, 
 											 mReadData, offset, size, mCache->getLocalAPRFilePool());
 		if (bytes_read != size)
 		{
-// 			llwarns << "LLTextureCacheWorker: "  << mID
-// 					<< " incorrect number of bytes read from header: " << bytes_read
-// 					<< " / " << size << llendl;
+			llwarns << "LLTextureCacheWorker: "  << mID
+					<< " incorrect number of bytes read from header: " << bytes_read
+					<< " / " << size << llendl;
+			delete[] mReadData;
+			mReadData = NULL;
 			mDataSize = -1; // failed
-			return true;
+			done = true;
 		}
-		if (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE)
+		// If we already read all we expected, we're actually done
+		if (mDataSize <= bytes_read)
 		{
-			return true; // done
+			done = true;
 		}
 		else
 		{
 			mState = BODY;
 		}
-#endif
 	}
 
-	if (mState == BODY)
+	// Fourth state / stage : read the rest of the data from the UUID based cached file
+	if (!done && (mState == BODY))
 	{
-#if USE_LFS_READ
-		if (mFileHandle == LLLFSThread::nullHandle())
-		{
-			std::string filename = mCache->getTextureFileName(mID);
-			S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool());
-			if (filesize > mOffset)
-			{
-				S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
-				mDataSize = llmin(datasize, mDataSize);
-				S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-				data_offset = llmax(data_offset, 0);
-				S32 file_size = mDataSize - data_offset;
-				S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
-				file_offset = llmax(file_offset, 0);
-
-				llassert_always(mDataSize > 0);
-				U8* data = new U8[mDataSize];
-				if (data_offset > 0)
-				{
-					llassert_always(mReadData);
-					llassert_always(data_offset <= mDataSize);
-					memcpy(data, mReadData, data_offset);
-					delete[] mReadData;
-					mReadData = NULL;
-				}
-				llassert_always(mReadData == NULL);
-				mReadData = data;
-
-				mBytesRead = -1;
-				mBytesToRead = file_size;
-				setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-				llassert_always(data_offset + mBytesToRead <= mDataSize);
-				mFileHandle = LLLFSThread::sLocal->read(filename,
-														mReadData + data_offset, file_offset, mBytesToRead,
-														new ReadResponder(mCache, mRequestHandle));
-				return false;
-			}
-			else
-			{
-				mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
-				return true; // done
-			}
-		}
-		else
-		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-// 					llwarns << "LLTextureCacheWorker: "  << mID
-// 							<< " incorrect number of bytes read from body: " << mBytesRead
-// 							<< " != " << mBytesToRead << llendl;
-					mDataSize = -1; // failed
-				}
-				return true;
-			}
-			else
-			{
-				return false;
-			}
-		}
-#else
 		std::string filename = mCache->getTextureFileName(mID);
 		S32 filesize = LLAPRFile::size(filename, mCache->getLocalAPRFilePool());
-		S32 bytes_read = 0;
-		if (filesize > mOffset)
+
+		if (filesize && (filesize + TEXTURE_CACHE_ENTRY_SIZE) > mOffset)
 		{
-			S32 datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize;
-			mDataSize = llmin(datasize, mDataSize);
-			S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-			data_offset = llmax(data_offset, 0);
-			S32 file_size = mDataSize - data_offset;
-			S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
-			file_offset = llmax(file_offset, 0);
+			S32 max_datasize = TEXTURE_CACHE_ENTRY_SIZE + filesize - mOffset;
+			mDataSize = llmin(max_datasize, mDataSize);
+
+			S32 data_offset, file_size, file_offset;
 			
+			// Reserve the whole data buffer first
 			U8* data = new U8[mDataSize];
-			if (data_offset > 0)
+
+			// Set the data file pointers taking the read offset into account. 2 cases:
+			if (mOffset < TEXTURE_CACHE_ENTRY_SIZE)
 			{
+				// Offset within the header record. That means we read something from the header cache.
+				// Note: most common case is (mOffset = 0), so this is the "normal" code path.
+				data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;	// i.e. TEXTURE_CACHE_ENTRY_SIZE if mOffset nul (common case)
+				file_offset = 0;
+				file_size = mDataSize - data_offset;
+				// Copy the raw data we've been holding from the header cache into the new sized buffer
 				llassert_always(mReadData);
 				memcpy(data, mReadData, data_offset);
 				delete[] mReadData;
+				mReadData = NULL;
+			}
+			else
+			{
+				// Offset bigger than the header record. That means we haven't read anything yet.
+				data_offset = 0;
+				file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
+				file_size = mDataSize;
+				// No data from header cache to copy in that case, we skipped it all
 			}
+
+			// Now use that buffer as the object read buffer
+			llassert_always(mReadData == NULL);
 			mReadData = data;
-			bytes_read = LLAPRFile::readEx(filename, 
+
+			// Read the data at last
+			S32 bytes_read = LLAPRFile::readEx(filename, 
 											 mReadData + data_offset,
 											 file_offset, file_size,
 											 mCache->getLocalAPRFilePool());
 			if (bytes_read != file_size)
 			{
-// 				llwarns << "LLTextureCacheWorker: "  << mID
-// 						<< " incorrect number of bytes read from body: " << bytes_read
-// 						<< " / " << file_size << llendl;
+				llwarns << "LLTextureCacheWorker: "  << mID
+						<< " incorrect number of bytes read from body: " << bytes_read
+						<< " / " << file_size << llendl;
+				delete[] mReadData;
+				mReadData = NULL;
 				mDataSize = -1; // failed
-				return true;
+				done = true;
 			}
 		}
 		else
 		{
-			mDataSize = TEXTURE_CACHE_ENTRY_SIZE;
-		}
-		
-		return true;
-#endif
+			// No body, we're done.
+			mDataSize = llmax(TEXTURE_CACHE_ENTRY_SIZE - mOffset, 0);
+			lldebugs << "No body file for: " << filename << llendl;
+		}	
+		// Nothing else to do at that point...
+		done = true;
 	}
-	
-	return false;
+
+	// Clean up and exit
+	return done;
 }
 
+// This is where *everything* about a texture is written down in the cache system (entry map, header and body)
+// Current assumption are:
+// - the whole data are in a raw form, starting at mWriteData
+// - the size of this raw data is mDataSize and can be smaller than TEXTURE_CACHE_ENTRY_SIZE (the size of a record in the header cache)
+// - the code *does not* support offset writing so there are no difference between buffer addresses and start of data
 bool LLTextureCacheRemoteWorker::doWrite()
 {
+	bool done = false;
 	S32 idx = -1;
 
-	// No LOCAL state for write()
-	
+	// First state / stage : check that what we're trying to cache is in an OK shape
 	if (mState == INIT)
 	{
+		llassert_always(mOffset == 0);	// We currently do not support write offsets
+		llassert_always(mDataSize > 0); // Things will go badly wrong if mDataSize is nul or negative...
+		mState = CACHE;
+	}
+	
+	// No LOCAL state for write(): because it doesn't make much sense to cache a local file...
+
+	// Second state / stage : set an entry in the headers entry (texture.entries) file
+	if (!done && (mState == CACHE))
+	{
+		bool alreadyCached = false;
 		S32 cur_imagesize = 0;
-		S32 offset = mOffset;
-		idx = mCache->getHeaderCacheEntry(mID, false, &cur_imagesize);
-		if (idx >= 0 && cur_imagesize > 0)
+		// Checks if this image is already in the entry list
+		idx = mCache->getHeaderCacheEntry(mID, cur_imagesize);
+		if (idx >= 0 && (cur_imagesize >= 0))
 		{
-			offset = TEXTURE_CACHE_ENTRY_SIZE; // don't re-write header
+			alreadyCached = true;	// already there and non empty
 		}
-		idx = mCache->getHeaderCacheEntry(mID, true, &mImageSize); // touch entry
-		if (idx >= 0)
+		idx = mCache->setHeaderCacheEntry(mID, mImageSize); // create or touch the entry
+		if (idx < 0)
 		{
-			if(cur_imagesize > 0 && mImageSize != cur_imagesize)
-			{
-// 				llwarns << "Header cache entry size: " << cur_imagesize << " != mImageSize: " << mImageSize << llendl;
-				offset = 0; // re-write header
-			}
-			mState = offset < TEXTURE_CACHE_ENTRY_SIZE ? HEADER : BODY;
+			llwarns << "LLTextureCacheWorker: "  << mID
+					<< " Unable to create header entry for writing!" << llendl;
+			mDataSize = -1; // failed
+			done = true;
 		}
 		else
 		{
-			mDataSize = -1; // failed
-			return true;
+			if (cur_imagesize > 0 && (mImageSize != cur_imagesize))
+			{
+				alreadyCached = false; // re-write the header if the size changed in all cases
+			}
+			if (alreadyCached && (mDataSize <= TEXTURE_CACHE_ENTRY_SIZE))
+			{
+				// Small texture already cached case: we're done with writing
+				done = true;
+			}
+			else
+			{
+				// If the texture has already been cached, we don't resave the header and go directly to the body part
+				mState = alreadyCached ? BODY : HEADER;
+			}
 		}
 	}
-	
-	if (mState == HEADER)
+
+	// Third stage / state : write the header record in the header file (texture.cache)
+	if (!done && (mState == HEADER))
 	{
-#if USE_LFS_WRITE
-		if (mFileHandle == LLLFSThread::nullHandle())
+		llassert_always(idx >= 0);	// we need an entry here or storing the header makes no sense
+		S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE;	// skip to the correct spot in the header file
+		S32 size = TEXTURE_CACHE_ENTRY_SIZE;			// record size is fixed for the header
+		S32 bytes_written;
+
+		if (mDataSize < TEXTURE_CACHE_ENTRY_SIZE)
 		{
-			llassert_always(idx >= 0);
-			llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
-			S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
-			S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-			mBytesRead = -1;
-			mBytesToRead = size;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-			mFileHandle = LLLFSThread::sLocal->write(mCache->mHeaderDataFileName,
-													 mWriteData, offset, mBytesToRead,
-													 new WriteResponder(mCache, mRequestHandle));
-			return false;
+			// We need to write a full record in the header cache so, if the amount of data is smaller
+			// than a record, we need to transfer the data to a buffer padded with 0 and write that
+			U8* padBuffer = new U8[TEXTURE_CACHE_ENTRY_SIZE];
+			memset(padBuffer, 0, TEXTURE_CACHE_ENTRY_SIZE);		// Init with zeros
+			memcpy(padBuffer, mWriteData, mDataSize);			// Copy the write buffer
+			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, padBuffer, offset, size, mCache->getLocalAPRFilePool());
+			delete [] padBuffer;
 		}
 		else
 		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-// 					llwarns << "LLTextureCacheWorker: "  << mID
-// 							<< " incorrect number of bytes written to header: " << mBytesRead
-// 							<< " != " << mBytesToRead << llendl;
-					mDataSize = -1; // failed
-					return true;
-				}
-				if (mDataSize <=  mBytesToRead)
-				{
-					return true; // done
-				}
-				else
-				{
-					mFileHandle = LLLFSThread::nullHandle();
-					mState = BODY;
-				}
-			}
-			else
-			{
-				return false;
-			}
+			// Write the header record (== first TEXTURE_CACHE_ENTRY_SIZE bytes of the raw file) in the header file
+			bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool());
 		}
-#else
-		llassert_always(idx >= 0);
-		llassert_always(mOffset < TEXTURE_CACHE_ENTRY_SIZE);
-		S32 offset = idx * TEXTURE_CACHE_ENTRY_SIZE + mOffset;
-		S32 size = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-		S32 bytes_written = LLAPRFile::writeEx(mCache->mHeaderDataFileName, mWriteData, offset, size, mCache->getLocalAPRFilePool());		
 
 		if (bytes_written <= 0)
 		{
-// 			llwarns << "LLTextureCacheWorker: missing entry: " << mID << llendl;
+			llwarns << "LLTextureCacheWorker: "  << mID
+					<< " Unable to write header entry!" << llendl;
 			mDataSize = -1; // failed
-			return true;
+			done = true;
 		}
 
-		if (mDataSize <= size)
+		// If we wrote everything (may be more with padding) in the header cache, 
+		// we're done so we don't have a body to store
+		if (mDataSize <= bytes_written)
 		{
-			return true; // done
+			done = true;
 		}
 		else
 		{
 			mState = BODY;
 		}
-#endif
 	}
 	
-	if (mState == BODY)
+	// Fourth stage / state : write the body file, i.e. the rest of the texture in a "UUID" file name
+	if (!done && (mState == BODY))
 	{
-#if USE_LFS_WRITE
-		if (mFileHandle == LLLFSThread::nullHandle())
+		llassert(mDataSize > TEXTURE_CACHE_ENTRY_SIZE);	// wouldn't make sense to be here otherwise...
+		S32 file_size = mDataSize - TEXTURE_CACHE_ENTRY_SIZE;
+		if ((file_size > 0) && mCache->updateTextureEntryList(mID, file_size))
 		{
-			S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-			data_offset = llmax(data_offset, 0);
-			S32 file_size = mDataSize - data_offset;
-			S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
-			file_offset = llmax(file_offset, 0);
-			if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
-			{
-				std::string filename = mCache->getTextureFileName(mID);
-				mBytesRead = -1;
-				mBytesToRead = file_size;
-				setPriority(LLWorkerThread::PRIORITY_LOW | mPriority);
-				mFileHandle = LLLFSThread::sLocal->write(filename,
-														 mWriteData + data_offset, file_offset, mBytesToRead,
-														 new WriteResponder(mCache, mRequestHandle));
-				return false;
-			}
-			else
-			{
-				mDataSize = 0; // no data written
-				return true; // done
-			}
-		}
-		else
-		{
-			if (mBytesRead >= 0)
-			{
-				if (mBytesRead != mBytesToRead)
-				{
-// 					llwarns << "LLTextureCacheWorker: "  << mID
-// 							<< " incorrect number of bytes written to body: " << mBytesRead
-// 							<< " != " << mBytesToRead << llendl;
-					mDataSize = -1; // failed
-				}
-				return true;
-			}
-			else
-			{
-				return false;
-			}
-		}
-#else
-		S32 data_offset = TEXTURE_CACHE_ENTRY_SIZE - mOffset;
-		data_offset = llmax(data_offset, 0);
-		S32 file_size = mDataSize - data_offset;
-		S32 file_offset = mOffset - TEXTURE_CACHE_ENTRY_SIZE;
-		file_offset = llmax(file_offset, 0);
-		S32 bytes_written = 0;
-		if (file_size > 0 && mCache->appendToTextureEntryList(mID, file_size))
-		{
-			std::string filename = mCache->getTextureFileName(mID);
-			
-			bytes_written = LLAPRFile::writeEx(filename, 
-												 mWriteData + data_offset,
-												 file_offset, file_size,
-												 mCache->getLocalAPRFilePool());
+			// build the cache file name from the UUID
+			std::string filename = mCache->getTextureFileName(mID);			
+// 			llinfos << "Writing Body: " << filename << " Bytes: " << file_offset+file_size << llendl;
+			S32 bytes_written = LLAPRFile::writeEx(	filename, 
+													mWriteData + TEXTURE_CACHE_ENTRY_SIZE,
+													0, file_size,
+													mCache->getLocalAPRFilePool());
 			if (bytes_written <= 0)
 			{
+				llwarns << "LLTextureCacheWorker: "  << mID
+						<< " incorrect number of bytes written to body: " << bytes_written
+						<< " / " << file_size << llendl;
 				mDataSize = -1; // failed
+				done = true;
 			}
 		}
 		else
 		{
 			mDataSize = 0; // no data written
 		}
-
-		return true;
-#endif
+		// Nothing else to do at that point...
+		done = true;
 	}
-	
-	return false;
+
+	// Clean up and exit
+	return done;
 }
 
 //virtual
 bool LLTextureCacheWorker::doWork(S32 param)
 {
-// *TODO reenable disabled apr_pool usage disabled due to maint-render-9 merge breakage -brad
-	//allocate a new local apr_pool
-//	LLAPRPool pool ;
-
-	//save the current mFileAPRPool to avoid breaking anything.
-//	apr_pool_t* old_pool = mCache->getFileAPRPool() ;
-	//make mFileAPRPool to point to the local one
-//	mCache->setFileAPRPool(pool.getAPRPool()) ;
-
 	bool res = false;
 	if (param == 0) // read
 	{
@@ -818,10 +675,6 @@ bool LLTextureCacheWorker::doWork(S32 param)
 	{
 		llassert_always(0);
 	}
-
-	//set mFileAPRPool back, the local one will be released automatically.
-//	mCache->setFileAPRPool(old_pool) ;
-
 	return res;
 }
 
@@ -887,6 +740,7 @@ LLTextureCache::LLTextureCache(bool threaded)
 	  mWorkersMutex(NULL),
 	  mHeaderMutex(NULL),
 	  mListMutex(NULL),
+	  mHeaderAPRFile(NULL),
 	  mReadOnly(FALSE),
 	  mTexturesSizeTotal(0),
 	  mDoPurge(FALSE)
@@ -926,6 +780,9 @@ S32 LLTextureCache::update(U32 max_time_ms)
 		}
 	}
 
+	unlockWorkers(); 
+	
+	// call 'completed' with workers list unlocked (may call readComplete() or writeComplete()
 	for (responder_list_t::iterator iter1 = completed_list.begin();
 		 iter1 != completed_list.end(); ++iter1)
 	{
@@ -934,8 +791,6 @@ S32 LLTextureCache::update(U32 max_time_ms)
 		responder->completed(success);
 	}
 	
-	unlockWorkers();
-	
 	return res;
 }
 
@@ -954,33 +809,48 @@ std::string LLTextureCache::getTextureFileName(const LLUUID& id)
 {
 	std::string idstr = id.asString();
 	std::string delem = gDirUtilp->getDirDelimiter();
-	std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr;
+	std::string filename = mTexturesDirName + delem + idstr[0] + delem + idstr + ".texture";
 	return filename;
 }
 
-bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
+bool LLTextureCache::updateTextureEntryList(const LLUUID& id, S32 bodysize)
 {
 	bool res = false;
 	bool purge = false;
-	// Append UUID to end of texture entries
 	{
 		LLMutexLock lock(&mHeaderMutex);
-		size_map_t::iterator iter = mTexturesSizeMap.find(id);
-		if (iter == mTexturesSizeMap.end() || iter->second < bodysize)
+		size_map_t::iterator iter1 = mTexturesSizeMap.find(id);
+		if (iter1 == mTexturesSizeMap.end() || iter1->second < bodysize)
 		{
 			llassert_always(bodysize > 0);
-			Entry* entry = new Entry(id, bodysize, time(NULL));
 
-			LLAPRFile::writeEx(mTexturesDirEntriesFileName,
-								 (U8*)entry, -1, 1*sizeof(Entry),
-								 getLocalAPRFilePool());			
-			delete entry;
-			if (iter != mTexturesSizeMap.end())
+			S32 oldbodysize = 0;
+			if (iter1 != mTexturesSizeMap.end())
+			{
+				oldbodysize = iter1->second;
+			}
+						
+			Entry entry;
+			S32 idx = openAndReadEntry(id, entry, false);
+			if (idx < 0)
+			{
+				// TODO: change to llwarns
+				llerrs << "Failed to open entry: " << id << llendl;
+				removeFromCache(id);
+				return false;
+			}			
+			else if (oldbodysize != entry.mBodySize)
 			{
-				mTexturesSizeTotal -= iter->second;
+				// TODO: change to llwarns
+				llerrs << "Entry mismatch in mTextureSizeMap / mHeaderIDMap"
+					   << " idx=" << idx << " oldsize=" << oldbodysize << " entrysize=" << entry.mBodySize << llendl;
 			}
+			entry.mBodySize = bodysize;
+			writeEntryAndClose(idx, entry);
+			
+			mTexturesSizeTotal -= oldbodysize;
 			mTexturesSizeTotal += bodysize;
-			mTexturesSizeMap[id] = bodysize;
+			
 			if (mTexturesSizeTotal > sCacheMaxTexturesSize)
 			{
 				purge = true;
@@ -995,11 +865,59 @@ bool LLTextureCache::appendToTextureEntryList(const LLUUID& id, S32 bodysize)
 	return res;
 }
 
+//debug
+BOOL LLTextureCache::isInCache(const LLUUID& id) 
+{
+	LLMutexLock lock(&mHeaderMutex);
+	id_map_t::const_iterator iter = mHeaderIDMap.find(id);
+	
+	return (iter != mHeaderIDMap.end()) ;
+}
+
+//debug
+BOOL LLTextureCache::isInLocal(const LLUUID& id) 
+{
+	S32 local_size = 0;
+	std::string local_filename;
+	
+	std::string filename = getLocalFileName(id);	
+	// Is it a JPEG2000 file? 
+	{
+		local_filename = filename + ".j2c";
+		local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
+		if (local_size > 0)
+		{
+			return TRUE ;
+		}
+	}
+		
+	// If not, is it a jpeg file?		
+	{
+		local_filename = filename + ".jpg";
+		local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
+		if (local_size > 0)
+		{
+			return TRUE ;
+		}
+	}
+		
+	// Hmm... What about a targa file? (used for UI texture mostly)		
+	{
+		local_filename = filename + ".tga";
+		local_size = LLAPRFile::size(local_filename, getLocalAPRFilePool());
+		if (local_size > 0)
+		{
+			return TRUE ;
+		}
+	}
+		
+	return FALSE ;
+}
 //////////////////////////////////////////////////////////////////////////////
 
 //static
 const S32 MAX_REASONABLE_FILE_SIZE = 512*1024*1024; // 512 MB
-F32 LLTextureCache::sHeaderCacheVersion = 1.0f;
+F32 LLTextureCache::sHeaderCacheVersion = 1.3f;
 U32 LLTextureCache::sCacheMaxEntries = MAX_REASONABLE_FILE_SIZE / TEXTURE_CACHE_ENTRY_SIZE;
 S64 LLTextureCache::sCacheMaxTexturesSize = 0; // no limit
 const char* entries_filename = "texture.entries";
@@ -1012,7 +930,6 @@ void LLTextureCache::setDirNames(ELLPath location)
 	mHeaderEntriesFileName = gDirUtilp->getExpandedFilename(location, entries_filename);
 	mHeaderDataFileName = gDirUtilp->getExpandedFilename(location, cache_filename);
 	mTexturesDirName = gDirUtilp->getExpandedFilename(location, textures_dirname);
-	mTexturesDirEntriesFileName = mTexturesDirName + delem + entries_filename;
 }
 
 void LLTextureCache::purgeCache(ELLPath location)
@@ -1020,7 +937,7 @@ void LLTextureCache::purgeCache(ELLPath location)
 	if (!mReadOnly)
 	{
 		setDirNames(location);
-	
+		llassert_always(mHeaderAPRFile == NULL);
 		LLAPRFile::remove(mHeaderEntriesFileName, getLocalAPRFilePool());
 		LLAPRFile::remove(mHeaderDataFileName, getLocalAPRFilePool());
 	}
@@ -1063,83 +980,317 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL read_only)
 	return max_size; // unused cache space
 }
 
-struct lru_data
+//----------------------------------------------------------------------------
+// mHeaderMutex must be locked for the following functions!
+
+LLAPRFile* LLTextureCache::openHeaderEntriesFile(bool readonly, S32 offset)
+{
+	llassert_always(mHeaderAPRFile == NULL);
+	apr_int32_t flags = readonly ? APR_READ|APR_BINARY : APR_READ|APR_WRITE|APR_BINARY;
+	mHeaderAPRFile = new LLAPRFile(mHeaderEntriesFileName, flags, getLocalAPRFilePool());
+	mHeaderAPRFile->seek(APR_SET, offset);
+	return mHeaderAPRFile;
+}
+
+void LLTextureCache::closeHeaderEntriesFile()
+{
+	llassert_always(mHeaderAPRFile != NULL);
+	delete mHeaderAPRFile;
+	mHeaderAPRFile = NULL;
+}
+
+void LLTextureCache::readEntriesHeader()
+{
+	// mHeaderEntriesInfo initializes to default values so safe not to read it
+		llassert_always(mHeaderAPRFile == NULL);
+	if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool()))
+	{
+		LLAPRFile::readEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
+						  getLocalAPRFilePool());
+	}
+}
+
+void LLTextureCache::writeEntriesHeader()
 {
-	lru_data(U32 t, S32 i, const LLUUID& id) { time=t; index=i; uuid=id; }
-	U32 time;
-	S32 index;
-	LLUUID uuid;
-	struct Compare
-	{
-		// lhs < rhs
-		typedef const lru_data* lru_data_ptr;
-		bool operator()(const lru_data_ptr& a, const lru_data_ptr& b) const
+	llassert_always(mHeaderAPRFile == NULL);
+	if (!mReadOnly)
+	{
+		LLAPRFile::writeEx(mHeaderEntriesFileName, (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
+						   getLocalAPRFilePool());
+	}
+}
+
+static S32 mHeaderEntriesMaxWriteIdx = 0;
+
+S32 LLTextureCache::openAndReadEntry(const LLUUID& id, Entry& entry, bool create)
+{
+	S32 idx = -1;
+	
+	id_map_t::iterator iter1 = mHeaderIDMap.find(id);
+	if (iter1 != mHeaderIDMap.end())
+	{
+		idx = iter1->second;
+	}
+
+	if (idx < 0)
+	{
+		if (create && !mReadOnly)
 		{
-			if(a->time == b->time)
-				return (a->index < b->index);
+			if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
+			{
+				// Add an entry to the end of the list
+				idx = mHeaderEntriesInfo.mEntries++;
+
+			}
+			else if (!mFreeList.empty())
+			{
+				idx = *(mFreeList.begin());
+				mFreeList.erase(mFreeList.begin());
+			}
 			else
-				return (a->time >= b->time);
+			{
+				// Look for a still valid entry in the LRU
+				for (std::set<LLUUID>::iterator iter2 = mLRU.begin(); iter2 != mLRU.end();)
+				{
+					std::set<LLUUID>::iterator curiter2 = iter2++;
+					LLUUID oldid = *curiter2;
+					// Erase entry from LRU regardless
+					mLRU.erase(curiter2);
+					// Look up entry and use it if it is valid
+					id_map_t::iterator iter3 = mHeaderIDMap.find(oldid);
+					if (iter3 != mHeaderIDMap.end() && iter3->second >= 0)
+					{
+						idx = iter3->second;
+						mHeaderIDMap.erase(oldid);
+						mTexturesSizeMap.erase(oldid);
+						break;
+					}
+				}
+				// if (idx < 0) at this point, we will rebuild the LRU 
+				//  and retry if called from setHeaderCacheEntry(),
+				//  otherwise this shouldn't happen and will trigger an error
+			}
+			if (idx >= 0)
+			{
+				// Set the header index
+				mHeaderIDMap[id] = idx;
+				llassert_always(mTexturesSizeMap.erase(id) == 0);
+				// Initialize the entry (will get written later)
+				entry.init(id, time(NULL));
+				// Update Header
+				writeEntriesHeader();
+				// Write Entry
+				S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+				LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
+				S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
+				llassert_always(bytes_written == sizeof(Entry));
+				mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
+				closeHeaderEntriesFile();
+			}
 		}
-	};				
-};
+	}
+	else
+	{
+		// Remove this entry from the LRU if it exists
+		mLRU.erase(id);
+		// Read the entry
+		S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+		LLAPRFile* aprfile = openHeaderEntriesFile(true, offset);
+		S32 bytes_read = aprfile->read((void*)&entry, (S32)sizeof(Entry));
+		llassert_always(bytes_read == sizeof(Entry));
+		llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
+		closeHeaderEntriesFile();
+	}
+	return idx;
+}
+
+void LLTextureCache::writeEntryAndClose(S32 idx, Entry& entry)
+{
+	if (idx >= 0)
+	{
+		if (!mReadOnly)
+		{
+			entry.mTime = time(NULL);
+			llassert_always(entry.mImageSize == 0 || entry.mImageSize == -1 || entry.mImageSize > entry.mBodySize);
+			if (entry.mBodySize > 0)
+			{
+				mTexturesSizeMap[entry.mID] = entry.mBodySize;
+			}
+// 			llinfos << "Updating TE: " << idx << ": " << id << " Size: " << entry.mBodySize << " Time: " << entry.mTime << llendl;
+			S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+			LLAPRFile* aprfile = openHeaderEntriesFile(false, offset);
+			S32 bytes_written = aprfile->write((void*)&entry, (S32)sizeof(Entry));
+			llassert_always(bytes_written == sizeof(Entry));
+			mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, idx);
+			closeHeaderEntriesFile();
+		}
+	}
+}
+
+U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)
+{
+	U32 num_entries = mHeaderEntriesInfo.mEntries;
+
+	mHeaderIDMap.clear();
+	mTexturesSizeMap.clear();
+	mFreeList.clear();
+	mTexturesSizeTotal = 0;
+
+	LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
+	for (U32 idx=0; idx<num_entries; idx++)
+	{
+		Entry entry;
+		S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry));
+		if (bytes_read < sizeof(Entry))
+		{
+			llwarns << "Corrupted header entries, failed at " << idx << " / " << num_entries << llendl;
+			closeHeaderEntriesFile();
+			purgeAllTextures(false);
+			return 0;
+		}
+		entries.push_back(entry);
+// 		llinfos << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << llendl;
+		if (entry.mImageSize < 0)
+		{
+			mFreeList.insert(idx);
+		}
+		else
+		{
+			mHeaderIDMap[entry.mID] = idx;
+			if (entry.mBodySize > 0)
+			{
+				mTexturesSizeMap[entry.mID] = entry.mBodySize;
+				mTexturesSizeTotal += entry.mBodySize;
+			}
+			llassert_always(entry.mImageSize == 0 || entry.mImageSize > entry.mBodySize);
+		}
+	}
+	closeHeaderEntriesFile();
+	return num_entries;
+}
+
+void LLTextureCache::writeEntriesAndClose(const std::vector<Entry>& entries)
+{
+	S32 num_entries = entries.size();
+	llassert_always(num_entries == mHeaderEntriesInfo.mEntries);
+	
+	if (!mReadOnly)
+	{
+		LLAPRFile* aprfile = openHeaderEntriesFile(false, (S32)sizeof(EntriesInfo));
+		for (S32 idx=0; idx<num_entries; idx++)
+		{
+			S32 bytes_written = aprfile->write((void*)(&entries[idx]), (S32)sizeof(Entry));
+			llassert_always(bytes_written == sizeof(Entry));
+		}
+		mHeaderEntriesMaxWriteIdx = llmax(mHeaderEntriesMaxWriteIdx, num_entries-1);
+		closeHeaderEntriesFile();
+	}
+}
+
+//----------------------------------------------------------------------------
 
 // Called from either the main thread or the worker thread
 void LLTextureCache::readHeaderCache()
 {
 	LLMutexLock lock(&mHeaderMutex);
-	mHeaderEntriesInfo.mVersion = 0.f;
-	mHeaderEntriesInfo.mEntries = 0;
-	if (LLAPRFile::isExist(mHeaderEntriesFileName, getLocalAPRFilePool()))
-	{
-		LLAPRFile::readEx(mHeaderEntriesFileName,
-							(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
-							getLocalAPRFilePool());
-	}
+
+	mLRU.clear(); // always clear the LRU
+
+	readEntriesHeader();
+	
 	if (mHeaderEntriesInfo.mVersion != sHeaderCacheVersion)
 	{
 		if (!mReadOnly)
 		{
-			// Info with 0 entries
-			mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
-
-			LLAPRFile::writeEx(mHeaderEntriesFileName, 
-								 (U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
-								 getLocalAPRFilePool());
+			purgeAllTextures(false);
 		}
 	}
 	else
 	{
-		S32 num_entries = mHeaderEntriesInfo.mEntries;
+		std::vector<Entry> entries;
+		U32 num_entries = openAndReadEntries(entries);
 		if (num_entries)
 		{
-			Entry* entries = new Entry[num_entries];
+			U32 empty_entries = 0;
+			typedef std::pair<U32, LLUUID> lru_data_t;
+			std::set<lru_data_t> lru;
+			std::vector<LLUUID> purge_list;
+			for (U32 i=0; i<num_entries; i++)
+			{
+				Entry& entry = entries[i];
+				const LLUUID& id = entry.mID;
+				if (entry.mImageSize < 0)
+				{
+					// This will be in the Free List, don't put it in the LRY
+					++empty_entries;
+				}
+				else
+				{
+					lru.insert(std::make_pair(entry.mTime, id));
+					if (entry.mBodySize > 0)
+					{
+						if (entry.mBodySize > entry.mImageSize)
+						{
+							// Shouldn't happen, failsafe only
+							llwarns << "Bad entry: " << i << ": " << id << ": BodySize: " << entry.mBodySize << llendl;
+							purge_list.push_back(id);
+						}
+					}
+				}
+			}
+			if (num_entries > sCacheMaxEntries)
+			{
+				// Special case: cache size was reduced, need to remove entries
+				// Note: After we prune entries, we will call this again and create the LRU
+				U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries;
+				if (entries_to_purge > 0)
+				{
+					for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
+					{
+						purge_list.push_back(iter->second);
+						if (--entries_to_purge <= 0)
+							break;
+					}
+				}
+			}
+			else
 			{
-				LLAPRFile::readEx(mHeaderEntriesFileName, 
-								(U8*)entries, sizeof(EntriesInfo), num_entries*sizeof(Entry),
-								getLocalAPRFilePool());
+				S32 lru_entries = (S32)((F32)sCacheMaxEntries * TEXTURE_CACHE_LRU_SIZE);
+				for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
+				{
+					mLRU.insert(iter->second);
+// 					llinfos << "LRU: " << iter->first << " : " << iter->second << llendl;
+					if (--lru_entries <= 0)
+						break;
+				}
 			}
-			typedef std::set<lru_data*, lru_data::Compare> lru_set_t;
-			lru_set_t lru;
-			for (S32 i=0; i<num_entries; i++)
+			
+			if (purge_list.size() > 0)
 			{
-				if (entries[i].mSize >= 0) // -1 indicates erased entry, skip
+				for (std::vector<LLUUID>::iterator iter = purge_list.begin(); iter != purge_list.end(); ++iter)
 				{
-					const LLUUID& id = entries[i].mID;
-					lru.insert(new lru_data(entries[i].mTime, i, id));
-					mHeaderIDMap[id] = i;
+					removeFromCache(*iter);
 				}
+				// If we removed any entries, we need to rebuild the entries list,
+				// write the header, and call this again
+				std::vector<Entry> new_entries;
+				for (U32 i=0; i<num_entries; i++)
+				{
+					const Entry& entry = entries[i];
+					if (entry.mImageSize >=0)
+					{
+						new_entries.push_back(entry);
+					}
+				}
+				llassert_always(new_entries.size() <= sCacheMaxEntries);
+				mHeaderEntriesInfo.mEntries = new_entries.size();
+				writeEntriesAndClose(new_entries);
+				readHeaderCache(); // repeat with new entries file
 			}
-			mLRU.clear();
-			S32 lru_entries = sCacheMaxEntries / 10;
-			for (lru_set_t::iterator iter = lru.begin(); iter != lru.end(); ++iter)
+			else
 			{
-				lru_data* data = *iter;
-				mLRU[data->index] = data->uuid;
-				if (--lru_entries <= 0)
-					break;
+				writeEntriesAndClose(entries);
 			}
-			for_each(lru.begin(), lru.end(), DeletePointer());
-			delete[] entries;
 		}
 	}
 }
@@ -1162,13 +1313,21 @@ void LLTextureCache::purgeAllTextures(bool purge_directories)
 				LLFile::rmdir(dirname);
 			}
 		}
-		LLAPRFile::remove(mTexturesDirEntriesFileName, getLocalAPRFilePool());
 		if (purge_directories)
 		{
 			LLFile::rmdir(mTexturesDirName);
 		}
 	}
+	mHeaderIDMap.clear();
 	mTexturesSizeMap.clear();
+	mTexturesSizeTotal = 0;
+	mFreeList.clear();
+	mTexturesSizeTotal = 0;
+
+	// Info with 0 entries
+	mHeaderEntriesInfo.mVersion = sHeaderCacheVersion;
+	mHeaderEntriesInfo.mEntries = 0;
+	writeEntriesHeader();
 }
 
 void LLTextureCache::purgeTextures(bool validate)
@@ -1182,51 +1341,37 @@ void LLTextureCache::purgeTextures(bool validate)
 	LLAppViewer::instance()->pauseMainloopTimeout();
 
 	LLMutexLock lock(&mHeaderMutex);
-	
-	S32 filesize = LLAPRFile::size(mTexturesDirEntriesFileName, getLocalAPRFilePool());
-	S32 num_entries = filesize / sizeof(Entry);
-	if (num_entries * (S32)sizeof(Entry) != filesize)
-	{
-		LL_WARNS("TextureCache") << "Bad cache file: " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL;
-		purgeAllTextures(false);
-		return;
-	}
-	if (num_entries == 0)
+
+	llinfos << "TEXTURE CACHE: Purging." << llendl;
+
+	// Read the entries list
+	std::vector<Entry> entries;
+	U32 num_entries = openAndReadEntries(entries);
+	if (!num_entries)
 	{
-		return; // nothing to do
+		writeEntriesAndClose(entries);
+		return; // nothing to purge
 	}
 	
-	Entry* entries = new Entry[num_entries];
-	S32 bytes_read = LLAPRFile::readEx(mTexturesDirEntriesFileName, 
-										 (U8*)entries, 0, num_entries*sizeof(Entry),
-										 getLocalAPRFilePool());	
-	if (bytes_read != filesize)
-	{
-		LL_WARNS("TextureCache") << "Bad cache file (2): " << mTexturesDirEntriesFileName << " Purging." << LL_ENDL;
-		purgeAllTextures(false);
-		return;
-	}
-	
-	LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Reading Entries..." << LL_ENDL;
-	
-	std::map<LLUUID, S32> entry_idx_map;
-	S64 total_size = 0;
-	for (S32 idx=0; idx<num_entries; idx++)
-	{
-		const LLUUID& id = entries[idx].mID;
- 		LL_DEBUGS("TextureCache") << "Entry: " << id << " Size: " << entries[idx].mSize << " Time: " << entries[idx].mTime << LL_ENDL;
-		std::map<LLUUID, S32>::iterator iter = entry_idx_map.find(id);
-		if (iter != entry_idx_map.end())
+	// Use mTexturesSizeMap to collect UUIDs of textures with bodies
+	typedef std::set<std::pair<U32,S32> > time_idx_set_t;
+	std::set<std::pair<U32,S32> > time_idx_set;
+	for (size_map_t::iterator iter1 = mTexturesSizeMap.begin();
+		 iter1 != mTexturesSizeMap.end(); ++iter1)
+	{
+		if (iter1->second > 0)
 		{
-			// Newer entry replacing older entry
-			S32 pidx = iter->second;
-			total_size -= entries[pidx].mSize;
-			entries[pidx].mSize = 0; // flag: skip older entry
+			id_map_t::iterator iter2 = mHeaderIDMap.find(iter1->first);
+			if (iter2 != mHeaderIDMap.end())
+			{
+				S32 idx = iter2->second;
+				time_idx_set.insert(std::make_pair(entries[idx].mTime, idx));
+// 				llinfos << "TIME: " << entries[idx].mTime << " TEX: " << entries[idx].mID << " IDX: " << idx << " Size: " << entries[idx].mImageSize << llendl;
+			}
 		}
-		entry_idx_map[id] = idx;
-		total_size += entries[idx].mSize;
 	}
-
+	
+	// Validate 1/256th of the files on startup
 	U32 validate_idx = 0;
 	if (validate)
 	{
@@ -1235,19 +1380,17 @@ void LLTextureCache::purgeTextures(bool validate)
 		gSavedSettings.setU32("CacheValidateCounter", next_idx);
 		LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL;
 	}
-	
-	S64 min_cache_size = (sCacheMaxTexturesSize * 9) / 10;
+
+	S64 cache_size = mTexturesSizeTotal;
+	S64 purged_cache_size = (sCacheMaxTexturesSize * (S64)((1.f-TEXTURE_CACHE_PURGE_AMOUNT)*100)) / 100;
 	S32 purge_count = 0;
-	S32 next_idx = 0;
-	for (S32 idx=0; idx<num_entries; idx++)
+	for (time_idx_set_t::iterator iter = time_idx_set.begin();
+		 iter != time_idx_set.end(); ++iter)
 	{
-		if (entries[idx].mSize == 0)
-		{
-			continue;
-		}
+		S32 idx = iter->second;
 		bool purge_entry = false;
 		std::string filename = getTextureFileName(entries[idx].mID);
-		if (total_size >= min_cache_size)
+		if (cache_size >= purged_cache_size)
 		{
 			purge_entry = true;
 		}
@@ -1257,60 +1400,44 @@ void LLTextureCache::purgeTextures(bool validate)
 			U32 uuididx = entries[idx].mID.mData[0];
 			if (uuididx == validate_idx)
 			{
- 				LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mSize << LL_ENDL;
+ 				LL_DEBUGS("TextureCache") << "Validating: " << filename << "Size: " << entries[idx].mBodySize << LL_ENDL;
 				S32 bodysize = LLAPRFile::size(filename, getLocalAPRFilePool());
-				if (bodysize != entries[idx].mSize)
+				if (bodysize != entries[idx].mBodySize)
 				{
-					LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mSize
+					LL_WARNS("TextureCache") << "TEXTURE CACHE BODY HAS BAD SIZE: " << bodysize << " != " << entries[idx].mBodySize
 							<< filename << LL_ENDL;
 					purge_entry = true;
 				}
 			}
 		}
+		else
+		{
+			break;
+		}
+		
 		if (purge_entry)
 		{
 			purge_count++;
 	 		LL_DEBUGS("TextureCache") << "PURGING: " << filename << LL_ENDL;
 			LLAPRFile::remove(filename, getLocalAPRFilePool());
-			total_size -= entries[idx].mSize;
-			entries[idx].mSize = 0;
-		}
-		else
-		{
-			if (next_idx != idx)
-			{
-				entries[next_idx] = entries[idx];
-			}
-			++next_idx;
+			cache_size -= entries[idx].mBodySize;
+			mTexturesSizeTotal -= entries[idx].mBodySize;
+			entries[idx].mBodySize = 0;
+			mTexturesSizeMap.erase(entries[idx].mID);
 		}
 	}
-	num_entries = next_idx;
 
 	LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Writing Entries: " << num_entries << LL_ENDL;
-	
-	LLAPRFile::remove(mTexturesDirEntriesFileName, getLocalAPRFilePool());
-	LLAPRFile::writeEx(mTexturesDirEntriesFileName, 
-						 (U8*)&entries[0], 0, num_entries*sizeof(Entry),
-						 getLocalAPRFilePool());
-	
-	mTexturesSizeTotal = 0;
-	mTexturesSizeMap.clear();
-	for (S32 idx=0; idx<num_entries; idx++)
-	{
-		mTexturesSizeMap[entries[idx].mID] = entries[idx].mSize;
-		mTexturesSizeTotal += entries[idx].mSize;
-	}
-	llassert(mTexturesSizeTotal == total_size);
-	
-	delete[] entries;
 
+	writeEntriesAndClose(entries);
+	
 	// *FIX:Mani - watchdog back on.
 	LLAppViewer::instance()->resumeMainloopTimeout();
 	
 	LL_INFOS("TextureCache") << "TEXTURE CACHE:"
 			<< " PURGED: " << purge_count
 			<< " ENTRIES: " << num_entries
-			<< " CACHE SIZE: " << total_size / 1024*1024 << " MB"
+			<< " CACHE SIZE: " << mTexturesSizeTotal / 1024*1024 << " MB"
 			<< llendl;
 }
 
@@ -1340,78 +1467,39 @@ LLTextureCacheWorker* LLTextureCache::getWriter(handle_t handle)
 }
 
 //////////////////////////////////////////////////////////////////////////////
-
 // Called from work thread
-S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize)
-{
-	bool retry = false;
-	S32 idx = -1;
 
+// Reads imagesize from the header, updates timestamp
+S32 LLTextureCache::getHeaderCacheEntry(const LLUUID& id, S32& imagesize)
+{
+	LLMutexLock lock(&mHeaderMutex);
+	Entry entry;
+	S32 idx = openAndReadEntry(id, entry, false);
+	if (idx >= 0)
 	{
-		LLMutexLock lock(&mHeaderMutex);
-		id_map_t::iterator iter = mHeaderIDMap.find(id);
-		if (iter != mHeaderIDMap.end())
-		{
-			idx = iter->second;
-		}
-		else if (touch && !mReadOnly)
-		{
-			if (mHeaderEntriesInfo.mEntries < sCacheMaxEntries)
-			{
-				// Add an entry
-				idx = mHeaderEntriesInfo.mEntries++;
-				mHeaderIDMap[id] = idx;
-				// Update Info
-				LLAPRFile::writeEx(mHeaderEntriesFileName, 
-									(U8*)&mHeaderEntriesInfo, 0, sizeof(EntriesInfo),
-									getLocalAPRFilePool());
-			}
-			else if (!mLRU.empty())
-			{
-				idx = mLRU.begin()->first; // will be erased below
-				const LLUUID& oldid = mLRU.begin()->second;
-				mHeaderIDMap.erase(oldid);
-				mTexturesSizeMap.erase(oldid);
-				mHeaderIDMap[id] = idx;
-			}
-			else
-			{
-				idx = -1;
-				retry = true;
-			}
-		}
-		if (idx >= 0)
-		{
-			if (touch && !mReadOnly)
-			{
-				// Update the lru entry
-				mLRU.erase(idx);
-				llassert_always(imagesize && *imagesize > 0);
-				Entry* entry = new Entry(id, *imagesize, time(NULL));
-				S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
-				LLAPRFile::writeEx(mHeaderEntriesFileName, 
-									 (U8*)entry, offset, sizeof(Entry),
-									 getLocalAPRFilePool());
-				delete entry;
-			}
-			else if (imagesize)
-			{
-				// Get the image size
-				Entry entry;
-				S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
+		imagesize = entry.mImageSize;
+		writeEntryAndClose(idx, entry); // updates time
+	}
+	return idx;
+}
 
-				LLAPRFile::readEx(mHeaderEntriesFileName, 
-									(U8*)&entry, offset, sizeof(Entry),
-									getLocalAPRFilePool());
-				*imagesize = entry.mSize;
-			}
-		}
+// Writes imagesize to the header, updates timestamp
+S32 LLTextureCache::setHeaderCacheEntry(const LLUUID& id, S32 imagesize)
+{
+	LLMutexLock lock(&mHeaderMutex);
+	llassert_always(imagesize >= 0);
+	Entry entry;
+	S32 idx = openAndReadEntry(id, entry, true);
+	if (idx >= 0)
+	{
+		entry.mImageSize = imagesize;
+		writeEntryAndClose(idx, entry);
 	}
-	if (retry)
+	else // retry
 	{
-		readHeaderCache(); // updates the lru
+		readHeaderCache(); // We couldn't write an entry, so refresh the LRU
 		llassert_always(!mLRU.empty() || mHeaderEntriesInfo.mEntries < sCacheMaxEntries);
-		idx = getHeaderCacheEntry(id, touch, imagesize); // assert above ensures no inf. recursion
+		idx = setHeaderCacheEntry(id, imagesize); // assert above ensures no inf. recursion
 	}
 	return idx;
 }
@@ -1427,8 +1515,8 @@ LLTextureCache::handle_t LLTextureCache::readFromCache(const std::string& filena
 	//  so let the thread handle it
 	LLMutexLock lock(&mWorkersMutex);
 	LLTextureCacheWorker* worker = new LLTextureCacheLocalFileWorker(this, priority, filename, id,
-															NULL, size, offset, 0,
-															responder);
+																	 NULL, size, offset, 0,
+																	 responder);
 	handle_t handle = worker->read();
 	mReaders[handle] = worker;
 	return handle;
@@ -1441,8 +1529,8 @@ LLTextureCache::handle_t LLTextureCache::readFromCache(const LLUUID& id, U32 pri
 	//  so let the thread handle it
 	LLMutexLock lock(&mWorkersMutex);
 	LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
-															NULL, size, offset, 0,
-															responder);
+																  NULL, size, offset,
+																  0, responder);
 	handle_t handle = worker->read();
 	mReaders[handle] = worker;
 	return handle;
@@ -1453,7 +1541,7 @@ bool LLTextureCache::readComplete(handle_t handle, bool abort)
 {
 	lockWorkers();
 	handle_map_t::iterator iter = mReaders.find(handle);
-	llassert_always(iter != mReaders.end());
+	llassert_always(iter != mReaders.end() || abort);
 	LLTextureCacheWorker* worker = iter->second;
 	bool res = worker->complete();
 	if (res || abort)
@@ -1487,19 +1575,13 @@ LLTextureCache::handle_t LLTextureCache::writeToCache(const LLUUID& id, U32 prio
 		purgeTextures(false);
 		mDoPurge = FALSE;
 	}
-	if (datasize >= TEXTURE_CACHE_ENTRY_SIZE)
-	{
-		LLMutexLock lock(&mWorkersMutex);
-		llassert_always(imagesize > 0);
-		LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
-																data, datasize, 0,
-																imagesize, responder);
-		handle_t handle = worker->write();
-		mWriters[handle] = worker;
-		return handle;
-	}
-	delete responder;
-	return LLWorkerThread::nullHandle();
+	LLMutexLock lock(&mWorkersMutex);
+	LLTextureCacheWorker* worker = new LLTextureCacheRemoteWorker(this, priority, id,
+																  data, datasize, 0,
+																  imagesize, responder);
+	handle_t handle = worker->write();
+	mWriters[handle] = worker;
+	return handle;
 }
 
 bool LLTextureCache::writeComplete(handle_t handle, bool abort)
@@ -1542,25 +1624,17 @@ void LLTextureCache::addCompleted(Responder* responder, bool success)
 
 bool LLTextureCache::removeHeaderCacheEntry(const LLUUID& id)
 {
-	if (mReadOnly)
-	{
-		return false;
-	}
-	LLMutexLock lock(&mHeaderMutex);
-	id_map_t::iterator iter = mHeaderIDMap.find(id);
-	if (iter != mHeaderIDMap.end())
+	if (!mReadOnly)
 	{
-		S32 idx = iter->second;
+		LLMutexLock lock(&mHeaderMutex);
+		Entry entry;
+		S32 idx = openAndReadEntry(id, entry, false);
 		if (idx >= 0)
 		{
-			Entry* entry = new Entry(id, -1, time(NULL));
-			S32 offset = sizeof(EntriesInfo) + idx * sizeof(Entry);
-
-			LLAPRFile::writeEx(mHeaderEntriesFileName,
-								 (U8*)entry, offset, sizeof(Entry),
-								 getLocalAPRFilePool());			
-			delete entry;
-			mLRU[idx] = id;
+			entry.mImageSize = -1;
+			entry.mBodySize = 0;
+			writeEntryAndClose(idx, entry);
+			mFreeList.insert(idx);
 			mHeaderIDMap.erase(id);
 			mTexturesSizeMap.erase(id);
 			return true;
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index 68b1458e9a80e0443802543cd4babe37114aea81..bc9c988648baeca9bdfdabbf7bf2a86397f67b73 100644
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -48,6 +48,27 @@ class LLTextureCache : public LLWorkerThread
 	friend class LLTextureCacheRemoteWorker;
 	friend class LLTextureCacheLocalFileWorker;
 
+private:
+	// Entries
+	struct EntriesInfo
+	{
+		EntriesInfo() : mVersion(0.f), mEntries(0) {}
+		F32 mVersion;
+		U32 mEntries;
+	};
+	struct Entry
+	{
+		Entry() {}
+		Entry(const LLUUID& id, S32 imagesize, S32 bodysize, U32 time) :
+			mID(id), mImageSize(imagesize), mBodySize(bodysize), mTime(time) {}
+		void init(const LLUUID& id, U32 time) { mID = id, mImageSize = 0; mBodySize = 0; mTime = time; }
+		LLUUID mID; // 16 bytes
+		S32 mImageSize; // total size of image if known
+		S32 mBodySize; // size of body file in body cache
+		U32 mTime; // seconds since 1/1/1970
+	};
+
+	
 public:
 
 	class Responder : public LLResponder
@@ -106,10 +127,16 @@ class LLTextureCache : public LLWorkerThread
 	// debug
 	S32 getNumReads() { return mReaders.size(); }
 	S32 getNumWrites() { return mWriters.size(); }
+	S64 getUsage() { return mTexturesSizeTotal; }
+	S64 getMaxUsage() { return sCacheMaxTexturesSize; }
+	U32 getEntries() { return mHeaderEntriesInfo.mEntries; }
+	U32 getMaxEntries() { return sCacheMaxEntries; };
+	BOOL isInCache(const LLUUID& id) ;
+	BOOL isInLocal(const LLUUID& id) ;
 
 protected:
 	// Accessed by LLTextureCacheWorker
-	bool appendToTextureEntryList(const LLUUID& id, S32 size);
+	bool updateTextureEntryList(const LLUUID& id, S32 size);
 	std::string getLocalFileName(const LLUUID& id);
 	std::string getTextureFileName(const LLUUID& id);
 	void addCompleted(Responder* responder, bool success);
@@ -122,7 +149,16 @@ class LLTextureCache : public LLWorkerThread
 	void readHeaderCache();
 	void purgeAllTextures(bool purge_directories);
 	void purgeTextures(bool validate);
-	S32 getHeaderCacheEntry(const LLUUID& id, bool touch, S32* imagesize = NULL);
+	LLAPRFile* openHeaderEntriesFile(bool readonly, S32 offset);
+	void closeHeaderEntriesFile();
+	void readEntriesHeader();
+	void writeEntriesHeader();
+	S32 openAndReadEntry(const LLUUID& id, Entry& entry, bool create);
+	void writeEntryAndClose(S32 idx, Entry& entry);
+	U32 openAndReadEntries(std::vector<Entry>& entries);
+	void writeEntriesAndClose(const std::vector<Entry>& entries);
+	S32 getHeaderCacheEntry(const LLUUID& id, S32& imagesize);
+	S32 setHeaderCacheEntry(const LLUUID& id, S32 imagesize);
 	bool removeHeaderCacheEntry(const LLUUID& id);
 	void lockHeaders() { mHeaderMutex.lock(); }
 	void unlockHeaders() { mHeaderMutex.unlock(); }
@@ -132,6 +168,7 @@ class LLTextureCache : public LLWorkerThread
 	LLMutex mWorkersMutex;
 	LLMutex mHeaderMutex;
 	LLMutex mListMutex;
+	LLAPRFile* mHeaderAPRFile;
 	
 	typedef std::map<handle_t, LLTextureCacheWorker*> handle_map_t;
 	handle_map_t mReaders;
@@ -145,42 +182,28 @@ class LLTextureCache : public LLWorkerThread
 	
 	BOOL mReadOnly;
 	
-	// Entries
-	struct EntriesInfo
-	{
-		F32 mVersion;
-		U32 mEntries;
-	};
-	struct Entry
-	{
-		Entry() {}
-		Entry(const LLUUID& id, S32 size, U32 time) : mID(id), mSize(size), mTime(time) {}
-		LLUUID mID; // 128 bits
-		S32 mSize; // total size of image if known (NOT size cached)
-		U32 mTime; // seconds since 1/1/1970
-	};
-
 	// HEADERS (Include first mip)
 	std::string mHeaderEntriesFileName;
 	std::string mHeaderDataFileName;
 	EntriesInfo mHeaderEntriesInfo;
-	typedef std::map<S32,LLUUID> index_map_t;
-	index_map_t mLRU; // index, id; stored as a map for fast removal
+	std::set<S32> mFreeList; // deleted entries
+	std::set<LLUUID> mLRU;
 	typedef std::map<LLUUID,S32> id_map_t;
 	id_map_t mHeaderIDMap;
 
 	// BODIES (TEXTURES minus headers)
 	std::string mTexturesDirName;
-	std::string mTexturesDirEntriesFileName;
 	typedef std::map<LLUUID,S32> size_map_t;
 	size_map_t mTexturesSizeMap;
 	S64 mTexturesSizeTotal;
 	LLAtomic32<BOOL> mDoPurge;
-	
+
 	// Statics
 	static F32 sHeaderCacheVersion;
 	static U32 sCacheMaxEntries;
 	static S64 sCacheMaxTexturesSize;
 };
 
+extern const S32 TEXTURE_CACHE_ENTRY_SIZE;
+
 #endif // LL_LLTEXTURECACHE_H
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 88fc7f98c01480b909f155eae7fadafdf6696059..c918f988952ae5cda09819a785abd3036df1bfb7 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -32,108 +32,35 @@
 
 #include "llviewerprecompiledheaders.h"
 
+#include <iostream>
+
 #include "llstl.h"
 
 #include "lltexturefetch.h"
 
 #include "llcurl.h"
+#include "lldir.h"
 #include "llhttpclient.h"
+#include "llhttpstatuscodes.h"
 #include "llimage.h"
 #include "llimageworker.h"
 #include "llworkerthread.h"
 
 #include "llagent.h"
 #include "lltexturecache.h"
+#include "llviewercontrol.h"
 #include "llviewertexturelist.h"
 #include "llviewertexture.h"
 #include "llviewerregion.h"
+#include "llworld.h"
 
 //////////////////////////////////////////////////////////////////////////////
-//static
 class LLTextureFetchWorker : public LLWorkerClass
 {
-friend class LLTextureFetch;
-
-private:
-#if 0
-	class URLResponder : public LLHTTPClient::Responder
-	{
-	public:
-		URLResponder(LLTextureFetch* fetcher, const LLUUID& id)
-			: mFetcher(fetcher), mID(id)
-		{
-		}
-		~URLResponder()
-		{
-		}
-		virtual void error(U32 status, const std::string& reason)
-		{
-			mFetcher->lockQueue();
-			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
-			if (worker)
-			{
-// 				llwarns << "LLTextureFetchWorker::URLResponder::error " << status << ": " << reason << llendl;
- 				worker->callbackURLReceived(LLSD(), false);
-			}
-			mFetcher->unlockQueue();
-		}
-		virtual void result(const LLSD& content)
-		{
-			mFetcher->lockQueue();
-			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
-			if (worker)
-			{
- 				worker->callbackURLReceived(content, true);
-			}
-			mFetcher->unlockQueue();
-		}
-	private:
-		LLTextureFetch* mFetcher;
-		LLUUID mID;
-	};
-
-	class HTTPGetResponder : public LLHTTPClient::Responder
-	{
-	public:
-		HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id)
-			: mFetcher(fetcher), mID(id)
-		{
-		}
-		~HTTPGetResponder()
-		{
-		}
-		virtual void completed(U32 status, const std::stringstream& content)
-		{
-			mFetcher->lockQueue();
-			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
-			if (worker)
-			{
-				const std::string& cstr = content.str();
-				if (200 <= status &&  status < 300)
-				{
-					if (203 == status) // partial information (i.e. last block)
-					{
-						worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), true);
-					}
-					else
-					{
-						worker->callbackHttpGet((U8*)cstr.c_str(), cstr.length(), false);
-					}
-				}
-				else
-				{
-// 					llinfos << "LLTextureFetchWorker::HTTPGetResponder::error " << status << ": " << cstr << llendl;
-					worker->callbackHttpGet(NULL, -1, true);
-				}
-			}
-			mFetcher->unlockQueue();
-		}
-	private:
-		LLTextureFetch* mFetcher;
-		LLUUID mID;
-	};
-#endif
+	friend class LLTextureFetch;
+	friend class HTTPGetResponder;
 	
+private:
 	class CacheReadResponder : public LLTextureCache::ReadResponder
 	{
 	public:
@@ -179,20 +106,20 @@ friend class LLTextureFetch;
 		LLUUID mID;
 	};
 	
-	class DecodeResponder : public LLResponder
+	class DecodeResponder : public LLImageDecodeThread::Responder
 	{
 	public:
 		DecodeResponder(LLTextureFetch* fetcher, const LLUUID& id, LLTextureFetchWorker* worker)
 			: mFetcher(fetcher), mID(id), mWorker(worker)
 		{
 		}
-		virtual void completed(bool success)
+		virtual void completed(bool success, LLImageRaw* raw, LLImageRaw* aux)
 		{
 			mFetcher->lockQueue();
 			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
 			if (worker)
 			{
- 				worker->callbackDecoded(success);
+ 				worker->callbackDecoded(success, raw, aux);
 			}
 			mFetcher->unlockQueue();
 		}
@@ -227,37 +154,45 @@ friend class LLTextureFetch;
 	~LLTextureFetchWorker();
 	void relese() { --mActiveCount; }
 
+	void callbackHttpGet(const LLChannelDescriptors& channels,
+						 const LLIOPipe::buffer_ptr_t& buffer,
+						 bool last_block, bool success);
+	void callbackCacheRead(bool success, LLImageFormatted* image,
+						   S32 imagesize, BOOL islocal);
+	void callbackCacheWrite(bool success);
+	void callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux);
+	
+	void setGetStatus(U32 status, const std::string& reason)
+	{
+		mGetStatus = status;
+		mGetReason = reason;
+	}
+
 protected:
 	LLTextureFetchWorker(LLTextureFetch* fetcher, const LLUUID& id, const LLHost& host,
 						 F32 priority, S32 discard, S32 size);
+	LLTextureFetchWorker(LLTextureFetch* fetcher, const std::string& url, const LLUUID& id, const LLHost& host,
+						 F32 priority, S32 discard, S32 size);
 
 private:
 	/*virtual*/ void startWork(S32 param); // called from addWork() (MAIN THREAD)
 	/*virtual*/ void endWork(S32 param, bool aborted); // called from doWork() (MAIN THREAD)
 
-	virtual std::string getName() { return LLStringUtil::null; }
 	void resetFormattedData();
 	
 	void setImagePriority(F32 priority);
 	void setDesiredDiscard(S32 discard, S32 size);
 	bool insertPacket(S32 index, U8* data, S32 size);
 	void clearPackets();
+	void setupPacketData();
 	U32 calcWorkPriority();
 	void removeFromCache();
 	bool processSimulatorPackets();
-	bool decodeImage();
 	bool writeToCacheComplete();
 	
-	void lockWorkData() { mWorkMutex.lock(); }
-	void unlockWorkData() { mWorkMutex.unlock(); }
+	void lockWorkMutex() { mWorkMutex.lock(); }
+	void unlockWorkMutex() { mWorkMutex.unlock(); }
 
-	void callbackURLReceived(const LLSD& data, bool success);
-	void callbackHttpGet(U8* data, S32 data_size, bool last_block);
-	void callbackCacheRead(bool success, LLImageFormatted* image,
-						   S32 imagesize, BOOL islocal);
-	void callbackCacheWrite(bool success);
-	void callbackDecoded(bool success);
-	
 private:
 	enum e_state // mState
 	{
@@ -268,8 +203,8 @@ friend class LLTextureFetch;
 		CACHE_POST,
 		LOAD_FROM_NETWORK,
 		LOAD_FROM_SIMULATOR,
-		LOAD_FROM_HTTP_GET_URL,
-		LOAD_FROM_HTTP_GET_DATA,
+		SEND_HTTP_REQ,
+		WAIT_HTTP_REQ,
 		DECODE_IMAGE,
 		DECODE_IMAGE_UPDATE,
 		WRITE_TO_CACHE,
@@ -280,19 +215,17 @@ friend class LLTextureFetch;
 	{
 		UNSENT = 0,
 		QUEUED = 1,
-		SENT_SIM = 2,
-		SENT_URL = 3,
-		SENT_HTTP = 4
+		SENT_SIM = 2
 	};
 	static const char* sStateDescs[];
 	e_state mState;
 	LLTextureFetch* mFetcher;
-	LLImageWorker* mImageWorker;
 	LLPointer<LLImageFormatted> mFormattedImage;
 	LLPointer<LLImageRaw> mRawImage;
 	LLPointer<LLImageRaw> mAuxImage;
 	LLUUID mID;
 	LLHost mHost;
+	std::string mUrl;
 	U8 mType;
 	F32 mImagePriority;
 	U32 mWorkPriority;
@@ -314,15 +247,18 @@ friend class LLTextureFetch;
 	S32 mCachedSize;
 	BOOL mLoaded;
 	e_request_state mSentRequest;
+	handle_t mDecodeHandle;
 	BOOL mDecoded;
 	BOOL mWritten;
 	BOOL mNeedsAux;
 	BOOL mHaveAllData;
 	BOOL mInLocalCache;
+	S32 mHTTPFailCount;
 	S32 mRetryAttempt;
-	std::string mURL;
 	S32 mActiveCount;
-
+	U32 mGetStatus;
+	std::string mGetReason;
+	
 	// Work Data
 	LLMutex mWorkMutex;
 	struct PacketData
@@ -340,25 +276,79 @@ friend class LLTextureFetch;
 	U8 mImageCodec;
 };
 
-class LLTextureFetchLocalFileWorker : public LLTextureFetchWorker
-{
-friend class LLTextureFetch;
-
-protected:
-	LLTextureFetchLocalFileWorker(LLTextureFetch* fetcher, const std::string& filename, const LLUUID& id, const LLHost& host,
-						 F32 priority, S32 discard, S32 size)
-		:	LLTextureFetchWorker(fetcher, id, host, priority, discard, size),
-			mFileName(filename)
-	{}
+//////////////////////////////////////////////////////////////////////////////
 
-private:
-	/*virtual*/ std::string getName() { return mFileName; }
+class HTTPGetResponder : public LLCurl::Responder
+{
+	LOG_CLASS(HTTPGetResponder);
+public:
+	HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset)
+		: mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset)
+	{
+	}
+	~HTTPGetResponder()
+	{
+	}
 
+	virtual void completedRaw(U32 status, const std::string& reason,
+							  const LLChannelDescriptors& channels,
+							  const LLIOPipe::buffer_ptr_t& buffer)
+	{
+		if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
+		{
+			mFetcher->mTextureInfo.setRequestStartTime(mID, mStartTime);
+			U64 timeNow = LLTimer::getTotalTime();
+			mFetcher->mTextureInfo.setRequestType(mID, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+			mFetcher->mTextureInfo.setRequestSize(mID, mRequestedSize);
+			mFetcher->mTextureInfo.setRequestOffset(mID, mOffset);
+			mFetcher->mTextureInfo.setRequestCompleteTimeAndLog(mID, timeNow);
+		}
 
+		lldebugs << "HTTP COMPLETE: " << mID << llendl;
+		mFetcher->lockQueue();
+		LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
+		if (worker)
+		{
+			bool success = false;
+			bool partial = false;
+			if (200 <= status &&  status < 300)
+			{
+				success = true;
+				if (203 == status) // partial information (i.e. last block)
+				{
+					partial = true;
+				}
+			}
+			else
+			{
+				worker->setGetStatus(status, reason);
+// 				llwarns << status << ": " << reason << llendl;
+			}
+			if (!success)
+			{
+				worker->setGetStatus(status, reason);
+// 				llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
+			}
+			mFetcher->removeFromHTTPQueue(mID);
+			worker->callbackHttpGet(channels, buffer, partial, success);
+		}
+		else
+		{
+			mFetcher->removeFromHTTPQueue(mID);
+ 			llwarns << "Worker not found: " << mID << llendl;
+		}
+		mFetcher->unlockQueue();
+	}
+	
 private:
-	std::string mFileName;
+	LLTextureFetch* mFetcher;
+	LLUUID mID;
+	U64 mStartTime;
+	S32 mRequestedSize;
+	U32 mOffset;
 };
 
+//////////////////////////////////////////////////////////////////////////////
 
 //static
 const char* LLTextureFetchWorker::sStateDescs[] = {
@@ -368,8 +358,8 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
 	"CACHE_POST",
 	"LOAD_FROM_NETWORK",
 	"LOAD_FROM_SIMULATOR",
-	"LOAD_FROM_HTTP_URL",
-	"LOAD_FROM_HTTP_DATA",
+	"SEND_HTTP_REQ",
+	"WAIT_HTTP_REQ",
 	"DECODE_IMAGE",
 	"DECODE_IMAGE_UPDATE",
 	"WRITE_TO_CACHE",
@@ -380,6 +370,7 @@ const char* LLTextureFetchWorker::sStateDescs[] = {
 // called from MAIN THREAD
 
 LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
+										   const std::string& url, // Optional URL
 										   const LLUUID& id,	// Image UUID
 										   const LLHost& host,	// Simulator host
 										   F32 priority,		// Priority
@@ -388,9 +379,9 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	: LLWorkerClass(fetcher, "TextureFetch"),
 	  mState(INIT),
 	  mFetcher(fetcher),
-	  mImageWorker(NULL),
 	  mID(id),
 	  mHost(host),
+	  mUrl(url),
 	  mImagePriority(priority),
 	  mWorkPriority(0),
 	  mRequestedPriority(0.f),
@@ -404,18 +395,21 @@ LLTextureFetchWorker::LLTextureFetchWorker(LLTextureFetch* fetcher,
 	  mBuffer(NULL),
 	  mBufferSize(0),
 	  mRequestedSize(0),
-	  mDesiredSize(FIRST_PACKET_SIZE),
+	  mDesiredSize(TEXTURE_CACHE_ENTRY_SIZE),
 	  mFileSize(0),
 	  mCachedSize(0),
 	  mLoaded(FALSE),
 	  mSentRequest(UNSENT),
+	  mDecodeHandle(0),
 	  mDecoded(FALSE),
 	  mWritten(FALSE),
 	  mNeedsAux(FALSE),
 	  mHaveAllData(FALSE),
 	  mInLocalCache(FALSE),
+	  mHTTPFailCount(0),
 	  mRetryAttempt(0),
 	  mActiveCount(0),
+	  mGetStatus(0),
 	  mWorkMutex(NULL),
 	  mFirstPacket(0),
 	  mLastPacket(-1),
@@ -440,7 +434,7 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
 // 			<< " Requested=" << mRequestedDiscard
 // 			<< " Desired=" << mDesiredDiscard << llendl;
 	llassert_always(!haveWork());
-	lockWorkData();
+	lockWorkMutex();
 	if (mCacheReadHandle != LLTextureCache::nullHandle())
 	{
 		mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
@@ -449,13 +443,9 @@ LLTextureFetchWorker::~LLTextureFetchWorker()
 	{
 		mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
 	}
-	if (mImageWorker)
-	{
-		mImageWorker->scheduleDelete();
-	}
 	mFormattedImage = NULL;
 	clearPackets();
-	unlockWorkData();
+	unlockWorkMutex();
 }
 
 void LLTextureFetchWorker::clearPackets()
@@ -467,6 +457,38 @@ void LLTextureFetchWorker::clearPackets()
 	mFirstPacket = 0;
 }
 
+void LLTextureFetchWorker::setupPacketData()
+{
+	S32 data_size = 0;
+	if (mFormattedImage.notNull())
+	{
+		data_size = mFormattedImage->getDataSize();
+	}
+	if (data_size > 0)
+	{
+		// Only used for simulator requests
+		mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1;
+		if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
+		{
+			llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
+			removeFromCache();
+			resetFormattedData();
+			clearPackets();
+		}
+		else if (mFileSize > 0)
+		{
+			mLastPacket = mFirstPacket-1;
+			mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
+		}
+		else
+		{
+			// This file was cached using HTTP so we have to refetch the first packet
+			resetFormattedData();
+			clearPackets();
+		}
+	}
+}
+
 U32 LLTextureFetchWorker::calcWorkPriority()
 {
 // 	llassert_always(mImagePriority >= 0 && mImagePriority <= LLViewerTexture::maxDecodePriority());
@@ -538,7 +560,6 @@ void LLTextureFetchWorker::resetFormattedData()
 // Called from MAIN thread
 void LLTextureFetchWorker::startWork(S32 param)
 {
-	llassert(mImageWorker == NULL);
 	llassert(mFormattedImage.isNull());
 }
 
@@ -549,6 +570,14 @@ bool LLTextureFetchWorker::doWork(S32 param)
 {
 	LLMutexLock lock(&mWorkMutex);
 
+	if ((mFetcher->isQuitting() || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)))
+	{
+		if (mState < WRITE_TO_CACHE)
+		{
+			return true; // abort
+		}
+	}
+	
 	if (mFetcher->mDebugPause)
 	{
 		return false; // debug: don't do any work
@@ -563,16 +592,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		mFetchTimer.reset();
 	}
 
-	if (mImagePriority <= 0.0f)
-	{
-		if (mState < WRITE_TO_CACHE)
-		{
-			return true; // cancel request
-		}
-	}
-	
 	if (mState == INIT)
 	{
+		mRawImage = NULL ;
 		mRequestedDiscard = -1;
 		mLoadedDiscard = -1;
 		mDecodedDiscard = -1;
@@ -590,8 +612,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		clearPackets(); // TODO: Shouldn't be necessary
 		mCacheReadHandle = LLTextureCache::nullHandle();
 		mCacheWriteHandle = LLTextureCache::nullHandle();
-		mURL.clear();
 		mState = LOAD_FROM_TEXTURE_CACHE;
+		LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority)
+							 << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
 		// fall through
 	}
 
@@ -612,16 +635,27 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
 
 			CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
-			if (getName().empty())
+			if (mUrl.compare(0, 7, "file://") == 0)
+			{
+				// read file from local disk
+				std::string filename = mUrl.substr(7, std::string::npos);
+				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
+																		  offset, size, responder);
+			}
+			else if (mUrl.empty())
 			{
 				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
 																		  offset, size, responder);
 			}
 			else
 			{
-				// read file from local disk
-				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(getName(), mID, cache_priority,
-																		  offset, size, responder);
+				if (!(mUrl.compare(0, 7, "http://") == 0))
+				{
+					// *TODO:?remove this warning
+					llwarns << "Unknown URL Type: " << mUrl << llendl;
+				}
+				setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+				mState = SEND_HTTP_REQ;
 			}
 		}
 
@@ -647,75 +681,101 @@ bool LLTextureFetchWorker::doWork(S32 param)
 
 	if (mState == CACHE_POST)
 	{
-		mDesiredSize = llmax(mDesiredSize, FIRST_PACKET_SIZE);
+		mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE);
 		mCachedSize = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
 		// Successfully loaded
 		if ((mCachedSize >= mDesiredSize) || mHaveAllData)
 		{
 			// we have enough data, decode it
 			llassert_always(mFormattedImage->getDataSize() > 0);
+			mLoadedDiscard = mDesiredDiscard;
 			mState = DECODE_IMAGE;
+			LL_DEBUGS("Texture") << mID << ": Cached. Bytes: " << mFormattedImage->getDataSize()
+								 << " Size: " << llformat("%dx%d",mFormattedImage->getWidth(),mFormattedImage->getHeight())
+								 << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
 			// fall through
 		}
 		else
 		{
-			if (!getName().empty())
+			if (mUrl.compare(0, 7, "file://") == 0)
 			{
 				// failed to load local file, we're done.
 				return true;
 			}
 			// need more data
-			mState = LOAD_FROM_NETWORK;
+			else
+			{
+				LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL;
+				mState = LOAD_FROM_NETWORK;
+			}
 			// fall through
 		}
 	}
 
 	if (mState == LOAD_FROM_NETWORK)
 	{
-		if (mSentRequest == UNSENT)
+		bool get_url = gSavedSettings.getBOOL("ImagePipelineUseHTTP");
+		if (!mUrl.empty()) get_url = false;
+// 		if (mHost != LLHost::invalid) get_url = false;
+		if ( get_url )
 		{
-			if (mFormattedImage.isNull())
-			{
-				mFormattedImage = new LLImageJ2C;
-			}
-			// Add this to the network queue and sit here.
-			// LLTextureFetch::update() will send off a request which will change our state
-			S32 data_size = mFormattedImage->getDataSize();
-			if (data_size > 0)
+			LLViewerRegion* region = NULL;
+			if (mHost == LLHost::invalid)
+				region = gAgent.getRegion();
+			else
+				region = LLWorld::getInstance()->getRegion(mHost);
+
+			if (region)
 			{
-				// Only used for simulator requests
-				mFirstPacket = (data_size - FIRST_PACKET_SIZE) / MAX_IMG_PACKET_SIZE + 1;
-				if (FIRST_PACKET_SIZE + (mFirstPacket-1) * MAX_IMG_PACKET_SIZE != data_size)
-				{
-// 					llwarns << "Bad CACHED TEXTURE size: " << data_size << " removing." << llendl;
-					removeFromCache();
-					resetFormattedData();
-					clearPackets();
-				}
-				else
+				std::string http_url = region->getCapability("GetTexture");
+				if (!http_url.empty())
 				{
-					mLastPacket = mFirstPacket-1;
-					mTotalPackets = (mFileSize - FIRST_PACKET_SIZE + MAX_IMG_PACKET_SIZE-1) / MAX_IMG_PACKET_SIZE + 1;
+					mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
 				}
 			}
+			else
+			{
+				llwarns << "Region not found for host: " << mHost << llendl;
+			}
+		}
+		if (!mUrl.empty())
+		{
+			mState = LLTextureFetchWorker::SEND_HTTP_REQ;
+			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+			// don't return, fall through to next state
+		}
+		else if (mSentRequest == UNSENT)
+		{
+			// Add this to the network queue and sit here.
+			// LLTextureFetch::update() will send off a request which will change our state
 			mRequestedSize = mDesiredSize;
 			mRequestedDiscard = mDesiredDiscard;
 			mSentRequest = QUEUED;
-			mFetcher->lockQueue();
 			mFetcher->addToNetworkQueue(this);
-			mFetcher->unlockQueue();
 			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			return false;
+		}
+		else
+		{
+			// Shouldn't need to do anything here
+			//llassert_always(mFetcher->mNetworkQueue.find(mID) != mFetcher->mNetworkQueue.end());
+			// Make certain this is in the network queue
+			//mFetcher->addToNetworkQueue(this);
+			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			return false;
 		}
-		return false;
 	}
 	
 	if (mState == LOAD_FROM_SIMULATOR)
 	{
+		if (mFormattedImage.isNull())
+		{
+			mFormattedImage = new LLImageJ2C;
+		}
 		if (processSimulatorPackets())
 		{
-			mFetcher->lockQueue();
-			mFetcher->removeFromNetworkQueue(this);
-			mFetcher->unlockQueue();
+			LL_DEBUGS("Texture") << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL;
+			mFetcher->removeFromNetworkQueue(this, false);
 			if (mFormattedImage.isNull() || !mFormattedImage->getDataSize())
 			{
 				// processSimulatorPackets() failed
@@ -727,108 +787,99 @@ bool LLTextureFetchWorker::doWork(S32 param)
 		}
 		else
 		{
+			mFetcher->addToNetworkQueue(this); // failsafe
 			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 		}
 		return false;
 	}
 	
-#if 0
-	if (mState == LOAD_FROM_HTTP_GET_URL)
-	{
-		if (!mSentRequest)
-		{
-			mSentRequest = TRUE;
-			mLoaded = FALSE;
-			std::string url;
-			LLViewerRegion* region = gAgent.getRegion();
-			if (region)
+	if (mState == SEND_HTTP_REQ)
+	{
+		{
+			const S32 HTTP_QUEUE_MAX_SIZE = 32;
+			// *TODO: Integrate this with llviewerthrottle
+			// Note: LLViewerThrottle uses dynamic throttling which makes sense for UDP,
+			// but probably not for Textures.
+			// Set the throttle to the entire bandwidth, assuming UDP packets will get priority
+			// when they are needed
+			F32 max_bandwidth = mFetcher->mMaxBandwidth;
+			if ((mFetcher->getHTTPQueueSize() >= HTTP_QUEUE_MAX_SIZE) ||
+				(mFetcher->getTextureBandwidth() > max_bandwidth))
 			{
-				url = region->getCapability("RequestTextureDownload");
-			}
-			if (!url.empty())
-			{
-				LLSD sd;
-				sd = mID.asString();
-				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-				LLHTTPClient::post(url, sd, new URLResponder(mFetcher, mID));
+				// Make normal priority and return (i.e. wait until there is room in the queue)
+				setPriority(LLWorkerThread::PRIORITY_NORMAL | mWorkPriority);
 				return false;
 			}
-			else
-			{
-// 				llwarns << mID << ": HTTP get url failed, requesting from simulator" << llendl;
-				mSentRequest = FALSE;
-				mState = LOAD_FROM_SIMULATOR;
-				return false;
-			}
-		}
-		else
-		{
-			if (mLoaded)
+			
+			mFetcher->removeFromNetworkQueue(this, false);
+			
+			S32 cur_size = 0;
+			if (mFormattedImage.notNull())
 			{
-				if (!mURL.empty())
-				{
-					mState = LOAD_FROM_HTTP_GET_DATA;
-					mSentRequest = FALSE; // reset
-					mLoaded = FALSE; // reset
-				}
-				else
-				{
-// 					llwarns << mID << ": HTTP get url is empty, requesting from simulator" << llendl;
-					mSentRequest = FALSE;
-					mState = LOAD_FROM_SIMULATOR;
-					return false;
-				}
+				cur_size = mFormattedImage->getDataSize(); // amount of data we already have
 			}
-		}
-		// fall through
-	}
-	
-	if (mState == LOAD_FROM_HTTP_GET_DATA)
-	{
-		if (!mSentRequest)
-		{
-			mSentRequest = TRUE;
-			S32 cur_size = mFormattedImage->getDataSize(); // amount of data we already have
 			mRequestedSize = mDesiredSize;
 			mRequestedDiscard = mDesiredDiscard;
-#if 1 // *TODO: LLCurl::getByteRange is broken (ignores range)
-			cur_size = 0;
-			mFormattedImage->deleteData();
-#endif
 			mRequestedSize -= cur_size;
-			// 			  F32 priority = mImagePriority / (F32)LLViewerTexture::maxDecodePriority(); // 0-1
 			S32 offset = cur_size;
 			mBufferSize = cur_size; // This will get modified by callbackHttpGet()
-			std::string url;
-			if (mURL.empty())
+			
+			bool res = false;
+			if (!mUrl.empty())
 			{
-				//url = "http://asset.agni/0000002f-38ae-0e17-8e72-712e58964e9c.texture";
-				std::stringstream urlstr;
-				urlstr << "http://asset.agni/" << mID.asString() << ".texture";
-				url = urlstr.str();
+				mLoaded = FALSE;
+				mGetStatus = 0;
+				mGetReason.clear();
+				lldebugs << "HTTP GET: " << mID << " Offset: " << offset
+						<< " Bytes: " << mRequestedSize
+						<< " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << max_bandwidth
+						<< llendl;
+				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+				mState = WAIT_HTTP_REQ;	
+
+				mFetcher->addToHTTPQueue(mID);
+				// Will call callbackHttpGet when curl request completes
+				std::vector<std::string> headers;
+				headers.push_back("Accept: image/x-j2c");
+				res = mFetcher->mCurlGetRequest->getByteRange(mUrl, headers, offset, mRequestedSize,
+															  new HTTPGetResponder(mFetcher, mID, LLTimer::getTotalTime(), mRequestedSize, offset));
 			}
-			else
+			if (!res)
 			{
-				url = mURL;
+				llwarns << "HTTP GET request failed for " << mID << llendl;
+				resetFormattedData();
+				++mHTTPFailCount;
+				return true; // failed
 			}
-			mLoaded = FALSE;
-// 			llinfos << "HTTP GET: " << mID << " Offset: " << offset << " Bytes: " << mRequestedSize << llendl;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-			LLCurl::getByteRange(url, offset, mRequestedSize,
-								 new HTTPGetResponder(mFetcher, mID)); // *TODO: use mWorkPriority
-			return false; // not done
+			// fall through
 		}
-
+	}
+	
+	if (mState == WAIT_HTTP_REQ)
+	{
 		if (mLoaded)
 		{
-			S32 cur_size = mFormattedImage->getDataSize();
+			S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
 			if (mRequestedSize < 0)
 			{
-// 				llwarns << "http get failed for: " << mID << llendl;
+				const S32 HTTP_MAX_RETRY_COUNT = 3;
+				S32 max_attempts = (mGetStatus == HTTP_NOT_FOUND) ? 1 : HTTP_MAX_RETRY_COUNT + 1;
+ 				llinfos << "HTTP GET failed for: " << mUrl
+						<< " Status: " << mGetStatus << " Reason: '" << mGetReason << "'"
+						<< " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl;
 				if (cur_size == 0)
 				{
-					resetFormattedData();
-					return true; // failed
+					++mHTTPFailCount;
+					if (mHTTPFailCount >= max_attempts)
+					{
+						resetFormattedData();
+						return true; // failed
+					}
+					else
+					{
+						mState = SEND_HTTP_REQ;
+						return false; // retry
+					}
 				}
 				else
 				{
@@ -836,6 +887,18 @@ bool LLTextureFetchWorker::doWork(S32 param)
 					return false; // use what we have
 				}
 			}
+			
+			if (mFormattedImage.isNull())
+			{
+				// For now, create formatted image based on extension
+				std::string extension = gDirUtilp->getExtension(mUrl);
+				mFormattedImage = LLImageFormatted::createFromType(LLImageBase::getCodecFromExtension(extension));
+				if (mFormattedImage.isNull())
+				{
+					mFormattedImage = new LLImageJ2C; // default
+				}
+			}
+			
 			llassert_always(mBufferSize == cur_size + mRequestedSize);
 			if (mHaveAllData)
 			{
@@ -854,43 +917,51 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			mBuffer = NULL;
 			mBufferSize = 0;
 			mLoadedDiscard = mRequestedDiscard;
-			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
 			mState = DECODE_IMAGE;
+			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+			return false;
+		}
+		else
+		{
+			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
 			return false;
 		}
-
-		// NOTE: Priority gets updated when the http get completes (in callbackHTTPGet())
-		setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-		return false;
 	}
-#endif
 	
 	if (mState == DECODE_IMAGE)
 	{
-		llassert_always(mFormattedImage->getDataSize() > 0);
+		if (mFormattedImage->getDataSize() <= 0)
+		{
+			llerrs << "Decode entered with invalid mFormattedImage. ID = " << mID << llendl;
+		}
 		setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
 		mRawImage = NULL;
 		mAuxImage = NULL;
-		llassert_always(mImageWorker == NULL);
 		llassert_always(mFormattedImage.notNull());
+		llassert_always(mLoadedDiscard >= 0);
 		S32 discard = mHaveAllData ? 0 : mLoadedDiscard;
 		U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority;
 		mDecoded  = FALSE;
 		mState = DECODE_IMAGE_UPDATE;
-		mImageWorker = new LLImageWorker(mFormattedImage, image_priority, discard, new DecodeResponder(mFetcher, mID, this));
-		// fall though (need to call requestDecodedData() to start work)
+		LL_DEBUGS("Texture") << mID << ": Decoding. Bytes: " << mFormattedImage->getDataSize() << " Discard: " << discard
+				<< " All Data: " << mHaveAllData << LL_ENDL;
+		mDecodeHandle = mFetcher->mImageDecodeThread->decodeImage(mFormattedImage, image_priority, discard, mNeedsAux,
+																  new DecodeResponder(mFetcher, mID, this));
+		// fall though
 	}
 	
 	if (mState == DECODE_IMAGE_UPDATE)
 	{
-		if (decodeImage())
+		if (mDecoded)
 		{
 			if (mDecodedDiscard < 0)
 			{
+				LL_DEBUGS("Texture") << mID << ": Failed to Decode." << LL_ENDL;
 				if (mCachedSize > 0 && !mInLocalCache && mRetryAttempt == 0)
 				{
 					// Cache file should be deleted, try again
 // 					llwarns << mID << ": Decode of cached file failed (removed), retrying" << llendl;
+					llassert_always(mDecodeHandle == 0);
 					mFormattedImage = NULL;
 					++mRetryAttempt;
 					setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
@@ -905,6 +976,9 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			}
 			else
 			{
+				llassert_always(mRawImage.notNull());
+				LL_DEBUGS("Texture") << mID << ": Decoded. Discard: " << mDecodedDiscard
+						<< " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL;
 				setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
 				mState = WRITE_TO_CACHE;
 			}
@@ -918,9 +992,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
 
 	if (mState == WRITE_TO_CACHE)
 	{
-		if (mInLocalCache || !mFileSize || mSentRequest == UNSENT)
+		if (mInLocalCache || mSentRequest == UNSENT || mFormattedImage.isNull())
 		{
-			// If we're in a local cache or we didn't actually receive any new data, skip
+			// If we're in a local cache or we didn't actually receive any new data,
+			// or we failed to load anything, skip
 			mState = DONE;
 			return false;
 		}
@@ -979,10 +1054,10 @@ bool LLTextureFetchWorker::doWork(S32 param)
 // Called from MAIN thread
 void LLTextureFetchWorker::endWork(S32 param, bool aborted)
 {
-	if (mImageWorker)
+	if (mDecodeHandle != 0)
 	{
-		mImageWorker->scheduleDelete();
-		mImageWorker = NULL;
+		mFetcher->mImageDecodeThread->abortRequest(mDecodeHandle, false);
+		mDecodeHandle = 0;
 	}
 	mFormattedImage = NULL;
 }
@@ -1035,7 +1110,7 @@ bool LLTextureFetchWorker::deleteOK()
 
 	if ((haveWork() &&
 		 // not ok to delete from these states
-		 ((mState >= LOAD_FROM_HTTP_GET_URL && mState <= LOAD_FROM_HTTP_GET_DATA) ||
+		 ((mState >= SEND_HTTP_REQ && mState <= WAIT_HTTP_REQ) ||
 		  (mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
 	{
 		delete_ok = false;
@@ -1044,7 +1119,6 @@ bool LLTextureFetchWorker::deleteOK()
 	return delete_ok;
 }
 
-
 void LLTextureFetchWorker::removeFromCache()
 {
 	if (!mInLocalCache)
@@ -1061,6 +1135,7 @@ bool LLTextureFetchWorker::processSimulatorPackets()
 	if (mFormattedImage.isNull() || mRequestedSize < 0)
 	{
 		// not sure how we got here, but not a valid state, abort!
+		llassert_always(mDecodeHandle == 0);
 		mFormattedImage = NULL;
 		return true;
 	}
@@ -1074,6 +1149,12 @@ bool LLTextureFetchWorker::processSimulatorPackets()
 			buffer_size += mPackets[i]->mSize;
 		}
 		bool have_all_data = mLastPacket >= mTotalPackets-1;
+		if (mRequestedSize <= 0)
+		{
+			// We received a packed but haven't requested anything yet (edge case)
+			// Return true (we're "done") since we didn't request anything
+			return true;
+		}
 		if (buffer_size >= mRequestedSize || have_all_data)
 		{
 			/// We have enough (or all) data
@@ -1109,50 +1190,36 @@ bool LLTextureFetchWorker::processSimulatorPackets()
 
 //////////////////////////////////////////////////////////////////////////////
 
-void LLTextureFetchWorker::callbackURLReceived(const LLSD& data, bool success)
+void LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
+										   const LLIOPipe::buffer_ptr_t& buffer,
+										   bool last_block, bool success)
 {
-#if 0
 	LLMutexLock lock(&mWorkMutex);
-	if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_URL)
-	{
-		llwarns << "callbackURLReceived for unrequested fetch worker, req="
-				<< mSentRequest << " state= " << mState << llendl;
-		return;
-	}
-	if (success)
-	{
-		mURL = data.asString();
-	}
-	mLoaded = TRUE;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-#endif
-}
-
-//////////////////////////////////////////////////////////////////////////////
 
-void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_block)
-{
-#if 0
-	LLMutexLock lock(&mWorkMutex);
-	if (!mSentRequest || mState != LOAD_FROM_HTTP_GET_DATA)
+	if (mState != WAIT_HTTP_REQ)
 	{
-		llwarns << "callbackHttpGet for unrequested fetch worker, req="
-				<< mSentRequest << " state= " << mState << llendl;
+		llwarns << "callbackHttpGet for unrequested fetch worker: " << mID
+				<< " req=" << mSentRequest << " state= " << mState << llendl;
 		return;
 	}
-// 	llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
 	if (mLoaded)
 	{
 		llwarns << "Duplicate callback for " << mID.asString() << llendl;
 		return; // ignore duplicate callback
 	}
-	if (data_size >= 0)
+	if (success)
 	{
+		// get length of stream:
+		S32 data_size = buffer->countAfter(channels.in(), NULL);
+
+		gTextureList.sTextureBits += data_size * 8; // Approximate - does not include header bits
+	
+		//llinfos << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << llendl;
 		if (data_size > 0)
 		{
+			// *TODO: set the formatted image data here directly to avoid the copy
 			mBuffer = new U8[data_size];
-			// *TODO: set the formatted image data here
-			memcpy(mBuffer, data, data_size);
+			buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
 			mBufferSize += data_size;
 			if (data_size < mRequestedSize || last_block == true)
 			{
@@ -1160,10 +1227,11 @@ void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_bl
 			}
 			else if (data_size > mRequestedSize)
 			{
-				// *TODO: This will happen until we fix LLCurl::getByteRange()
-// 				llinfos << "HUH?" << llendl;
+				// *TODO: This shouldn't be happening any more
+				llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl;
 				mHaveAllData = TRUE;
-				mFormattedImage->deleteData();
+				llassert_always(mDecodeHandle == 0);
+				mFormattedImage = NULL; // discard any previous data we had
 				mBufferSize = data_size;
 			}
 		}
@@ -1181,7 +1249,6 @@ void LLTextureFetchWorker::callbackHttpGet(U8* data, S32 data_size, bool last_bl
 	}
 	mLoaded = TRUE;
 	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-#endif
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1197,7 +1264,7 @@ void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* ima
 	}
 	if (success)
 	{
-		llassert_always(imagesize > 0);
+		llassert_always(imagesize >= 0);
 		mFileSize = imagesize;
 		mFormattedImage = image;
 		mImageCodec = image->getCodec();
@@ -1225,65 +1292,40 @@ void LLTextureFetchWorker::callbackCacheWrite(bool success)
 
 //////////////////////////////////////////////////////////////////////////////
 
-void LLTextureFetchWorker::callbackDecoded(bool success)
+void LLTextureFetchWorker::callbackDecoded(bool success, LLImageRaw* raw, LLImageRaw* aux)
 {
+	LLMutexLock lock(&mWorkMutex);
+	if (mDecodeHandle == 0)
+	{
+		return; // aborted, ignore
+	}
 	if (mState != DECODE_IMAGE_UPDATE)
 	{
 // 		llwarns << "Decode callback for " << mID << " with state = " << mState << llendl;
+		mDecodeHandle = 0;
 		return;
 	}
-// 	llinfos << mID << " : DECODE COMPLETE " << llendl;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-bool LLTextureFetchWorker::decodeImage()
-{
-	if(!mImageWorker)
-	{
-		//LLTextureFetchWorker is aborted, skip image decoding.
-		return true ;
-	}
-
-	bool res = true;
-	if (mRawImage.isNull())
-	{
-		res = false;
-		if (mImageWorker->requestDecodedData(mRawImage, -1))
-		{
-			res = true;
-// 			llinfos << mID << " : BASE DECODE FINISHED" << llendl;
-		}
-	}
-	if (res &&
-		(mRawImage.notNull() && mRawImage->getDataSize() > 0) &&
-		(mNeedsAux && mAuxImage.isNull()))
+	llassert_always(mFormattedImage.notNull());
+	
+	mDecodeHandle = 0;
+	if (success)
 	{
-		res = false;
-		if (mImageWorker->requestDecodedAuxData(mAuxImage, 4, -1))
-		{
-			res = true;
-// 			llinfos << mID << " : AUX DECODE FINISHED" << llendl;
-		}
+		llassert_always(raw);
+		mRawImage = raw;
+		mAuxImage = aux;
+		mDecodedDiscard = mFormattedImage->getDiscardLevel();
+ 		LL_DEBUGS("Texture") << mID << ": Decode Finished. Discard: " << mDecodedDiscard
+							 << " Raw Image: " << llformat("%dx%d",mRawImage->getWidth(),mRawImage->getHeight()) << LL_ENDL;
 	}
-	if (res)
+	else
 	{
-		if ((mRawImage.notNull() && mRawImage->getDataSize() > 0) &&
-			(!mNeedsAux || (mAuxImage.notNull() && mAuxImage->getDataSize() > 0)))
-		{
-			mDecodedDiscard = mFormattedImage->getDiscardLevel();
-// 			llinfos << mID << " : DECODE FINISHED. DISCARD: " << mDecodedDiscard << llendl;
-		}
-		else
-		{
-// 			llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl;
-			removeFromCache();
-		}
-		mImageWorker->scheduleDelete();
-		mImageWorker = NULL;
+		llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl;
+		removeFromCache();
+		mDecodedDiscard = -1; // Redundant, here for clarity and paranoia
 	}
-	return res;
+	mDecoded = TRUE;
+// 	llinfos << mID << " : DECODE COMPLETE " << llendl;
+	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1314,15 +1356,21 @@ bool LLTextureFetchWorker::writeToCacheComplete()
 //////////////////////////////////////////////////////////////////////////////
 // public
 
-LLTextureFetch::LLTextureFetch(LLTextureCache* cache, bool threaded)
+LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded)
 	: LLWorkerThread("TextureFetch", threaded),
 	  mDebugCount(0),
 	  mDebugPause(FALSE),
 	  mPacketCount(0),
 	  mBadPacketCount(0),
 	  mQueueMutex(getAPRPool()),
-	  mTextureCache(cache)
+	  mNetworkQueueMutex(getAPRPool()),
+	  mTextureCache(cache),
+	  mImageDecodeThread(imagedecodethread),
+	  mTextureBandwidth(0),
+	  mCurlGetRequest(NULL)
 {
+	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
+	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
 }
 
 LLTextureFetch::~LLTextureFetch()
@@ -1330,13 +1378,7 @@ LLTextureFetch::~LLTextureFetch()
 	// ~LLQueuedThread() called here
 }
 
-bool LLTextureFetch::createRequest(const LLUUID& id, const LLHost& host, F32 priority,
-									S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux)
-{
-	return createRequest(LLStringUtil::null, id, host, priority, w, h, c, desired_discard, needs_aux);
-}
-
-bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id, const LLHost& host, F32 priority,
+bool LLTextureFetch::createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
 								   S32 w, S32 h, S32 c, S32 desired_discard, bool needs_aux)
 {
 	if (mDebugPause)
@@ -1361,7 +1403,14 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
 	}
 
 	S32 desired_size;
-	if (desired_discard == 0)
+	std::string exten = gDirUtilp->getExtension(url);
+	if (!url.empty() && (!exten.empty() && LLImageBase::getCodecFromExtension(exten) != IMG_CODEC_J2C))
+	{
+		// Only do partial requests for J2C at the moment
+		//llinfos << "Merov : LLTextureFetch::createRequest(), blocking fetch on " << url << llendl; 
+		desired_size = MAX_IMAGE_DATA_SIZE;
+	}
+	else if (desired_discard == 0)
 	{
 		// if we want the entire image, and we know its size, then get it all
 		// (calcDataSizeJ2C() below makes assumptions about how the image
@@ -1378,7 +1427,7 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
 	}
 	else
 	{
-		desired_size = FIRST_PACKET_SIZE;
+		desired_size = TEXTURE_CACHE_ENTRY_SIZE;
 		desired_discard = MAX_DISCARD_LEVEL;
 	}
 
@@ -1389,10 +1438,10 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
 		{
 			return false; // need to wait for previous aborted request to complete
 		}
-		worker->lockWorkData();
+		worker->lockWorkMutex();
 		worker->setImagePriority(priority);
 		worker->setDesiredDiscard(desired_discard, desired_size);
-		worker->unlockWorkData();
+		worker->unlockWorkMutex();
 		if (!worker->haveWork())
 		{
 			worker->mState = LLTextureFetchWorker::INIT;
@@ -1401,16 +1450,7 @@ bool LLTextureFetch::createRequest(const std::string& filename, const LLUUID& id
 	}
 	else
 	{
-		if (filename.empty())
-		{
-			// do remote fetch
-			worker = new LLTextureFetchWorker(this, id, host, priority, desired_discard, desired_size);
-		}
-		else
-		{
-			// do local file fetch
-			worker = new LLTextureFetchLocalFileWorker(this, filename, id, host, priority, desired_discard, desired_size);
-		}
+		worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size);
 		mRequestMap[id] = worker;
 	}
 	worker->mActiveCount++;
@@ -1430,10 +1470,9 @@ void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
 }
 
 // protected
-
-// call lockQueue() first!
 void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
 {
+	LLMutexLock lock(&mNetworkQueueMutex);
 	if (mRequestMap.find(worker->mID) != mRequestMap.end())
 	{
 		// only add to the queue if in the request map
@@ -1447,10 +1486,27 @@ void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
 	}
 }
 
-// call lockQueue() first!
-void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker)
+void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel)
 {
-	mNetworkQueue.erase(worker->mID);
+	LLMutexLock lock(&mNetworkQueueMutex);
+	size_t erased = mNetworkQueue.erase(worker->mID);
+	if (cancel && erased > 0)
+	{
+		mCancelQueue[worker->mHost].insert(worker->mID);
+	}
+}
+
+// protected
+void LLTextureFetch::addToHTTPQueue(const LLUUID& id)
+{
+	LLMutexLock lock(&mNetworkQueueMutex);
+	mHTTPTextureQueue.insert(id);
+}
+
+void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id)
+{
+	LLMutexLock lock(&mNetworkQueueMutex);
+	mHTTPTextureQueue.erase(id);
 }
 
 // call lockQueue() first!
@@ -1458,11 +1514,7 @@ void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel)
 {
 	size_t erased_1 = mRequestMap.erase(worker->mID);
 	llassert_always(erased_1 > 0) ;
-	size_t erased = mNetworkQueue.erase(worker->mID);
-	if (cancel && erased > 0)
-	{
-		mCancelQueue[worker->mHost].insert(worker->mID);
-	}
+	removeFromNetworkQueue(worker, cancel);
 	llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
 
 	worker->scheduleDelete();	
@@ -1504,24 +1556,27 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
 		}
 		else if (worker->checkWork())
 		{
+			worker->lockWorkMutex();
 			discard_level = worker->mDecodedDiscard;
-			raw = worker->mRawImage; worker->mRawImage = NULL;
-			aux = worker->mAuxImage; worker->mAuxImage = NULL;
+			raw = worker->mRawImage;
+			aux = worker->mAuxImage;
 			res = true;
+			LL_DEBUGS("Texture") << id << ": Request Finished. State: " << worker->mState << " Discard: " << discard_level << LL_ENDL;
+			worker->unlockWorkMutex();
 		}
 		else
 		{
-			worker->lockWorkData();
+			worker->lockWorkMutex();
 			if ((worker->mDecodedDiscard >= 0) &&
 				(worker->mDecodedDiscard < discard_level || discard_level < 0) &&
 				(worker->mState >= LLTextureFetchWorker::WAIT_ON_WRITE))
 			{
 				// Not finished, but data is ready
 				discard_level = worker->mDecodedDiscard;
-				if (worker->mRawImage) raw = worker->mRawImage;
-				if (worker->mAuxImage) aux = worker->mAuxImage;
+				raw = worker->mRawImage;
+				aux = worker->mAuxImage;
 			}
-			worker->unlockWorkData();
+			worker->unlockWorkMutex();
 		}
 	}
 	else
@@ -1538,9 +1593,9 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
 	LLTextureFetchWorker* worker = getWorker(id);
 	if (worker)
 	{
-		worker->lockWorkData();
+		worker->lockWorkMutex();
 		worker->setImagePriority(priority);
-		worker->unlockWorkData();
+		worker->unlockWorkMutex();
 		res = true;
 	}
 	return res;
@@ -1548,40 +1603,106 @@ bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
 
 //////////////////////////////////////////////////////////////////////////////
 
+// MAIN THREAD
 //virtual
 S32 LLTextureFetch::update(U32 max_time_ms)
 {
 	S32 res;
+	
+	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
+	
 	res = LLWorkerThread::update(max_time_ms);
 	
-	const F32 REQUEST_TIME = 1.f;
-
-	// Periodically, gather the list of textures that need data from the network
-	// And send the requests out to the simulators
-	if (mNetworkTimer.getElapsedTimeF32() >= REQUEST_TIME)
+	if (!mDebugPause)
 	{
-		mNetworkTimer.reset();
 		sendRequestListToSimulators();
 	}
 	
 	return res;
 }
 
+// WORKER THREAD
+void LLTextureFetch::startThread()
+{
+	// Construct mCurlGetRequest from Worker Thread
+	mCurlGetRequest = new LLCurlRequest();
+}
+
+// WORKER THREAD
+void LLTextureFetch::endThread()
+{
+	// Destroy mCurlGetRequest from Worker Thread
+	delete mCurlGetRequest;
+	mCurlGetRequest = NULL;
+}
+
+// WORKER THREAD
+void LLTextureFetch::threadedUpdate()
+{
+	llassert_always(mCurlGetRequest);
+	
+	// Limit update frequency
+	const F32 PROCESS_TIME = 0.05f; 
+	static LLFrameTimer process_timer;
+	if (process_timer.getElapsedTimeF32() < PROCESS_TIME)
+	{
+		return;
+	}
+	process_timer.reset();
+	
+	// Update Curl on same thread as mCurlGetRequest was constructed
+	S32 processed = mCurlGetRequest->process();
+	if (processed > 0)
+	{
+		lldebugs << "processed: " << processed << " messages." << llendl;
+	}
+
+#if 0
+	const F32 INFO_TIME = 1.0f; 
+	static LLFrameTimer info_timer;
+	if (info_timer.getElapsedTimeF32() >= INFO_TIME)
+	{
+		S32 q = mCurlGetRequest->getQueued();
+		if (q > 0)
+		{
+			llinfos << "Queued gets: " << q << llendl;
+			info_timer.reset();
+		}
+	}
+#endif
+	
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 void LLTextureFetch::sendRequestListToSimulators()
 {
+	// All requests
+	const F32 REQUEST_DELTA_TIME = 0.10f; // 10 fps
+	
+	// Sim requests
 	const S32 IMAGES_PER_REQUEST = 50;
-	const F32 LAZY_FLUSH_TIMEOUT = 15.f; // 10.0f // temp
+	const F32 SIM_LAZY_FLUSH_TIMEOUT = 10.0f; // temp
 	const F32 MIN_REQUEST_TIME = 1.0f;
 	const F32 MIN_DELTA_PRIORITY = 1000.f;
 
-	LLMutexLock lock(&mQueueMutex);
+	// Periodically, gather the list of textures that need data from the network
+	// And send the requests out to the simulators
+	static LLFrameTimer timer;
+	if (timer.getElapsedTimeF32() < REQUEST_DELTA_TIME)
+	{
+		return;
+	}
+	timer.reset();
 	
+	LLMutexLock lock(&mQueueMutex);
+
 	// Send requests
 	typedef std::set<LLTextureFetchWorker*,LLTextureFetchWorker::Compare> request_list_t;
 	typedef std::map< LLHost, request_list_t > work_request_map_t;
 	work_request_map_t requests;
+	{
+	LLMutexLock lock2(&mNetworkQueueMutex);
 	for (queue_t::iterator iter = mNetworkQueue.begin(); iter != mNetworkQueue.end(); )
 	{
 		queue_t::iterator curiter = iter++;
@@ -1591,65 +1712,65 @@ void LLTextureFetch::sendRequestListToSimulators()
 			mNetworkQueue.erase(curiter);
 			continue; // paranoia
 		}
+		if ((req->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK) &&
+			(req->mState != LLTextureFetchWorker::LOAD_FROM_SIMULATOR))
+		{
+			// We already received our URL, remove from the queue
+			llwarns << "Worker: " << req->mID << " in mNetworkQueue but in wrong state: " << req->mState << llendl;
+			mNetworkQueue.erase(curiter);
+			continue;
+		}
 		if (req->mID == mDebugID)
 		{
 			mDebugCount++; // for setting breakpoints
 		}
-		if (req->mTotalPackets > 0 && req->mLastPacket >= req->mTotalPackets-1)
+		if (req->mSentRequest == LLTextureFetchWorker::SENT_SIM &&
+			req->mTotalPackets > 0 &&
+			req->mLastPacket >= req->mTotalPackets-1)
 		{
 			// We have all the packets... make sure this is high priority
 // 			req->setPriority(LLWorkerThread::PRIORITY_HIGH | req->mWorkPriority);
 			continue;
 		}
 		F32 elapsed = req->mRequestedTimer.getElapsedTimeF32();
-		F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority);
-		if ((req->mSimRequestedDiscard != req->mDesiredDiscard) ||
-			(delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) ||
-			(elapsed >= LAZY_FLUSH_TIMEOUT))
 		{
-			requests[req->mHost].insert(req);
+			F32 delta_priority = llabs(req->mRequestedPriority - req->mImagePriority);
+			if ((req->mSimRequestedDiscard != req->mDesiredDiscard) ||
+				(delta_priority > MIN_DELTA_PRIORITY && elapsed >= MIN_REQUEST_TIME) ||
+				(elapsed >= SIM_LAZY_FLUSH_TIMEOUT))
+			{
+				requests[req->mHost].insert(req);
+			}
 		}
 	}
-
-	std::string http_url;
-#if 0
-	if (gSavedSettings.getBOOL("ImagePipelineUseHTTP"))
-	{
-		LLViewerRegion* region = gAgent.getRegion();
-		if (region)
-		{
-			http_url = region->getCapability("RequestTextureDownload");
-		}
 	}
-#endif
-	
+
 	for (work_request_map_t::iterator iter1 = requests.begin();
 		 iter1 != requests.end(); ++iter1)
 	{
-		bool use_http = http_url.empty() ? false : true;
 		LLHost host = iter1->first;
 		// invalid host = use agent host
 		if (host == LLHost::invalid)
 		{
 			host = gAgent.getRegionHost();
 		}
-		else
-		{
-			use_http = false;
-		}
 
-		if (use_http)
+		S32 sim_request_count = 0;
+		
+		for (request_list_t::iterator iter2 = iter1->second.begin();
+			 iter2 != iter1->second.end(); ++iter2)
 		{
-		}
-		else
-		{
-			S32 request_count = 0;
-			for (request_list_t::iterator iter2 = iter1->second.begin();
-				 iter2 != iter1->second.end(); ++iter2)
+			LLTextureFetchWorker* req = *iter2;
+			if (gMessageSystem)
 			{
-				LLTextureFetchWorker* req = *iter2;
-				req->mSentRequest = LLTextureFetchWorker::SENT_SIM;
-				if (0 == request_count)
+				if (req->mSentRequest != LLTextureFetchWorker::SENT_SIM)
+				{
+					// Initialize packet data based on data read from cache
+					req->lockWorkMutex();
+					req->setupPacketData();
+					req->unlockWorkMutex();
+				}
+				if (0 == sim_request_count)
 				{
 					gMessageSystem->newMessageFast(_PREHASH_RequestImage);
 					gMessageSystem->nextBlockFast(_PREHASH_AgentData);
@@ -1666,30 +1787,42 @@ void LLTextureFetch::sendRequestListToSimulators()
 // 				llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard
 // 						<< " Packet: " << packet << " Priority: " << req->mImagePriority << llendl;
 
-				req->lockWorkData();
+				if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
+				{
+					mTextureInfo.setRequestStartTime(req->mID, LLTimer::getTotalTime());
+					mTextureInfo.setRequestOffset(req->mID, 0);
+					mTextureInfo.setRequestSize(req->mID, 0);
+					mTextureInfo.setRequestType(req->mID, LLTextureInfoDetails::REQUEST_TYPE_UDP);
+				}
+
+				req->lockWorkMutex();
+				req->mSentRequest = LLTextureFetchWorker::SENT_SIM;
 				req->mSimRequestedDiscard = req->mDesiredDiscard;
 				req->mRequestedPriority = req->mImagePriority;
 				req->mRequestedTimer.reset();
-				req->unlockWorkData();
-				request_count++;
-				if (request_count >= IMAGES_PER_REQUEST)
+				req->unlockWorkMutex();
+				sim_request_count++;
+				if (sim_request_count >= IMAGES_PER_REQUEST)
 				{
-// 					llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
+// 					llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
+
 					gMessageSystem->sendSemiReliable(host, NULL, NULL);
-					request_count = 0;
+					sim_request_count = 0;
 				}
 			}
-			if (request_count > 0 && request_count < IMAGES_PER_REQUEST)
-			{
-// 				llinfos << "REQUESTING " << request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
-				gMessageSystem->sendSemiReliable(host, NULL, NULL);
-				request_count = 0;
-			}
+		}
+		if (gMessageSystem && sim_request_count > 0 && sim_request_count < IMAGES_PER_REQUEST)
+		{
+// 			llinfos << "REQUESTING " << sim_request_count << " IMAGES FROM HOST: " << host.getIPString() << llendl;
+			gMessageSystem->sendSemiReliable(host, NULL, NULL);
+			sim_request_count = 0;
 		}
 	}
 	
 	// Send cancelations
-	if (!mCancelQueue.empty())
+	{
+	LLMutexLock lock2(&mNetworkQueueMutex);
+	if (gMessageSystem && !mCancelQueue.empty())
 	{
 		for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
 			 iter1 != mCancelQueue.end(); ++iter1)
@@ -1732,6 +1865,7 @@ void LLTextureFetch::sendRequestListToSimulators()
 		}
 		mCancelQueue.clear();
 	}
+	}
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -1808,7 +1942,7 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
 		return false;
 	}
 
-	worker->lockWorkData();
+	worker->lockWorkMutex();
 
 	//	Copy header data into image object
 	worker->mImageCodec = codec;
@@ -1819,7 +1953,7 @@ bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8
 	res = worker->insertPacket(0, data, data_size);
 	worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
 	worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
-	worker->unlockWorkData();
+	worker->unlockWorkMutex();
 	return res;
 }
 
@@ -1853,7 +1987,7 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
 		return false;
 	}
 
-	worker->lockWorkData();
+	worker->lockWorkMutex();
 	
 	res = worker->insertPacket(packet_num, data, data_size);
 	
@@ -1866,12 +2000,20 @@ bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U1
 	else
 	{
 // 		llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id
-// 			<< " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl;
-		removeFromNetworkQueue(worker); // failsafe
-		mCancelQueue[host].insert(id);
+// 				<< " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl;
+		removeFromNetworkQueue(worker, true); // failsafe
 	}
-	
-	worker->unlockWorkData();
+
+	if(packet_num >= (worker->mTotalPackets - 1))
+	{
+		if ((gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog")) || (gSavedSettings.getBOOL("LogTextureDownloadsToSimulator")))
+		{
+			U64 timeNow = LLTimer::getTotalTime();
+			mTextureInfo.setRequestSize(id, worker->mFileSize);
+			mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow);
+		}
+	}
+	worker->unlockWorkMutex();
 
 	return res;
 }
@@ -1885,9 +2027,9 @@ BOOL LLTextureFetch::isFromLocalCache(const LLUUID& id)
 	LLTextureFetchWorker* worker = getWorker(id);
 	if (worker)
 	{
-		worker->lockWorkData();
+		worker->lockWorkMutex() ;
 		from_cache = worker->mInLocalCache ;
-		worker->unlockWorkData();
+		worker->unlockWorkMutex() ;
 	}
 
 	return from_cache ;
@@ -1907,7 +2049,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
 	LLTextureFetchWorker* worker = getWorker(id);
 	if (worker && worker->haveWork())
 	{
-		worker->lockWorkData();
+		worker->lockWorkMutex();
 		state = worker->mState;
 		fetch_dtime = worker->mFetchTimer.getElapsedTimeF32();
 		request_dtime = worker->mRequestedTimer.getElapsedTimeF32();
@@ -1924,7 +2066,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
 				data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize;
 			}
 		}
-		if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::LOAD_FROM_HTTP_GET_DATA)
+		if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::WAIT_HTTP_REQ)
 		{
 			requested_priority = worker->mRequestedPriority;
 		}
@@ -1933,7 +2075,7 @@ S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& r
 			requested_priority = worker->mImagePriority;
 		}
 		fetch_priority = worker->getPriority();
-		worker->unlockWorkData();
+		worker->unlockWorkMutex();
 	}
 	data_progress_p = data_progress;
 	requested_priority_p = requested_priority;
@@ -1959,5 +2101,3 @@ void LLTextureFetch::dump()
 	}
 }
 
-
-//////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 97719a9468e7d1ddc727f190cb3a3dfc90ed28c7..373e38a83cbd399326d7ccf881d6dcba06f33b8d 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -37,26 +37,29 @@
 #include "llimage.h"
 #include "lluuid.h"
 #include "llworkerthread.h"
+#include "llcurl.h"
+#include "lltextureinfo.h"
 
 class LLViewerTexture;
 class LLTextureFetchWorker;
+class HTTPGetResponder;
 class LLTextureCache;
+class LLImageDecodeThread;
 class LLHost;
 
 // Interface class
 class LLTextureFetch : public LLWorkerThread
 {
 	friend class LLTextureFetchWorker;
+	friend class HTTPGetResponder;
 	
 public:
-	LLTextureFetch(LLTextureCache* cache, bool threaded);
+	LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded);
 	~LLTextureFetch();
 
 	/*virtual*/ S32 update(U32 max_time_ms);	
 
-	bool createRequest(const LLUUID& id, const LLHost& host, F32 priority,
-					   S32 w, S32 h, S32 c, S32 discard, bool needs_aux);
-	bool createRequest(const std::string& filename, const LLUUID& id, const LLHost& host, F32 priority,
+	bool createRequest(const std::string& url, const LLUUID& id, const LLHost& host, F32 priority,
 					   S32 w, S32 h, S32 c, S32 discard, bool needs_aux);
 	void deleteRequest(const LLUUID& id, bool cancel);
 	bool getRequestFinished(const LLUUID& id, S32& discard_level,
@@ -66,25 +69,39 @@ class LLTextureFetch : public LLWorkerThread
 	bool receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes, U16 data_size, U8* data);
 	bool receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data);
 
+	void setTextureBandwidth(F32 bandwidth) { mTextureBandwidth = bandwidth; }
+	F32 getTextureBandwidth() { return mTextureBandwidth; }
+	
 	// Debug
 	BOOL isFromLocalCache(const LLUUID& id);
 	S32 getFetchState(const LLUUID& id, F32& decode_progress_p, F32& requested_priority_p,
 					  U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p);
 	void dump();
 	S32 getNumRequests() { return mRequestMap.size(); }
+	S32 getNumHTTPRequests() { return mHTTPTextureQueue.size(); }
 	
 	// Public for access by callbacks
 	void lockQueue() { mQueueMutex.lock(); }
 	void unlockQueue() { mQueueMutex.unlock(); }
 	LLTextureFetchWorker* getWorker(const LLUUID& id);
+
+	LLTextureInfo* getTextureInfo() { return &mTextureInfo; }
 	
 protected:
 	void addToNetworkQueue(LLTextureFetchWorker* worker);
-	void removeFromNetworkQueue(LLTextureFetchWorker* worker);
+	void removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel);
+	void addToHTTPQueue(const LLUUID& id);
+	void removeFromHTTPQueue(const LLUUID& id);
+	S32 getHTTPQueueSize() { return (S32)mHTTPTextureQueue.size(); }
 	void removeRequest(LLTextureFetchWorker* worker, bool cancel);
+	// Called from worker thread (during doWork)
+	void processCurlRequests();	
 
 private:
 	void sendRequestListToSimulators();
+	/*virtual*/ void startThread(void);
+	/*virtual*/ void endThread(void);
+	/*virtual*/ void threadedUpdate(void);
 
 public:
 	LLUUID mDebugID;
@@ -95,8 +112,11 @@ class LLTextureFetch : public LLWorkerThread
 	
 private:
 	LLMutex mQueueMutex;
+	LLMutex mNetworkQueueMutex;
 
 	LLTextureCache* mTextureCache;
+	LLImageDecodeThread* mImageDecodeThread;
+	LLCurlRequest* mCurlGetRequest;
 	
 	// Map of all requests by UUID
 	typedef std::map<LLUUID,LLTextureFetchWorker*> map_t;
@@ -105,10 +125,13 @@ class LLTextureFetch : public LLWorkerThread
 	// Set of requests that require network data
 	typedef std::set<LLUUID> queue_t;
 	queue_t mNetworkQueue;
+	queue_t mHTTPTextureQueue;
 	typedef std::map<LLHost,std::set<LLUUID> > cancel_queue_t;
 	cancel_queue_t mCancelQueue;
-
-	LLFrameTimer mNetworkTimer;
+	F32 mTextureBandwidth;
+	F32 mMaxBandwidth;
+	LLTextureInfo mTextureInfo;
 };
 
 #endif // LL_LLTEXTUREFETCH_H
+
diff --git a/indra/newview/lltextureinfo.cpp b/indra/newview/lltextureinfo.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..672a36a8bd76f0dc5b98687f317d94e940d8d388
--- /dev/null
+++ b/indra/newview/lltextureinfo.cpp
@@ -0,0 +1,290 @@
+/** 
+ * @file lltextureinfo.cpp
+ * @brief Object which handles local texture info
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ * 
+ * Copyright (c) 2000-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 "lltextureinfo.h"
+#include "lltexturestats.h"
+#include "llviewercontrol.h"
+
+LLTextureInfo::LLTextureInfo() : 
+	mLogTextureDownloadsToViewerLog(false),
+	mLogTextureDownloadsToSimulator(false),
+	mTotalBytes(0),
+	mTotalMilliseconds(0),
+	mTextureDownloadsStarted(0),
+	mTextureDownloadsCompleted(0),
+	mTextureDownloadProtocol("NONE"),
+	mTextureLogThreshold(100 * 1024),
+	mCurrentStatsBundleStartTime(0)
+{
+	mTextures.clear();
+}
+
+void LLTextureInfo::setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold)
+{
+	mLogTextureDownloadsToViewerLog = writeToViewerLog;
+	mLogTextureDownloadsToSimulator = sendToSim;
+	mTextureLogThreshold = textureLogThreshold;
+}
+
+LLTextureInfo::~LLTextureInfo()
+{
+	std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator;
+	for (iterator = mTextures.begin(); iterator != mTextures.end(); iterator++)
+	{
+		LLTextureInfoDetails *info = (*iterator).second;
+		delete info;
+	}
+
+	mTextures.clear();
+}
+
+void LLTextureInfo::addRequest(const LLUUID& id)
+{
+	LLTextureInfoDetails *info = new LLTextureInfoDetails();
+	mTextures[id] = info;
+}
+
+U32 LLTextureInfo::getTextureInfoMapSize()
+{
+	return mTextures.size();
+}
+
+bool LLTextureInfo::has(const LLUUID& id)
+{
+	std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+	if (iterator == mTextures.end())
+	{
+		return false;
+	}
+	else
+	{
+		return true;
+	}
+}
+
+void LLTextureInfo::setRequestStartTime(const LLUUID& id, U64 startTime)
+{
+	if (!has(id))
+	{
+		addRequest(id);
+	}
+	mTextures[id]->mStartTime = startTime;
+	mTextureDownloadsStarted++;
+}
+
+void LLTextureInfo::setRequestSize(const LLUUID& id, U32 size)
+{
+	if (!has(id))
+	{
+		addRequest(id);
+	}
+	mTextures[id]->mSize = size;
+}
+
+void LLTextureInfo::setRequestOffset(const LLUUID& id, U32 offset)
+{
+	if (!has(id))
+	{
+		addRequest(id);
+	}
+	mTextures[id]->mOffset = offset;
+}
+
+void LLTextureInfo::setRequestType(const LLUUID& id, LLTextureInfoDetails::LLRequestType type)
+{
+	if (!has(id))
+	{
+		addRequest(id);
+	}
+	mTextures[id]->mType = type;
+}
+
+void LLTextureInfo::setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime)
+{
+	if (!has(id))
+	{
+		addRequest(id);
+	}
+	mTextures[id]->mCompleteTime = completeTime;
+
+	std::string protocol = "NONE";
+	switch(mTextures[id]->mType)
+	{
+	case LLTextureInfoDetails::REQUEST_TYPE_HTTP:
+		protocol = "HTTP";
+		break;
+
+	case LLTextureInfoDetails::REQUEST_TYPE_UDP:
+		protocol = "UDP";
+		break;
+
+	case LLTextureInfoDetails::REQUEST_TYPE_NONE:
+	default:
+		break;
+	}
+
+	if (mLogTextureDownloadsToViewerLog)
+	{
+		llinfos << "texture=" << id 
+			<< " start=" << mTextures[id]->mStartTime 
+			<< " end=" << mTextures[id]->mCompleteTime
+			<< " size=" << mTextures[id]->mSize
+			<< " offset=" << mTextures[id]->mOffset
+			<< " length_in_ms=" << (mTextures[id]->mCompleteTime - mTextures[id]->mStartTime) / 1000
+			<< " protocol=" << protocol
+			<< llendl;
+	}
+
+	if(mLogTextureDownloadsToSimulator)
+	{
+		S32 texture_stats_upload_threshold = mTextureLogThreshold;
+		mTotalBytes += mTextures[id]->mSize;
+		mTotalMilliseconds += mTextures[id]->mCompleteTime - mTextures[id]->mStartTime;
+		mTextureDownloadsCompleted++;
+		mTextureDownloadProtocol = protocol;
+		if (mTotalBytes >= texture_stats_upload_threshold)
+		{
+			LLSD texture_data;
+			std::stringstream startTime;
+			startTime << mCurrentStatsBundleStartTime;
+			texture_data["start_time"] = startTime.str();
+			std::stringstream endTime;
+			endTime << completeTime;
+			texture_data["end_time"] = endTime.str();
+			texture_data["averages"] = getAverages();
+			send_texture_stats_to_sim(texture_data);
+			resetTextureStatistics();
+		}
+	}
+
+	mTextures.erase(id);
+}
+
+LLSD LLTextureInfo::getAverages()
+{
+	LLSD averagedTextureData;
+	S32 averageDownloadRate;
+	if(mTotalMilliseconds == 0)
+	{
+		averageDownloadRate = 0;
+	}
+	else
+	{
+		averageDownloadRate = (mTotalBytes * 8) / mTotalMilliseconds;
+	}
+
+	averagedTextureData["bits_per_second"] = averageDownloadRate;
+	averagedTextureData["bytes_downloaded"] = mTotalBytes;
+	averagedTextureData["texture_downloads_started"] = mTextureDownloadsStarted;
+	averagedTextureData["texture_downloads_completed"] = mTextureDownloadsCompleted;
+	averagedTextureData["transport"] = mTextureDownloadProtocol;
+
+	return averagedTextureData;
+}
+
+void LLTextureInfo::resetTextureStatistics()
+{
+	mTotalMilliseconds = 0;
+	mTotalBytes = 0;
+	mTextureDownloadsStarted = 0;
+	mTextureDownloadsCompleted = 0;
+	mTextureDownloadProtocol = "NONE";
+	mCurrentStatsBundleStartTime = LLTimer::getTotalTime();
+}
+
+U32 LLTextureInfo::getRequestStartTime(const LLUUID& id)
+{
+	if (!has(id))
+	{
+		return 0;
+	}
+	else
+	{
+		std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+		return (*iterator).second->mStartTime;
+	}
+}
+
+U32 LLTextureInfo::getRequestSize(const LLUUID& id)
+{
+	if (!has(id))
+	{
+		return 0;
+	}
+	else
+	{
+		std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+		return (*iterator).second->mSize;
+	}
+}
+
+U32 LLTextureInfo::getRequestOffset(const LLUUID& id)
+{
+	if (!has(id))
+	{
+		return 0;
+	}
+	else
+	{
+		std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+		return (*iterator).second->mOffset;
+	}
+}
+
+LLTextureInfoDetails::LLRequestType LLTextureInfo::getRequestType(const LLUUID& id)
+{
+	if (!has(id))
+	{
+		return LLTextureInfoDetails::REQUEST_TYPE_NONE;
+	}
+	else
+	{
+		std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+		return (*iterator).second->mType;
+	}
+}
+
+U32 LLTextureInfo::getRequestCompleteTime(const LLUUID& id)
+{
+	if (!has(id))
+	{
+		return 0;
+	}
+	else
+	{
+		std::map<LLUUID, LLTextureInfoDetails *>::iterator iterator = mTextures.find(id);
+		return (*iterator).second->mCompleteTime;
+	}
+}
+
diff --git a/indra/newview/lltextureinfo.h b/indra/newview/lltextureinfo.h
new file mode 100644
index 0000000000000000000000000000000000000000..71b0ea431fdddf1a00a8b35f6082d0c1ce14431e
--- /dev/null
+++ b/indra/newview/lltextureinfo.h
@@ -0,0 +1,80 @@
+/** 
+ * @file lltextureinfo.h
+ * @brief Object for managing texture information.
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ * 
+ * Copyright (c) 2000-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_LLTEXTUREINFO_H
+#define LL_LLTEXTUREINFO_H
+
+#include "lluuid.h"
+#include "lltextureinfodetails.h"
+#include <map>
+
+class LLTextureInfo
+{
+public:
+	LLTextureInfo();
+	~LLTextureInfo();
+
+	void setUpLogging(bool writeToViewerLog, bool sendToSim, U32 textureLogThreshold);
+	bool has(const LLUUID& id);
+	void setRequestStartTime(const LLUUID& id, U64 startTime);
+	void setRequestSize(const LLUUID& id, U32 size);
+	void setRequestOffset(const LLUUID& id, U32 offset);
+	void setRequestType(const LLUUID& id, LLTextureInfoDetails::LLRequestType type);
+	void setRequestCompleteTimeAndLog(const LLUUID& id, U64 completeTime);
+	U32 getRequestStartTime(const LLUUID& id);
+	U32 getRequestSize(const LLUUID& id);
+	U32 getRequestOffset(const LLUUID& id);
+	LLTextureInfoDetails::LLRequestType getRequestType(const LLUUID& id);
+	U32 getRequestCompleteTime(const LLUUID& id);
+	void resetTextureStatistics();
+	U32 getTextureInfoMapSize();
+	LLSD getAverages();
+
+private:
+	void addRequest(const LLUUID& id);
+
+	std::map<LLUUID, LLTextureInfoDetails *> mTextures;
+
+	LLSD mAverages;
+
+	bool mLogTextureDownloadsToViewerLog;
+	bool mLogTextureDownloadsToSimulator;
+	S32 mTotalBytes;
+	S32 mTotalMilliseconds;
+	S32 mTextureDownloadsStarted;
+	S32 mTextureDownloadsCompleted;
+	std::string mTextureDownloadProtocol;
+	U32 mTextureLogThreshold; // in bytes
+	U64 mCurrentStatsBundleStartTime;
+};
+
+#endif // LL_LLTEXTUREINFO_H
diff --git a/indra/newview/lltextureinfodetails.cpp b/indra/newview/lltextureinfodetails.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f6ef47a2ee5460bcece0336bd54c44cbe2110705
--- /dev/null
+++ b/indra/newview/lltextureinfodetails.cpp
@@ -0,0 +1,40 @@
+/** 
+ * @file lltextureinfodetails.cpp
+ * @brief Object which handles details of any individual texture
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ * 
+ * Copyright (c) 2000-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 "lltextureinfodetails.h"
+
+LLTextureInfoDetails::LLTextureInfoDetails() : mStartTime(0), mCompleteTime(0), mSize(0), mType(REQUEST_TYPE_NONE), mOffset(0)
+{
+}
+
diff --git a/indra/newview/lltextureinfodetails.h b/indra/newview/lltextureinfodetails.h
new file mode 100644
index 0000000000000000000000000000000000000000..091fa01a3d7fe1829168b62ecaf4097bab654e78
--- /dev/null
+++ b/indra/newview/lltextureinfodetails.h
@@ -0,0 +1,58 @@
+/** 
+ * @file lltextureinfo.h
+ * @brief Object for managing texture information.
+ *
+ * $LicenseInfo:firstyear=2000&license=viewergpl$
+ * 
+ * Copyright (c) 2000-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_LLTEXTUREINFODETAILS_H
+#define LL_LLTEXTUREINFODETAILS_H
+
+#include "lluuid.h"
+
+class LLTextureInfoDetails
+{
+public:
+	enum LLRequestType
+	{
+		REQUEST_TYPE_NONE,
+		REQUEST_TYPE_HTTP,
+		REQUEST_TYPE_UDP
+	};
+
+	U32 mStartTime;
+	U32 mCompleteTime;
+	U32 mOffset;
+	U32 mSize;
+	LLRequestType mType;
+
+	LLTextureInfoDetails();
+};
+
+#endif // LL_LLTEXTUREINFODETAILS_H
+
diff --git a/indra/newview/lltexturestats.cpp b/indra/newview/lltexturestats.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c91bfd4df2a8c50bc059b2b29e3d21b417ba006c
--- /dev/null
+++ b/indra/newview/lltexturestats.cpp
@@ -0,0 +1,61 @@
+/** 
+ * @file lltexturerstats.cpp
+ * @brief texture stats helper methods
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-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 "pipeline.h" 
+#include "llagent.h"
+#include "lltexturefetch.h" 
+#include "lltexturestats.h"
+#include "lltexturestatsuploader.h"
+#include "llviewerregion.h"
+
+void send_texture_stats_to_sim(const LLSD &texture_stats)
+{
+	LLSD texture_stats_report;
+	// Only send stats if the agent is connected to a region.
+	if (!gAgent.getRegion() || gNoRender)
+	{
+		return;
+	}
+
+	LLUUID agent_id = gAgent.getID();
+	texture_stats_report["agent_id"] = agent_id;
+	texture_stats_report["region_id"] = gAgent.getRegion()->getRegionID();
+	texture_stats_report["stats_data"] = texture_stats;
+
+	std::string texture_cap_url = gAgent.getRegion()->getCapability("TextureStats");
+	LLTextureStatsUploader tsu;
+	llinfos << "uploading texture stats data to simulator" << llendl;
+	tsu.uploadStatsToSimulator(texture_cap_url, texture_stats);
+}
+
diff --git a/indra/newview/lltexturestats.h b/indra/newview/lltexturestats.h
new file mode 100644
index 0000000000000000000000000000000000000000..2deb377dfdd13c809d1ccb014bffca437d9eb29b
--- /dev/null
+++ b/indra/newview/lltexturestats.h
@@ -0,0 +1,41 @@
+/** 
+ * @file lltexturestats.h
+ * @brief texture stats utilities
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 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_LLTEXTURESTATS_H
+#define LL_LLTEXTURESTATS_H
+
+#include "llappviewer.h"
+
+// utility functions to capture data on texture download speeds and send to simulator periodically
+void send_texture_stats_to_sim(const LLSD &texture_stats);
+
+#endif // LL_LLTEXTURESTATS_H
diff --git a/indra/newview/lltexturestatsuploader.cpp b/indra/newview/lltexturestatsuploader.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e0358e1fcafbdff4d942df50d8534df18871f457
--- /dev/null
+++ b/indra/newview/lltexturestatsuploader.cpp
@@ -0,0 +1,59 @@
+/** 
+ * @file lltexturerstats.cpp
+ * @brief texture stats upload class
+ *
+ * $LicenseInfo:firstyear=2002&license=viewergpl$
+ * 
+ * Copyright (c) 2002-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 "lltexturestatsuploader.h"
+
+LLTextureStatsUploader::LLTextureStatsUploader()
+{
+}
+
+LLTextureStatsUploader::~LLTextureStatsUploader()
+{
+}
+
+void LLTextureStatsUploader::uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats)
+{
+	if ( texture_cap_url != "" )
+	{
+		LLHTTPClient::post(texture_cap_url, texture_stats, NULL);
+	}
+	else
+	{
+		llinfos << "Not sending texture stats: " 
+				<< texture_stats 
+				<< " as there is no cap url." 
+				<< llendl;
+	}
+}
+
diff --git a/indra/newview/lltexturestatsuploader.h b/indra/newview/lltexturestatsuploader.h
new file mode 100644
index 0000000000000000000000000000000000000000..f6cc8be8fe9aec874694a543023bc4bbbe74746f
--- /dev/null
+++ b/indra/newview/lltexturestatsuploader.h
@@ -0,0 +1,48 @@
+/** 
+ * @file lltexturestatsuploader.h
+ * @brief Class to send the texture stats to the simulatore
+ *
+ * $LicenseInfo:firstyear=2009&license=viewergpl$
+ * 
+ * Copyright (c) 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_LLTEXTURESTATSUPLOADER_H
+#define LL_LLTEXTURESTATSUPLOADER_H
+
+#include "llappviewer.h"
+
+// utility functions to capture data on texture download speeds and send to simulator periodically
+
+class LLTextureStatsUploader
+{
+public:
+	LLTextureStatsUploader();
+	~LLTextureStatsUploader();
+	void uploadStatsToSimulator(const std::string texture_cap_url, const LLSD &texture_stats);
+};
+
+#endif // LL_LLTEXTURESTATSUPLOADER_H
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index ea675c5a6e48646fa51113f7a1f277b3fc04e46f..44ef6717e7019ab3b864c75ecb034f7f5612f544 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -44,19 +44,21 @@
 #include "llrender.h"
 
 #include "lltooltip.h"
+#include "llappviewer.h"
 #include "llselectmgr.h"
 #include "lltexlayer.h"
 #include "lltexturecache.h"
 #include "lltexturefetch.h"
+#include "llviewercontrol.h"
 #include "llviewerobject.h"
 #include "llviewertexture.h"
 #include "llviewertexturelist.h"
-#include "llappviewer.h"
-
+#include "llvovolume.h"
 extern F32 texmem_lower_bound_scale;
 
 LLTextureView *gTextureView = NULL;
 LLTextureSizeView *gTextureSizeView = NULL;
+LLTextureSizeView *gTextureCategoryView = NULL;
 
 //static
 std::set<LLViewerFetchedTexture*> LLTextureView::sDebugImages;
@@ -230,10 +232,10 @@ void LLTextureBar::draw()
 		{ "DSK", LLColor4::blue },	// CACHE_POST
 		{ "NET", LLColor4::green },	// LOAD_FROM_NETWORK
 		{ "SIM", LLColor4::green },	// LOAD_FROM_SIMULATOR
-		{ "URL", LLColor4::green2 },// LOAD_FROM_HTTP_GET_URL
-		{ "HTP", LLColor4::green },	// LOAD_FROM_HTTP_GET_DATA
+		{ "REQ", LLColor4::yellow },// SEND_HTTP_REQ
+		{ "HTP", LLColor4::green },	// WAIT_HTTP_REQ
 		{ "DEC", LLColor4::yellow },// DECODE_IMAGE
-		{ "DEC", LLColor4::yellow },// DECODE_IMAGE_UPDATE
+		{ "DEC", LLColor4::green }, // DECODE_IMAGE_UPDATE
 		{ "WRT", LLColor4::purple },// WRITE_TO_CACHE
 		{ "WRT", LLColor4::orange },// WAIT_ON_WRITE
 		{ "END", LLColor4::red },   // DONE
@@ -261,7 +263,7 @@ void LLTextureBar::draw()
 
 	// Draw the progress bar.
 	S32 bar_width = 100;
-	S32 bar_left = 280;
+	S32 bar_left = 260;
 	left = bar_left;
 	right = left + bar_width;
 
@@ -286,30 +288,31 @@ void LLTextureBar::draw()
 	S32 pip_x = title_x3 + pip_space/2;
 	
 	// Draw the packet pip
+	const F32 pip_max_time = 5.f;
 	F32 last_event = mImagep->mLastPacketTimer.getElapsedTimeF32();
-	if (last_event < 1.f)
+	if (last_event < pip_max_time)
 	{
 		clr = LLColor4::white; 
 	}
 	else
 	{
 		last_event = mImagep->mRequestDeltaTime;
-		if (last_event < 1.f)
+		if (last_event < pip_max_time)
 		{
 			clr = LLColor4::green;
 		}
 		else
 		{
 			last_event = mImagep->mFetchDeltaTime;
-			if (last_event < 1.f)
+			if (last_event < pip_max_time)
 			{
 				clr = LLColor4::yellow;
 			}
 		}
 	}
-	if (last_event < 1.f)
+	if (last_event < pip_max_time)
 	{
-		clr.setAlpha(1.f - last_event);
+		clr.setAlpha(1.f - last_event/pip_max_time);
 		gGL.color4fv(clr.mV);
 		gl_rect_2d(pip_x, top, pip_x + pip_width, bottom);
 	}
@@ -406,89 +409,113 @@ void LLGLTexMemBar::draw()
 	S32 total_mem = BYTES_TO_MEGA_BYTES(LLViewerTexture::sTotalTextureMemoryInBytes);
 	S32 max_total_mem = LLViewerTexture::sMaxTotalTextureMemInMegaBytes;
 	F32 discard_bias = LLViewerTexture::sDesiredDiscardBias;
+	F32 cache_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getUsage()) ;
+	F32 cache_max_usage = (F32)BYTES_TO_MEGA_BYTES(LLAppViewer::getTextureCache()->getMaxUsage()) ;
 	S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
 	S32 h_offset = (S32)((texture_bar_height + 2.5f) * mTextureView->mNumTextureBars + 2.5f);
 	//----------------------------------------------------------------------------
 	LLGLSUIDefault gls_ui;
-	F32 text_color[] = {1.f, 1.f, 1.f, 0.75f};
+	LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
+	LLColor4 color;
 	
 	std::string text;
-	text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Discard Bias: %.2f",
+	text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB",
 					total_mem,
 					max_total_mem,
 					bound_mem,
 					max_bound_mem,
-					discard_bias);
+					LLImageRaw::sGlobalRawMemory >> 20,					discard_bias,
+					cache_usage, cache_max_usage);
+	//, cache_entries, cache_max_entries
 
 	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, h_offset + line_height*3,
-									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+											 text_color, LLFontGL::LEFT, LLFontGL::TOP);
 
 	//----------------------------------------------------------------------------
-	S32 bar_left = 380;
+#if 0
+	S32 bar_left = 400;
 	S32 bar_width = 200;
 	S32 top = line_height*3 - 2 + h_offset;
 	S32 bottom = top - 6;
 	S32 left = bar_left;
 	S32 right = left + bar_width;
-
-	F32 bar_scale = (F32)bar_width / (max_bound_mem * 1.5f);
+	F32 bar_scale;
 	
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	
-	gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f);
-	gl_rect_2d(left, top, right, bottom);
 
-	
+	// GL Mem Bar
+		
 	left = bar_left;
-	right = left + llfloor(bound_mem * bar_scale);
-	if (bound_mem < llfloor(max_bound_mem * texmem_lower_bound_scale))
-	{
-		gGL.color4f(0.f, 1.f, 0.f, 0.75f);
-	}
-	else if (bound_mem < max_bound_mem)
-	{
-		gGL.color4f(1.f, 1.f, 0.f, 0.75f);
-	}
-	else
-	{
-		gGL.color4f(1.f, 0.f, 0.f, 0.75f);
-	}
+	text = "GL";
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, line_height*3,
+											 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	
+	left = bar_left+20;
+	right = left + bar_width;
+	
+	gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f); // grey
 	gl_rect_2d(left, top, right, bottom);
 
 	bar_scale = (F32)bar_width / (max_total_mem * 1.5f);
+	right = left + llfloor(total_mem * bar_scale);
+	right = llclamp(right, bar_left, bar_left + bar_width);
 	
-	top = bottom - 2;
-	bottom = top - 6;
+	color = (total_mem < llfloor(max_total_mem * texmem_lower_bound_scale)) ? LLColor4::green :
+		  	(total_mem < max_total_mem) ? LLColor4::yellow : LLColor4::red;
+	color[VALPHA] = .75f;
+	glColor4fv(color.mV);
+	
+	gl_rect_2d(left, top, right, bottom); // red/yellow/green
+
+	//
+	bar_left += bar_width + bar_space;
+	//top = bottom - 2; bottom = top - 6;
+	
+	// Bound Mem Bar
+
 	left = bar_left;
-	right = left + llfloor(total_mem * bar_scale);
-	if (total_mem < llfloor(max_total_mem * texmem_lower_bound_scale))
-	{
-		gGL.color4f(0.f, 1.f, 0.f, 0.75f);
-	}
-	else if (total_mem < max_total_mem)
-	{
-		gGL.color4f(1.f, 1.f, 0.f, 0.75f);
-	}
-	else
-	{
-		gGL.color4f(1.f, 0.f, 0.f, 0.75f);
-	}
+	text = "GL";
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, line_height*3,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	left = bar_left + 20;
+	right = left + bar_width;
+	
+	gGL.color4f(0.5f, 0.5f, 0.5f, 0.75f);
 	gl_rect_2d(left, top, right, bottom);
 
+	color = (bound_mem < llfloor(max_bound_mem * texmem_lower_bound_scale)) ? LLColor4::green :
+		  	(bound_mem < max_bound_mem) ? LLColor4::yellow : LLColor4::red;
+	color[VALPHA] = .75f;
+	glColor4fv(color.mV);
+
+	gl_rect_2d(left, top, right, bottom);
+#else
+	S32 left = 0 ;
+#endif
 	//----------------------------------------------------------------------------
 
-	text = llformat("Textures: Count: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d IW:%d(%d) RAW:%d mRaw:%d mAux:%d CB:%d",
+	text = llformat("Textures: %d Fetch: %d(%d) Pkts:%d(%d) Cache R/W: %d/%d LFS:%d IW:%d RAW:%d HTP:%d",
 					gTextureList.getNumImages(),
 					LLAppViewer::getTextureFetch()->getNumRequests(), LLAppViewer::getTextureFetch()->getNumDeletes(),
 					LLAppViewer::getTextureFetch()->mPacketCount, LLAppViewer::getTextureFetch()->mBadPacketCount, 
 					LLAppViewer::getTextureCache()->getNumReads(), LLAppViewer::getTextureCache()->getNumWrites(),
 					LLLFSThread::sLocal->getPending(),
-					LLImageWorker::sCount, LLImageWorker::getWorkerThread()->getNumDeletes(),
-					LLImageRaw::sRawImageCount, LLViewerFetchedTexture::sRawCount, LLViewerFetchedTexture::sAuxCount,
-					gTextureList.mCallbackList.size());
+					LLAppViewer::getImageDecodeThread()->getPending(), 
+					LLImageRaw::sRawImageCount,
+					LLAppViewer::getTextureFetch()->getNumHTTPRequests());
 
 	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, h_offset + line_height*2,
 									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+
+	left = 550;
+	F32 bandwidth = LLAppViewer::getTextureFetch()->getTextureBandwidth();
+	F32 max_bandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
+	color = bandwidth > max_bandwidth ? LLColor4::red : bandwidth > max_bandwidth*.75f ? LLColor4::yellow : text_color;
+	color[VALPHA] = text_color[VALPHA];
+	text = llformat("BW:%.0f/%.0f",bandwidth, max_bandwidth);
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left, line_height*2,
+											 color, LLFontGL::LEFT, LLFontGL::TOP);
 	
 	S32 dx1 = 0;
 	if (LLAppViewer::getTextureFetch()->mDebugPause)
@@ -555,7 +582,7 @@ class LLGLTexSizeBar
 	void setTop(S32 loaded, S32 bound, F32 scale) {mTopLoaded = loaded ; mTopBound = bound; mScale = scale ;}
 
 	void draw();	
-	BOOL handleHover(S32 x, S32 y, MASK mask) ;
+	BOOL handleHover(S32 x, S32 y, MASK mask, BOOL set_pick_size) ;
 	
 private:
 	S32 mIndex ;
@@ -568,19 +595,16 @@ class LLGLTexSizeBar
 	F32 mScale ;
 };
 
-BOOL LLGLTexSizeBar::handleHover(S32 x, S32 y, MASK mask) 
+BOOL LLGLTexSizeBar::handleHover(S32 x, S32 y, MASK mask, BOOL set_pick_size) 
 {
-#if !LL_RELEASE_FOR_DOWNLOAD
 	if(y > mBottom && (y < mBottom + (S32)(mTopLoaded * mScale) || y < mBottom + (S32)(mTopBound * mScale)))
 	{
-		LLImageGL::setCurTexSizebar(mIndex);
+		LLImageGL::setCurTexSizebar(mIndex, set_pick_size);
 	}
-#endif
 	return TRUE ;
 }
 void LLGLTexSizeBar::draw()
 {
-#if !LL_RELEASE_FOR_DOWNLOAD
 	LLGLSUIDefault gls_ui;
 
 	if(LLImageGL::sCurTexSizeBar == mIndex)
@@ -601,7 +625,6 @@ void LLGLTexSizeBar::draw()
 	F32 bound_color[] = {1.0f, 1.0f, 0.0f, 0.75f};
 	gl_rect_2d(mLeft, mBottom + (S32)(mTopLoaded * mScale), (mLeft + mRight) / 2, mBottom, loaded_color) ;
 	gl_rect_2d((mLeft + mRight) / 2, mBottom + (S32)(mTopBound * mScale), mRight, mBottom, bound_color) ;
-#endif
 }
 ////////////////////////////////////////////////////////////////////////////
 
@@ -675,7 +698,13 @@ void LLTextureView::draw()
 						<< "\t" << cur_discard
 						<< llendl;
 			}
-		
+
+			if (imagep->getID() == LLAppViewer::getTextureFetch()->mDebugID)
+			{
+				static S32 debug_count = 0;
+				++debug_count; // for breakpoints
+			}
+			
 #if 0
 			if (imagep->getDontDiscard())
 			{
@@ -889,8 +918,7 @@ BOOL LLTextureView::handleKey(KEY key, MASK mask, BOOL called_from_parent)
 }
 
 //-----------------------------------------------------------------
-LLTextureSizeView::LLTextureSizeView(const LLTextureSizeView::Params& p)
-	: LLView(p)
+LLTextureSizeView::LLTextureSizeView(const LLTextureSizeView::Params& p) : LLContainerView(p)
 {
 	setVisible(FALSE) ;
 
@@ -910,7 +938,31 @@ LLTextureSizeView::~LLTextureSizeView()
 }
 void LLTextureSizeView::draw()
 {
-#if !LL_RELEASE_FOR_DOWNLOAD
+	if(mType == TEXTURE_MEM_OVER_SIZE)
+	{
+		drawTextureSizeGraph();
+	}
+	else
+	{
+		drawTextureCategoryGraph() ;
+	}
+	
+	LLView::draw();
+}
+
+BOOL LLTextureSizeView::handleHover(S32 x, S32 y, MASK mask) 
+{
+	if(x > mTextureSizeBarRect.mLeft && x < mTextureSizeBarRect.mRight)
+	{
+		mTextureSizeBar[(x - mTextureSizeBarRect.mLeft) / mTextureSizeBarWidth]->handleHover(x, y, mask, (mType == TEXTURE_MEM_OVER_SIZE)) ;
+	}
+
+	return TRUE ;
+}
+
+//draw real-time texture mem bar over size
+void LLTextureSizeView::drawTextureSizeGraph()
+{
 	if(mTextureSizeBar.size() == 0)
 	{
 		S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
@@ -931,29 +983,16 @@ void LLTextureSizeView::draw()
 		mTextureSizeBar[i]->draw() ;
 	}		
 	LLImageGL::resetCurTexSizebar();
-
-	LLView::draw();
-#endif
-}
-
-BOOL LLTextureSizeView::handleHover(S32 x, S32 y, MASK mask) 
-{
-	if(x > mTextureSizeBarRect.mLeft && x < mTextureSizeBarRect.mRight)
-	{
-		mTextureSizeBar[(x - mTextureSizeBarRect.mLeft) / mTextureSizeBarWidth]->handleHover(x, y, mask) ;
-	}
-
-	return TRUE ;
 }
 
 //draw background of texture size bar graph
 F32 LLTextureSizeView::drawTextureSizeDistributionGraph()
 {	
+	//scale
 	F32 scale = 1.0f ;
-#if !LL_RELEASE_FOR_DOWNLOAD
+	
 	LLGLSUIDefault gls_ui;
 
-	//scale	
 	{
 		S32 count = 0 ;
 		for(U32 i = 0 ; i < LLImageGL::sTextureLoadedCounter.size() ; i++)
@@ -1043,8 +1082,137 @@ F32 LLTextureSizeView::drawTextureSizeDistributionGraph()
 	text = llformat("Texture Size Distribution") ;
 	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 250, top + line_height * 3,
 									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
-
-#endif	
 	return scale ;
 }
 
+//draw real-time texture mem bar over category
+void LLTextureSizeView::drawTextureCategoryGraph()
+{
+	if(mTextureSizeBar.size() == 0)
+	{
+		S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
+		mTextureSizeBar.resize(LLViewerTexture::getTotalNumOfCategories()) ;
+		mTextureSizeBarRect.set(700, line_height * 2 + 400, 700 + mTextureSizeBar.size() * mTextureSizeBarWidth, line_height * 2) ;
+		
+		for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++)
+		{				
+			mTextureSizeBar[i] = new LLGLTexSizeBar(i, mTextureSizeBarRect.mLeft + i * mTextureSizeBarWidth , 
+				line_height * 2, mTextureSizeBarRect.mLeft + (i + 1) * mTextureSizeBarWidth, line_height) ;				
+		}			
+	}
+
+	F32 size_bar_scale = drawTextureCategoryDistributionGraph() ;		
+	for(U32 i = 0 ; i < mTextureSizeBar.size() ; i++)
+	{
+		U32 k = LLViewerTexture::getIndexFromCategory(i) ;
+		mTextureSizeBar[i]->setTop(LLImageGL::sTextureMemByCategory[k] >> 20, LLImageGL::sTextureMemByCategoryBound[k] >> 20, size_bar_scale) ;
+		mTextureSizeBar[i]->draw() ;
+	}		
+	LLImageGL::resetCurTexSizebar();
+}
+
+//draw background for TEXTURE_MEM_OVER_CATEGORY
+F32 LLTextureSizeView::drawTextureCategoryDistributionGraph() 
+{
+	//scale
+	F32 scale = 4.0f ;
+	
+	LLGLSUIDefault gls_ui;
+
+	{
+		S32 count = 0 ;
+		for(U32 i = 0 ; i < LLImageGL::sTextureMemByCategory.size() ; i++)
+		{
+			S32 tmp = LLImageGL::sTextureMemByCategory[i] >> 20 ;
+			if(tmp > count)
+			{
+				count = tmp ;
+			}
+		}
+		if(count > mTextureSizeBarRect.getHeight() * 0.25f)
+		{
+			scale = (F32)mTextureSizeBarRect.getHeight() * 0.25f / count ;
+		}
+	}
+
+	S32 line_height = (S32)(LLFontGL::getFontMonospace()->getLineHeight() + .5f);
+	S32 left = mTextureSizeBarRect.mLeft ;
+	S32 bottom = mTextureSizeBarRect.mBottom ;
+	S32 right = mTextureSizeBarRect.mRight ;
+	S32 top = mTextureSizeBarRect.mTop ;
+
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	
+	//background rect
+	gl_rect_2d(left - 25, top + 30, right + 100, bottom - 25, LLColor4(0.0f, 0.0f, 0.0f, 0.25f)) ;
+
+	//--------------------------------------------------
+	gGL.color4f(1.0f, 0.5f, 0.5f, 0.75f);
+	gl_line_2d(left, bottom, right, bottom) ; //x axis
+	gl_line_2d(left, bottom, left, top) ; //y axis
+
+	//ruler
+	//--------------------------------------------------
+	gGL.color4f(1.0f, 0.5f, 0.5f, 0.5f);
+	for(S32 i = bottom + 50 ; i <= top ; i += 50)
+	{
+		gl_line_2d(left, i, right, i) ;
+	}
+
+	//texts
+	//--------------------------------------------------
+	F32 text_color[] = {1.f, 1.f, 1.f, 0.75f};	
+	std::string text;
+	
+	//-------
+	//x axis: size label			
+	static char category[LLViewerTexture::MAX_GL_IMAGE_CATEGORY][4] = 
+	{"Non", "Bak", "Av", "Cld", "Scp", "Hi", "Trn", "Slt", "Hud", "Bsf", "UI", "Pvw", "Map", "Mvs", "Slf", "Loc", "Scr", "Dyn", "Mdi", "ALT", "Oth" } ;
+
+	text = llformat("%s", category[0]) ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 12, bottom - line_height / 2,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	for(U32 i = 1 ; i < mTextureSizeBar.size() ; i++)
+	{
+		text = llformat("%s", category[i]) ;
+		LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + i * mTextureSizeBarWidth + 12, bottom - line_height / 2,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	}
+	//-------
+
+	//y axis: number label
+	for(S32 i = bottom + 50 ; i <= top ; i += 50)
+	{
+		text = llformat("%d", (S32)((i - bottom) / scale)) ;
+		LLFontGL::getFontMonospace()->renderUTF8(text, 0, left - 20, i + line_height / 2 ,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+		LLFontGL::getFontMonospace()->renderUTF8(text, 0, right + 5, i + line_height / 2 ,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	}
+
+	text = llformat("MB") ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left - 20, top + line_height * 2 ,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+	//--------------------------------------------------
+	F32 loaded_color[] = {1.0f, 0.0f, 0.0f, 0.75f};
+	gl_rect_2d(left + 70, top + line_height * 2, left + 90, top + line_height, loaded_color) ;
+	text = llformat("Loaded") ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 100, top + line_height * 2,
+									 loaded_color, 
+									 LLFontGL::LEFT, LLFontGL::TOP);
+
+	F32 bound_color[] = {1.0f, 1.0f, 0.0f, 0.75f};
+	gl_rect_2d(left + 170, top + line_height * 2, left + 190, top + line_height, bound_color) ;
+	text = llformat("Bound") ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 200, top + line_height * 2,
+									 bound_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+	//--------------------------------------------------
+
+	//title
+	text = llformat("Texture Category Distribution") ;
+	LLFontGL::getFontMonospace()->renderUTF8(text, 0, left + 250, top + line_height * 3,
+									 text_color, LLFontGL::LEFT, LLFontGL::TOP);
+
+	return scale ;
+}
diff --git a/indra/newview/lltextureview.h b/indra/newview/lltextureview.h
index e917c0235e7aff3e0282b530a1208d99fa01e0d5..435a55df8357a35dfa21fe95952fcc7224cfae45 100644
--- a/indra/newview/lltextureview.h
+++ b/indra/newview/lltextureview.h
@@ -79,24 +79,41 @@ class LLTextureView : public LLContainerView
 };
 
 class LLGLTexSizeBar;
-
-class LLTextureSizeView : public LLView
+class LLTextureSizeView : public LLContainerView
 {
-public:
+protected:
 	LLTextureSizeView(const Params&);
+	friend class LLUICtrlFactory;
+public:	
 	~LLTextureSizeView();
 
 	/*virtual*/ void draw();
 	/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask) ;
 	
+	void setType(S32 type) {mType = type ;}
+	enum
+	{
+		TEXTURE_MEM_OVER_SIZE,
+		TEXTURE_MEM_OVER_CATEGORY
+	};
 private:
+	//draw background for TEXTURE_MEM_OVER_SIZE
 	F32 drawTextureSizeDistributionGraph() ;
-	
+	//draw real-time texture mem bar over size
+	void drawTextureSizeGraph();
+
+	//draw background for TEXTURE_MEM_OVER_CATEGORY
+	F32 drawTextureCategoryDistributionGraph() ;
+	//draw real-time texture mem bar over category
+	void drawTextureCategoryGraph();
+
 private:
 	std::vector<LLGLTexSizeBar*> mTextureSizeBar ;
 	LLRect mTextureSizeBarRect ;
-	S32    mTextureSizeBarWidth ;
+	S32    mTextureSizeBarWidth ;	
+	S32    mType ;
 };
 extern LLTextureView *gTextureView;
 extern LLTextureSizeView *gTextureSizeView;
+extern LLTextureSizeView *gTextureCategoryView;
 #endif // LL_TEXTURE_VIEW_H
diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp
index 841902f6833dd733a36cd7a31488dad340d1de10..a3daca6fa42947c000fd80095cb4775373a5efe3 100644
--- a/indra/newview/llurldispatcher.cpp
+++ b/indra/newview/llurldispatcher.cpp
@@ -46,7 +46,7 @@
 #include "llstartup.h"			// gStartupState
 #include "llurlsimstring.h"
 #include "llweb.h"
-#include "llworldmap.h"
+#include "llworldmapmessage.h"
 
 // library includes
 #include "llsd.h"
@@ -201,7 +201,7 @@ bool LLURLDispatcherImpl::dispatchRegion(const std::string& url, bool right_mous
 	//if(url_displayp) 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
@@ -240,7 +240,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);
 	}
@@ -335,7 +335,7 @@ class LLTeleportHandler : public LLCommandHandler
 		{
 			url += tokens[i].asString() + "/";
 		}
-		LLWorldMap::getInstance()->sendNamedRegionRequest(region_name,
+		LLWorldMapMessage::getInstance()->sendNamedRegionRequest(region_name,
 			LLURLDispatcherImpl::regionHandleCallback,
 			url,
 			true);	// teleport
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index f65baea6ca0a95d1ee5dfc71d108509a8260c30f..b5709fa10214720a68131ad5bedd65c9e8be5609 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -109,10 +109,13 @@ LLViewerCamera::LLViewerCamera() : LLCamera()
 {
 	calcProjection(getFar());
 	mCameraFOVDefault = DEFAULT_FIELD_OF_VIEW;
+	mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
 	mPixelMeterRatio = 0.f;
 	mScreenPixelArea = 0;
 	mZoomFactor = 1.f;
 	mZoomSubregion = 1;
+	mAverageSpeed = 0.f;
+	mAverageAngularSpeed = 0.f;
 	gSavedSettings.getControl("CameraAngle")->getCommitSignal()->connect(boost::bind(&LLViewerCamera::updateCameraAngle, this, _2));
 }
 
@@ -151,15 +154,22 @@ void LLViewerCamera::updateCameraLocation(const LLVector3 &center,
 
 	setOriginAndLookAt(origin, up_direction, point_of_interest);
 
-	F32 dpos = (center - last_position).magVec();
+	mVelocityDir = center - last_position ; 
+	F32 dpos = mVelocityDir.normVec() ;
 	LLQuaternion rotation;
 	rotation.shortestArc(last_axis, getAtAxis());
 
 	F32 x, y, z;
 	F32 drot;
 	rotation.getAngleAxis(&drot, &x, &y, &z);
+
 	mVelocityStat.addValue(dpos);
 	mAngularVelocityStat.addValue(drot);
+	
+	mAverageSpeed = mVelocityStat.getMeanPerSec() ;
+	mAverageAngularSpeed = mAngularVelocityStat.getMeanPerSec() ;
+	mCosHalfCameraFOV = cosf(0.5f * getView() * llmax(1.0f, getAspect()));
+
 	// update pixel meter ratio using default fov, not modified one
 	mPixelMeterRatio = getViewHeightInPixels()/ (2.f*tanf(mCameraFOVDefault*0.5));
 	// update screen pixel area
@@ -818,10 +828,12 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
 	LLCamera::setView(vertical_fov_rads); // call base implementation
 }
 
-void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) {
+void LLViewerCamera::setDefaultFOV(F32 vertical_fov_rads) 
+{
 	vertical_fov_rads = llclamp(vertical_fov_rads, getMinView(), getMaxView());
 	setView(vertical_fov_rads);
 	mCameraFOVDefault = vertical_fov_rads; 
+	mCosHalfCameraFOV = cosf(mCameraFOVDefault * 0.5f);
 }
 
 
diff --git a/indra/newview/llviewercamera.h b/indra/newview/llviewercamera.h
index 90b77f771f3ec3d1cd3b31eeabc87a4b9ce4af1f..2b8a0892bf62f5731faa03ddbba2c02a2d2f9450 100644
--- a/indra/newview/llviewercamera.h
+++ b/indra/newview/llviewercamera.h
@@ -91,17 +91,20 @@ class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera>
 	BOOL projectPosAgentToScreen(const LLVector3 &pos_agent, LLCoordGL &out_point, const BOOL clamp = TRUE) const;
 	BOOL projectPosAgentToScreenEdge(const LLVector3 &pos_agent, LLCoordGL &out_point) const;
 
-
+	const LLVector3* getVelocityDir() const {return &mVelocityDir;}
 	LLStat *getVelocityStat() { return &mVelocityStat; }
 	LLStat *getAngularVelocityStat() { return &mAngularVelocityStat; }
+	F32     getCosHalfFov() {return mCosHalfCameraFOV;}
+	F32     getAverageSpeed() {return mAverageSpeed ;}
+	F32     getAverageAngularSpeed() {return mAverageAngularSpeed;}
 
 	void getPixelVectors(const LLVector3 &pos_agent, LLVector3 &up, LLVector3 &right);
 	LLVector3 roundToPixel(const LLVector3 &pos_agent);
 
 	// Sets the current matrix
 	/* virtual */ void setView(F32 vertical_fov_rads);
-	// Sets the current matrix AND remembers result as default view
-	void setDefaultFOV(F32 vertical_fov_rads);
+
+	void setDefaultFOV(F32 fov) ;
 	F32 getDefaultFOV() { return mCameraFOVDefault; }
 
 	BOOL cameraUnderWater() const;
@@ -120,9 +123,14 @@ class LLViewerCamera : public LLCamera, public LLSingleton<LLViewerCamera>
 
 	LLStat mVelocityStat;
 	LLStat mAngularVelocityStat;
+	LLVector3 mVelocityDir ;
+	F32       mAverageSpeed ;
+	F32       mAverageAngularSpeed ;
+
 	mutable LLMatrix4	mProjectionMatrix;	// Cache of perspective matrix
 	mutable LLMatrix4	mModelviewMatrix;
 	F32					mCameraFOVDefault;
+	F32					mCosHalfCameraFOV;
 	LLVector3			mLastPointOfInterest;
 	F32					mPixelMeterRatio; // Divide by distance from camera to get pixels per meter at that distance.
 	S32					mScreenPixelArea; // Pixel area of entire window
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index b71291f834f5358f502ce3aa589a28cc8cde105e..6d3bf277bbaacc45b780663f159ca7a51f63dc56 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -90,7 +90,7 @@ std::string gCurrentVersion;
 
 extern BOOL gResizeScreenTexture;
 extern BOOL gDebugGL;
-
+extern BOOL gAuditTexture;
 ////////////////////////////////////////////////////////////////////////////
 // Listeners
 
@@ -378,6 +378,12 @@ static bool handleRenderUseImpostorsChanged(const LLSD& newvalue)
 	return true;
 }
 
+static bool handleAuditTextureChanged(const LLSD& newvalue)
+{
+	gAuditTexture = newvalue.asBoolean();
+	return true;
+}
+
 static bool handleRenderDebugGLChanged(const LLSD& newvalue)
 {
 	gDebugGL = newvalue.asBoolean() || gDebugSession;
@@ -566,6 +572,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderDeferredShadow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("RenderDeferredGI")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2));
+	gSavedSettings.getControl("AuditTexture")->getSignal()->connect(boost::bind(&handleAuditTextureChanged, _2));
 	gSavedSettings.getControl("ChatFontSize")->getSignal()->connect(boost::bind(&handleChatFontSizeChanged, _2));
 	gSavedSettings.getControl("ChatPersistTime")->getSignal()->connect(boost::bind(&handleChatPersistTimeChanged, _2));
 	gSavedSettings.getControl("ConsoleMaxLines")->getSignal()->connect(boost::bind(&handleConsoleMaxLinesChanged, _2));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index a6a72e96661008945f1b2eb29f207895c6eb9565..e0bb8fedeb1da7aebe4f6d33bfa6482eb4ead218 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -712,7 +712,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 			gBumpImageList.updateImages();  // must be called before gTextureList version so that it's textures are thrown out first.
 
-			const F32 max_image_decode_time = llmin(0.005f, 0.005f*10.f*gFrameIntervalSeconds); // 50 ms/second decode time (no more than 5ms/frame)
+			F32 max_image_decode_time = 0.050f*gFrameIntervalSeconds; // 50 ms/second decode time
+			max_image_decode_time = llclamp(max_image_decode_time, 0.001f, 0.005f ); // min 1ms/frame, max 5ms/frame)
 			gTextureList.updateImages(max_image_decode_time);
 
 			//remove dead textures from GL
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index e4643a15b58428e0ab3ce8a35b946c990c1a3d3d..3374720a68c2664656dfdbe77a5a6fa245e16fde 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -606,6 +606,14 @@ class LLAdvancedToggleConsole : public view_listener_t
 		{
 			toggle_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) );
 		}
+		else if (gTextureSizeView && "texture size" == console_type)
+		{
+			toggle_visibility( (void*)gTextureSizeView );
+		}
+		else if (gTextureCategoryView && "texture category" == console_type)
+		{
+			toggle_visibility( (void*)gTextureCategoryView );
+		}
 		else if ("fast timers" == console_type)
 		{
 			toggle_visibility( (void*)gDebugView->mFastTimerView );
@@ -633,6 +641,14 @@ class LLAdvancedCheckConsole : public view_listener_t
 		{
 			new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) );
 		}
+		else if (gTextureSizeView && "texture size" == console_type)
+		{
+			new_value = get_visibility( (void*)gTextureSizeView );
+		}
+		else if (gTextureCategoryView && "texture category" == console_type)
+		{
+			new_value = get_visibility( (void*)gTextureCategoryView );
+		}
 		else if ("fast timers" == console_type)
 		{
 			new_value = get_visibility( (void*)gDebugView->mFastTimerView );
@@ -1156,28 +1172,6 @@ class LLAdvancedCheckWireframe : public view_listener_t
 	}
 };
 	
-//////////////////////
-// DISABLE TEXTURES //
-//////////////////////
-
-class LLAdvancedToggleDisableTextures : public view_listener_t
-{
-	bool handleEvent(const LLSD& userdata)
-	{
-		LLViewerTexture::sDontLoadVolumeTextures = !LLViewerTexture::sDontLoadVolumeTextures;
-		return true;
-	}
-};
-
-class LLAdvancedCheckDisableTextures : public view_listener_t
-{
-	bool handleEvent(const LLSD& userdata)
-	{
-		bool new_value = LLViewerTexture::sDontLoadVolumeTextures; // <-- make this using LLCacheControl
-		return new_value;
-	}
-};
-
 //////////////////////
 // TEXTURE ATLAS //
 //////////////////////
@@ -1909,7 +1903,7 @@ class LLAdvancedRebakeTextures : public view_listener_t
 };
 	
 	
-#ifndef LL_RELEASE_FOR_DOWNLOAD
+#if 1 //ndef LL_RELEASE_FOR_DOWNLOAD
 ///////////////////////////
 // DEBUG AVATAR TEXTURES //
 ///////////////////////////
@@ -3511,9 +3505,8 @@ void set_god_level(U8 god_level)
 	gIMMgr->refresh();
 	LLViewerParcelMgr::getInstance()->notifyObservers();
 
-	// God mode changes sim visibility
-	LLWorldMap::getInstance()->reset();
-	LLWorldMap::getInstance()->setCurrentLayer(0);
+	// God mode changes region visibility
+	LLWorldMap::getInstance()->reloadItems(true);
 
 	// inventory in items may change in god mode
 	gObjectList.dirtyAllObjectInventory();
@@ -7887,8 +7880,6 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo");
 	view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe");
 	view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
-	view_listener_t::addMenu(new LLAdvancedToggleDisableTextures(), "Advanced.ToggleDisableTextures");
-	view_listener_t::addMenu(new LLAdvancedCheckDisableTextures(), "Advanced.CheckDisableTextures");
 	view_listener_t::addMenu(new LLAdvancedToggleTextureAtlas(), "Advanced.ToggleTextureAtlas");
 	view_listener_t::addMenu(new LLAdvancedCheckTextureAtlas(), "Advanced.CheckTextureAtlas");
 	view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion");
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 20cd516fa06e08a53d1bc616d6e700cd93dfd6e8..5de52367ef46957c41b1562016ab07619ee12997 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2906,7 +2906,7 @@ F32 LLViewerObject::getMidScale() const
 }
 
 
-void LLViewerObject::updateTextures(LLAgent &agent)
+void LLViewerObject::updateTextures()
 {
 }
 
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index b8ae31118c1c078bc83ed2b0536b08f78c9b33be..01b213a87d1b871ccbfcdc7b56350cf034bdd375 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -199,7 +199,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	S32 getNumFaces() const { return mNumFaces; }
 
 	// Graphical stuff for objects - maybe broken out into render class later?
-	virtual void updateTextures(LLAgent &agent);
+	virtual void updateTextures();
 	virtual void boostTexturePriority(BOOL boost_children = TRUE);	// When you just want to boost priority of this object
 	
 	virtual LLDrawable* createDrawable(LLPipeline *pipeline);
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 2927ca529264f0bb172909ca0fdf4b484558bd1e..96828ee1b6088baad4c3ef16e92c81c7a38438fb 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -642,7 +642,7 @@ void LLViewerObjectList::updateApparentAngles(LLAgent &agent)
 
 			//  Update distance & gpw 
 			objectp->setPixelAreaAndAngle(agent); // Also sets the approx. pixel area
-			objectp->updateTextures(agent);	// Update the image levels of textures for this object.
+			objectp->updateTextures();	// Update the image levels of textures for this object.
 		}
 	}
 
@@ -1074,6 +1074,7 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
 	LLColor4 group_own_below_water_color = 
 						LLUIColorTable::instance().getColor( "NetMapGroupOwnBelowWater" );
 
+	F32 max_radius = gSavedSettings.getF32("MiniMapPrimMaxRadius");
 
 	for (S32 i = 0; i < mMapObjects.count(); i++)
 	{
@@ -1089,6 +1090,11 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
 
 		F32 approx_radius = (scale.mV[VX] + scale.mV[VY]) * 0.5f * 0.5f * 1.3f;  // 1.3 is a fudge
 
+		// Limit the size of megaprims so they don't blot out everything on the minimap.
+		// Attempting to draw very large megaprims also causes client lag.
+		// See DEV-17370 and DEV-29869/SNOW-79 for details.
+		approx_radius = llmin(approx_radius, max_radius);
+
 		LLColor4U color = above_water_color;
 		if( objectp->permYouOwner() )
 		{
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 7ea55b49e869452ab988e4372a88eec4e8ead0f5..d1c9840a972d71f47edf2156772a168d8fb520c4 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1427,11 +1427,11 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("EstateChangeInfo");
 	capabilityNames.append("EventQueueGet");
 	capabilityNames.append("FetchInventory");
-	capabilityNames.append("WebFetchInventoryDescendents");
 	capabilityNames.append("ObjectMedia");
 	capabilityNames.append("ObjectMediaNavigate");
 	capabilityNames.append("FetchLib");
 	capabilityNames.append("FetchLibDescendents");
+	capabilityNames.append("GetTexture");
 	capabilityNames.append("GroupProposalBallot");
 	capabilityNames.append("HomeLocation");
 	capabilityNames.append("MapLayer");
@@ -1452,6 +1452,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("SendUserReportWithScreenshot");
 	capabilityNames.append("ServerReleaseNotes");
 	capabilityNames.append("StartGroupProposal");
+	capabilityNames.append("TextureStats");
 	capabilityNames.append("UntrustedSimulatorMessage");
 	capabilityNames.append("UpdateAgentInformation");
 	capabilityNames.append("UpdateAgentLanguage");
@@ -1464,6 +1465,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("UploadBakedTexture");
 	capabilityNames.append("ViewerStartAuction");
 	capabilityNames.append("ViewerStats");
+	capabilityNames.append("WebFetchInventoryDescendents");
 	// Please add new capabilities alphabetically to reduce
 	// merge conflicts.
 
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 6e07d8f2468c369a187bb8591e65c6f49fd2882f..caa94dba381252b8369484d446968428d09ae007 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -560,12 +560,18 @@ extern U32  gVisCompared;
 extern U32  gVisTested;
 
 std::map<S32,LLFrameTimer> gDebugTimers;
+std::map<S32,std::string> gDebugTimerLabel;
+
+void init_statistics()
+{
+	// Label debug timers
+	gDebugTimerLabel[0] = "Texture";
+}
 
 void update_statistics(U32 frame_count)
 {
 	gTotalWorldBytes += gVLManager.getTotalBytes();
 	gTotalObjectBytes += gObjectBits / 8;
-	gTotalTextureBytes += gTextureList.mTextureBits / 8;
 
 	// make sure we have a valid time delta for this frame
 	if (gFrameIntervalSeconds > 0.f)
@@ -617,7 +623,6 @@ void update_statistics(U32 frame_count)
 	F32 layer_bits = (F32)(gVLManager.getLandBits() + gVLManager.getWindBits() + gVLManager.getCloudBits());
 	LLViewerStats::getInstance()->mLayersKBitStat.addValue(layer_bits/1024.f);
 	LLViewerStats::getInstance()->mObjectKBitStat.addValue(gObjectBits/1024.f);
-	LLViewerStats::getInstance()->mTextureKBitStat.addValue(gTextureList.mTextureBits/1024.f);
 	LLViewerStats::getInstance()->mVFSPendingOperations.addValue(LLVFile::getVFSThread()->getPending());
 	LLViewerStats::getInstance()->mAssetKBitStat.addValue(gTransferManager.getTransferBitsIn(LLTCT_ASSET)/1024.f);
 	gTransferManager.resetTransferBitsIn(LLTCT_ASSET);
@@ -631,8 +636,6 @@ void update_statistics(U32 frame_count)
 		gDebugTimers[0].unpause();
 	}
 	
-	LLViewerStats::getInstance()->mTexturePacketsStat.addValue(gTextureList.mTexturePackets);
-
 	{
 		static F32 visible_avatar_frames = 0.f;
 		static F32 avg_visible_avatars = 0;
@@ -652,8 +655,20 @@ void update_statistics(U32 frame_count)
 	gObjectBits = 0;
 //	gDecodedBits = 0;
 
-	gTextureList.mTextureBits = 0;
-	gTextureList.mTexturePackets = 0;
+	// Only update texture stats ones per second so that they are less noisy
+	{
+		static const F32 texture_stats_freq = 1.f;
+		static LLFrameTimer texture_stats_timer;
+		if (texture_stats_timer.getElapsedTimeF32() >= texture_stats_freq)
+		{
+			LLViewerStats::getInstance()->mTextureKBitStat.addValue(LLViewerTextureList::sTextureBits/1024.f);
+			LLViewerStats::getInstance()->mTexturePacketsStat.addValue(LLViewerTextureList::sTexturePackets);
+			gTotalTextureBytes += LLViewerTextureList::sTextureBits / 8;
+			LLViewerTextureList::sTextureBits = 0;
+			LLViewerTextureList::sTexturePackets = 0;
+			texture_stats_timer.reset();
+		}
+	}
 
 }
 
@@ -826,3 +841,4 @@ void send_stats()
 	LLViewerStats::getInstance()->addToMessage(body);
 	LLHTTPClient::post(url, body, new ViewerStatsResponder());
 }
+
diff --git a/indra/newview/llviewerstats.h b/indra/newview/llviewerstats.h
index ba89fbf02a52ce104a76568cf8aa54192d3ab129..13d73000d242ed6158e38821d8437bf94b2a7141 100644
--- a/indra/newview/llviewerstats.h
+++ b/indra/newview/llviewerstats.h
@@ -34,6 +34,7 @@
 #define LL_LLVIEWERSTATS_H
 
 #include "llstat.h"
+#include "lltextureinfo.h"
 
 class LLViewerStats : public LLSingleton<LLViewerStats>
 {
@@ -205,10 +206,13 @@ class LLViewerStats : public LLSingleton<LLViewerStats>
 static const F32 SEND_STATS_PERIOD = 300.0f;
 
 // The following are from (older?) statistics code found in appviewer.
+void init_statistics();
 void reset_statistics();
 void output_statistics(void*);
 void update_statistics(U32 frame_count);
 void send_stats();
 
 extern std::map<S32,LLFrameTimer> gDebugTimers;
+extern std::map<S32,std::string> gDebugTimerLabel;
+
 #endif // LL_LLVIEWERSTATS_H
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index a0ab4cb1e68687c6064bd02ee707b8ea8af83df4..b2ca9edfea57e4a652f1550589c58cc244fe46b0 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -60,6 +60,8 @@
 #include "llviewercontrol.h"
 #include "pipeline.h"
 #include "llappviewer.h"
+#include "llface.h"
+#include "llviewercamera.h"
 #include "lltextureatlas.h"
 #include "lltextureatlasmanager.h"
 #include "lltextureentry.h"
@@ -88,7 +90,15 @@ S32 LLViewerTexture::sTotalTextureMemoryInBytes = 0;
 S32 LLViewerTexture::sMaxBoundTextureMemInMegaBytes = 0;
 S32 LLViewerTexture::sMaxTotalTextureMemInMegaBytes = 0;
 S32 LLViewerTexture::sMaxDesiredTextureMemInBytes = 0 ;
-BOOL LLViewerTexture::sDontLoadVolumeTextures = FALSE;
+S8  LLViewerTexture::sCameraMovingDiscardBias = 0 ;
+S32 LLViewerTexture::sMaxSculptRez = 128 ; //max sculpt image size
+const S32 MAX_CACHED_RAW_IMAGE_AREA = 64 * 64 ;
+const S32 MAX_CACHED_RAW_SCULPT_IMAGE_AREA = LLViewerTexture::sMaxSculptRez * LLViewerTexture::sMaxSculptRez ;
+const S32 MAX_CACHED_RAW_TERRAIN_IMAGE_AREA = 128 * 128 ;
+S32 LLViewerTexture::sMinLargeImageSize = 65536 ; //256 * 256.
+S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA ;
+BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE ;
+F32 LLViewerTexture::sCurrentTime = 0.0f ;
 BOOL LLViewerTexture::sUseTextureAtlas        = FALSE ;
 
 const F32 desired_discard_bias_min = -2.0f; // -max number of levels to improve image quality by
@@ -161,6 +171,7 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(BOOL usemipma
 	if(generate_gl_tex)
 	{
 		tex->generateGLTexture() ;
+		tex->setCategory(LLViewerTexture::LOCAL) ;
 	}
 	return tex ;
 }
@@ -170,12 +181,14 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const LLUUID&
 	if(generate_gl_tex)
 	{
 		tex->generateGLTexture() ;
+		tex->setCategory(LLViewerTexture::LOCAL) ;
 	}
 	return tex ;
 }
 LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const LLImageRaw* raw, BOOL usemipmaps) 
 {
 	LLPointer<LLViewerTexture> tex = new LLViewerTexture(raw, usemipmaps) ;
+	tex->setCategory(LLViewerTexture::LOCAL) ;
 	return tex ;
 }
 LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const U32 width, const U32 height, const U8 components, BOOL usemipmaps, BOOL generate_gl_tex) 
@@ -184,6 +197,7 @@ LLPointer<LLViewerTexture> LLViewerTextureManager::getLocalTexture(const U32 wid
 	if(generate_gl_tex)
 	{
 		tex->generateGLTexture() ;
+		tex->setCategory(LLViewerTexture::LOCAL) ;
 	}
 	return tex ;
 }
@@ -212,6 +226,19 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile(
 	return gTextureList.getImageFromFile(filename, usemipmaps, level_immediate, texture_type, internal_format, primary_format, force_id) ;
 }
 
+//static 
+LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url,									 
+									 BOOL usemipmaps,
+									 BOOL level_immediate,		// Get the requested level immediately upon creation.
+									 S8 texture_type,
+									 LLGLint internal_format,
+									 LLGLenum primary_format,
+									 const LLUUID& force_id
+									 )
+{
+	return gTextureList.getImageFromUrl(url, usemipmaps, level_immediate, texture_type, internal_format, primary_format, force_id) ;
+}
+
 LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromHost(const LLUUID& image_id, LLHost host) 
 {
 	return gTextureList.getImageFromHost(image_id, host) ;
@@ -253,11 +280,12 @@ void LLViewerTextureManager::init()
 	}
 	imagep->createGLTexture(0, image_raw);
 	image_raw = NULL;
-	LLViewerFetchedTexture::sDefaultImagep->dontDiscard();
 #else
  	LLViewerFetchedTexture::sDefaultImagep = LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE);
 #endif
-	
+	LLViewerFetchedTexture::sDefaultImagep->dontDiscard();
+	LLViewerFetchedTexture::sDefaultImagep->setCategory(LLViewerTexture::OTHER) ;
+
  	LLViewerFetchedTexture::sSmokeImagep = LLViewerTextureManager::getFetchedTexture(IMG_SMOKE, TRUE, TRUE);
 	LLViewerFetchedTexture::sSmokeImagep->setNoDelete() ;
 
@@ -281,6 +309,8 @@ void LLViewerTextureManager::cleanup()
 	LLViewerFetchedTexture::sWhiteImagep = NULL;
 
 	LLViewerMediaTexture::cleanup() ;	
+
+	LLViewerTexture::cleanupClass() ;
 }
 
 //----------------------------------------------------------------------------------------------
@@ -291,6 +321,11 @@ void LLViewerTextureManager::cleanup()
 void LLViewerTexture::initClass()
 {
 	LLImageGL::sDefaultGLTexture = LLViewerFetchedTexture::sDefaultImagep->getGLTexture() ;
+
+	if(gAuditTexture)
+	{
+		LLImageGL::setHighlightTexture(LLViewerTexture::OTHER) ;	
+	}
 }
 
 // static
@@ -298,6 +333,25 @@ void LLViewerTexture::cleanupClass()
 {
 }
 
+// static
+S32 LLViewerTexture::getTotalNumOfCategories() 
+{
+	return MAX_GL_IMAGE_CATEGORY - (BOOST_HIGH - BOOST_SCULPTED) + 2 ;
+}
+
+// static
+//index starts from zero.
+S32 LLViewerTexture::getIndexFromCategory(S32 category) 
+{
+	return (category < BOOST_HIGH) ? category : category - (BOOST_HIGH - BOOST_SCULPTED) + 1 ;
+}
+
+//static 
+S32 LLViewerTexture::getCategoryFromIndex(S32 index)
+{
+	return (index < BOOST_HIGH) ? index : index + (BOOST_HIGH - BOOST_SCULPTED) - 1 ;
+}
+
 // tuning params
 const F32 discard_bias_delta = .05f;
 const F32 discard_delta_time = 0.5f;
@@ -309,6 +363,8 @@ F32 texmem_middle_bound_scale = 0.925f;
 //static
 void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity)
 {
+	sCurrentTime = gFrameTimeSeconds ;
+
 	if(LLViewerTextureManager::sTesterp)
 	{
 		LLViewerTextureManager::sTesterp->update() ;
@@ -349,6 +405,13 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
 	}
 	sDesiredDiscardBias = llclamp(sDesiredDiscardBias, desired_discard_bias_min, desired_discard_bias_max);
 	LLViewerTexture::sUseTextureAtlas = gSavedSettings.getBOOL("EnableTextureAtlas") ;
+	
+	F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ;
+	F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed();
+	sCameraMovingDiscardBias = (S8)llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1) ;
+
+	LLViewerTexture::sFreezeImageScalingDown = (BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) < 0.75f * sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale) &&
+				(BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) < 0.75f * sMaxTotalTextureMemInMegaBytes * texmem_middle_bound_scale) ;
 }
 
 //end of static functions
@@ -414,7 +477,9 @@ void LLViewerTexture::init(bool firstinit)
 	mTextureState = NO_DELETE ;
 	mDontDiscard = FALSE;
 	mMaxVirtualSize = 0.f;
+	mNeedsGLTexture = FALSE ;
 	mNeedsResetMaxVirtualSize = FALSE ;
+	mAdditionalDecodePriority = 0.f ;	
 }
 
 //virtual 
@@ -455,11 +520,15 @@ void LLViewerTexture::setBoostLevel(S32 level)
 		{
 			setNoDelete() ;		
 		}
+		if(gAuditTexture)
+		{
+			setCategory(mBoostLevel);
+		}
 	}
 }
 
 
-bool LLViewerTexture::bindDefaultImage(S32 stage) const
+bool LLViewerTexture::bindDefaultImage(S32 stage) 
 {
 	if (stage < 0) return false;
 
@@ -478,6 +547,10 @@ bool LLViewerTexture::bindDefaultImage(S32 stage) const
 		llwarns << "LLViewerTexture::bindDefaultImage failed." << llendl;
 	}
 	stop_glerror();
+
+	//check if there is cached raw image and switch to it if possible
+	switchToCachedImage() ;
+
 	if(LLViewerTextureManager::sTesterp)
 	{
 		LLViewerTextureManager::sTesterp->updateGrayTextureBinding() ;
@@ -496,24 +569,32 @@ void LLViewerTexture::forceImmediateUpdate()
 {
 }
 
-void LLViewerTexture::addTextureStats(F32 virtual_size) const 
+void LLViewerTexture::addTextureStats(F32 virtual_size, BOOL needs_gltexture) const 
 {
-	if (virtual_size > mMaxVirtualSize)
+	if(needs_gltexture)
 	{
-		mMaxVirtualSize = virtual_size;
+		mNeedsGLTexture = TRUE ;
 	}
-}
 
-void LLViewerTexture::resetTextureStats(BOOL zero)
-{
-	if (zero)
+	if(mNeedsResetMaxVirtualSize)
 	{
-		mMaxVirtualSize = 0.0f;
+		//flag to reset the values because the old values are used.
+		mNeedsResetMaxVirtualSize = FALSE ;
+		mMaxVirtualSize = virtual_size;		
+		mAdditionalDecodePriority = 0.f ;	
+		mNeedsGLTexture = needs_gltexture ;
 	}
-	else
+	else if (virtual_size > mMaxVirtualSize)
 	{
-		mMaxVirtualSize -= mMaxVirtualSize * .10f; // decay by 5%/update
-	}
+		mMaxVirtualSize = virtual_size;
+	}	
+}
+
+void LLViewerTexture::resetTextureStats()
+{
+	mMaxVirtualSize = 0.0f;
+	mAdditionalDecodePriority = 0.f ;	
+	mNeedsResetMaxVirtualSize = FALSE ;
 }
 
 //virtual 
@@ -534,6 +615,12 @@ void LLViewerTexture::removeFace(LLFace* facep)
 	mFaceList.remove(facep) ;
 }
 
+//virtual
+void LLViewerTexture::switchToCachedImage()
+{
+	//nothing here.
+}
+
 void LLViewerTexture::forceActive()
 {
 	mTextureState = ACTIVE ; 
@@ -578,11 +665,11 @@ BOOL LLViewerTexture::createGLTexture()
 	return mGLTexturep->createGLTexture() ;
 }
 
-BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename)
+BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename, BOOL to_create, S32 category)
 {
 	llassert_always(mGLTexturep.notNull()) ;	
 
-	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename) ;
+	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ;
 	
 	if(ret)
 	{
@@ -694,6 +781,13 @@ void LLViewerTexture::setGLTextureCreated (bool initialized)
 	mGLTexturep->setGLTextureCreated (initialized) ;
 }
 
+void  LLViewerTexture::setCategory(S32 category) 
+{
+	llassert_always(mGLTexturep.notNull()) ;
+
+	mGLTexturep->setCategory(category) ;
+}
+
 LLTexUnit::eTextureAddressMode LLViewerTexture::getAddressMode(void) const
 {
 	llassert_always(mGLTexturep.notNull()) ;
@@ -742,18 +836,18 @@ BOOL LLViewerTexture::getMissed() const
 	return mGLTexturep->getMissed() ;
 }
 
-BOOL LLViewerTexture::isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) 
+BOOL LLViewerTexture::isJustBound() const
 {
 	llassert_always(mGLTexturep.notNull()) ;
 
-	return mGLTexturep->isValidForSculpt(discard_level, image_width, image_height, ncomponents) ;
+	return mGLTexturep->isJustBound() ;
 }
 
-BOOL LLViewerTexture::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const
+void LLViewerTexture::forceUpdateBindStats(void) const
 {
 	llassert_always(mGLTexturep.notNull()) ;
 
-	return mGLTexturep->readBackRaw(discard_level, imageraw, compressed_ok) ;
+	return mGLTexturep->forceUpdateBindStats() ;
 }
 
 U32 LLViewerTexture::getTexelsInAtlas() const
@@ -793,6 +887,11 @@ void LLViewerTexture::destroyGLTexture()
 	}	
 }
 
+BOOL LLViewerTexture::isLargeImage()
+{
+	return mFullWidth * mFullHeight > LLViewerTexture::sMinLargeImageSize ;
+}
+
 //virtual 
 void LLViewerTexture::updateBindStatsForTester()
 {
@@ -813,11 +912,12 @@ void LLViewerTexture::updateBindStatsForTester()
 //static
 F32 LLViewerFetchedTexture::maxDecodePriority()
 {
-	return 2000000.f;
+	return 6000000.f;
 }
 
-LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, BOOL usemipmaps)
-	: LLViewerTexture(id, usemipmaps)
+LLViewerFetchedTexture::LLViewerFetchedTexture(const LLUUID& id, const LLHost& host, BOOL usemipmaps)
+	: LLViewerTexture(id, usemipmaps),
+	mTargetHost(host)
 {
 	init(TRUE) ;
 	generateGLTexture() ;
@@ -829,9 +929,9 @@ LLViewerFetchedTexture::LLViewerFetchedTexture(const LLImageRaw* raw, BOOL usemi
 	init(TRUE) ;
 }
 	
-LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps)
+LLViewerFetchedTexture::LLViewerFetchedTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps)
 	: LLViewerTexture(id, usemipmaps),
-	mLocalFileName(full_path)
+	mUrl(url)
 {
 	init(TRUE) ;
 	generateGLTexture() ;
@@ -879,6 +979,16 @@ void LLViewerFetchedTexture::init(bool firstinit)
 	mVisibleFrame = 0;
 	mForSculpt = FALSE ;
 	mIsFetched = FALSE ;
+
+	mCachedRawImage = NULL ;
+	mCachedRawDiscardLevel = -1 ;
+	mCachedRawImageReady = FALSE ;
+
+	mSavedRawImage = NULL ;
+	mForceToSaveRawImage  = FALSE ;
+	mSavedRawDiscardLevel = -1 ;
+	mDesiredSavedRawDiscardLevel = -1 ;
+	mLastReferencedSavedRawImageTime = 0.0f ;
 }
 
 LLViewerFetchedTexture::~LLViewerFetchedTexture()
@@ -915,11 +1025,25 @@ void LLViewerFetchedTexture::cleanup()
 	
 	// Clean up image data
 	destroyRawImage();
+	mCachedRawImage = NULL ;
+	mCachedRawDiscardLevel = -1 ;
+	mCachedRawImageReady = FALSE ;
+	mSavedRawImage = NULL ;
 }
 
 void LLViewerFetchedTexture::setForSculpt()
 {
 	mForSculpt = TRUE ;
+	if(isForSculptOnly() && !getBoundRecently())
+	{
+		destroyGLTexture() ; //sculpt image does not need gl texture.
+	}
+	checkCachedRawSculptImage() ;
+}
+
+BOOL LLViewerFetchedTexture::isForSculptOnly() const
+{
+	return mForSculpt && !mNeedsGLTexture ;
 }
 
 BOOL LLViewerFetchedTexture::isDeleted()  
@@ -954,17 +1078,37 @@ void LLViewerFetchedTexture::setInactive()
 	}
 }
 
+BOOL LLViewerFetchedTexture::isFullyLoaded() const
+{
+	// Unfortunately, the boolean "mFullyLoaded" is never updated correctly so we use that logic
+	// to check if the texture is there and completely downloaded
+	return (mFullWidth != 0) && (mFullHeight != 0) && !mIsFetching && !mHasFetcher;
+}
+
+
 // virtual
 void LLViewerFetchedTexture::dump()
 {
 	LLViewerTexture::dump();
 
-	llinfos << "LLViewerFetchedTexture"
-			<< " mIsMissingAsset " << (S32)mIsMissingAsset
-			<< " mFullWidth " << mFullWidth
-			<< " mFullHeight " << mFullHeight
-			<< " mOrigWidth" << mOrigWidth
-			<< " mOrigHeight" << mOrigHeight
+	llinfos << "Dump : " << mID 
+			<< ", mIsMissingAsset = " << (S32)mIsMissingAsset
+			<< ", mFullWidth = " << (S32)mFullWidth
+			<< ", mFullHeight = " << (S32)mFullHeight
+			<< ", mOrigWidth = " << (S32)mOrigWidth
+			<< ", mOrigHeight = " << (S32)mOrigHeight
+			<< llendl;
+	llinfos << "     : " 
+			<< " mFullyLoaded = " << (S32)mFullyLoaded
+			<< ", mFetchState = " << (S32)mFetchState
+			<< ", mFetchPriority = " << (S32)mFetchPriority
+			<< ", mDownloadProgress = " << (F32)mDownloadProgress
+			<< llendl;
+	llinfos << "     : " 
+			<< " mHasFetcher = " << (S32)mHasFetcher
+			<< ", mIsFetching = " << (S32)mIsFetching
+			<< ", mIsFetched = " << (S32)mIsFetched
+			<< ", mBoostLevel = " << (S32)mBoostLevel
 			<< llendl;
 }
 
@@ -985,6 +1129,75 @@ void LLViewerFetchedTexture::destroyTexture()
 	mFullyLoaded = FALSE ;
 }
 
+//
+//do not change the discard level of the loaded texture image.
+BOOL LLViewerFetchedTexture::keepReuestedDiscardLevel()
+{
+	if (!mLoadedCallbackList.empty())
+	{
+		return TRUE ;
+	}
+
+	return FALSE ;
+}
+
+void LLViewerFetchedTexture::addToCreateTexture()
+{
+	if(isForSculptOnly())
+	{
+		//just update some variables, not to create a real GL texture.
+		createGLTexture(mRawDiscardLevel, mRawImage, 0, FALSE) ;
+		mNeedsCreateTexture = FALSE ;
+		destroyRawImage();
+	}
+	else
+	{	
+#if 1
+		//
+		//if mRequestedDiscardLevel > mDesiredDiscardLevel, we assume the required image res keep going up,
+		//so do not scale down the over qualified image.
+		//Note: scaling down image is expensensive. Do it only when very necessary.
+		//
+		if(mRequestedDiscardLevel <= mDesiredDiscardLevel && !keepReuestedDiscardLevel())
+		{
+			S32 w = mFullWidth >> mRawDiscardLevel;
+			S32 h = mFullHeight >> mRawDiscardLevel;
+
+			//if big image, do not load extra data
+			//scale it down to size >= LLViewerTexture::sMinLargeImageSize
+			if(w * h > LLViewerTexture::sMinLargeImageSize)
+			{
+				S32 d_level = llmin(mRequestedDiscardLevel, (S32)mDesiredDiscardLevel) - mRawDiscardLevel ;
+				
+				if(d_level > 0)
+				{
+					S32 i = 0 ;
+					while((d_level > 0) && ((w >> i) * (h >> i) > LLViewerTexture::sMinLargeImageSize))
+					{
+						i++;
+						d_level--;
+					}
+					if(i > 0)
+					{
+						mRawDiscardLevel += i ;
+						if(mRawDiscardLevel >= getDiscardLevel() && getDiscardLevel() > 0)
+						{
+							mNeedsCreateTexture = FALSE ;
+							destroyRawImage();
+							return ;
+						}
+						mRawImage->scale(w >> i, h >> i) ;					
+					}
+				}
+			}
+		}
+#endif
+		mNeedsCreateTexture = TRUE;
+		gTextureList.mCreateTextureList.insert(this);
+	}	
+	return ;
+}
+
 // ONLY called from LLViewerTextureList
 BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
 {
@@ -1006,7 +1219,7 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
 	if (!gNoRender)
 	{
 		// store original size only for locally-sourced images
-		if (!mLocalFileName.empty())
+		if (mUrl.compare(0, 7, "file://") == 0)
 		{
 			mOrigWidth = mRawImage->getWidth();
 			mOrigHeight = mRawImage->getHeight();
@@ -1052,7 +1265,7 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
 		
 		if(!(res = insertToAtlas()))
 		{
-			res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename);
+			res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
 			resetFaceAtlas() ;
 		}
 		setActive() ;
@@ -1099,7 +1312,15 @@ void LLViewerFetchedTexture::processTextureStats()
 		return ;
 	}
 
-	if(!mFullWidth || !mFullHeight)
+	updateVirtualSize() ;
+	
+	static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes");
+	
+	if (textures_fullres)
+	{
+		mDesiredDiscardLevel = 0;
+	}
+	else if(!mFullWidth || !mFullHeight)
 	{
 		mDesiredDiscardLevel = 	getMaxDiscardLevel() ;
 	}
@@ -1148,8 +1369,11 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
 	{
 		return mDecodePriority; // no change while waiting to create
 	}
-
-	F32 priority;
+	if(mForceToSaveRawImage)
+	{
+		return maxDecodePriority() ;
+	}
+	
 	S32 cur_discard = getDiscardLevel();
 	bool have_all_data = (cur_discard >= 0 && (cur_discard <= mDesiredDiscardLevel));
 	F32 pixel_priority = fsqrtf(mMaxVirtualSize);
@@ -1159,11 +1383,24 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
 	{
 		mVisibleFrame = mDecodeFrame;
 	}
-	
+
+	F32 priority;
 	if (mIsMissingAsset)
 	{
 		priority = 0.0f;
 	}
+	else if(mDesiredDiscardLevel >= cur_discard && cur_discard > -1)
+	{
+		priority = -1.0f ;
+	}
+	else if (!isJustBound() && mCachedRawImageReady && !mBoostLevel)
+	{
+		priority = -1.0f;
+	}
+	else if(mCachedRawDiscardLevel > -1 && mDesiredDiscardLevel >= mCachedRawDiscardLevel)
+	{
+		priority = -1.0f;
+	}
 	else if (mDesiredDiscardLevel > getMaxDiscardLevel())
 	{
 		// Don't decode anything we don't need
@@ -1213,7 +1450,7 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
 		{
 			ddiscard+=2;
 		}
-		else if (mGLTexturep.notNull() && !mGLTexturep->getBoundRecently() && mBoostLevel == 0)
+		else if (ddiscard > 2 && mGLTexturep.notNull() && !mGLTexturep->getBoundRecently() && mBoostLevel == 0)
 		{
 			ddiscard-=2;
 		}
@@ -1222,7 +1459,10 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
 	}
 	if (priority > 0.0f)
 	{
-		pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f); // priority range = 100000-900000
+		// priority range = 100000-900000
+		pixel_priority = llclamp(pixel_priority, 0.0f, priority-1.f); 
+
+		// priority range = [100000.f, 2000000.f]
 		if ( mBoostLevel > BOOST_HIGH)
 		{
 			priority = 1000000.f + pixel_priority + 1000.f * mBoostLevel;
@@ -1231,6 +1471,12 @@ F32 LLViewerFetchedTexture::calcDecodePriority()
 		{
 			priority +=      0.f + pixel_priority + 1000.f * mBoostLevel;
 		}
+
+		// priority range = [2100000.f, 5000000.f] if mAdditionalDecodePriority > 1.0
+		if(mAdditionalDecodePriority > 1.0f)
+		{
+			priority += 2000000.f + mAdditionalDecodePriority ;
+		}
 	}
 	return priority;
 }
@@ -1242,6 +1488,40 @@ void LLViewerFetchedTexture::setDecodePriority(F32 priority)
 	mDecodePriority = priority;
 }
 
+F32 LLViewerFetchedTexture::maxAdditionalDecodePriority()
+{
+	return 2000000.f;
+}
+void LLViewerFetchedTexture::setAdditionalDecodePriority(F32 priority)
+{
+	priority *= maxAdditionalDecodePriority();
+	if(mAdditionalDecodePriority < priority)
+	{
+		mAdditionalDecodePriority = priority;
+	}
+}
+
+void LLViewerFetchedTexture::updateVirtualSize() 
+{	
+	if(mNeedsResetMaxVirtualSize)
+	{
+		addTextureStats(0.f, FALSE) ;//reset
+	}
+	if(mFaceList.size() > 0) 
+	{				
+		for(std::list<LLFace*>::iterator iter = mFaceList.begin(); iter != mFaceList.end(); ++iter)
+		{
+			LLFace* facep = *iter ;
+			if(facep->getDrawable()->isRecentlyVisible())
+			{
+				addTextureStats(facep->getVirtualSize()) ;
+				setAdditionalDecodePriority(facep->getImportanceToCamera()) ;
+			}
+		}	
+	}
+	mNeedsResetMaxVirtualSize = TRUE ;
+}
+
 bool LLViewerFetchedTexture::updateFetch()
 {
 	mFetchState = 0;
@@ -1281,6 +1561,15 @@ bool LLViewerFetchedTexture::updateFetch()
 	{
 		// Sets mRawDiscardLevel, mRawImage, mAuxRawImage
 		S32 fetch_discard = current_discard;
+		
+		if(mForceToSaveRawImage)
+		{
+			if(fetch_discard >= 0)
+			{
+				fetch_discard = llmax(fetch_discard, mSavedRawDiscardLevel) ;
+			}
+		}
+
 		if (mRawImage.notNull()) sRawCount--;
 		if (mAuxRawImage.notNull()) sAuxCount--;
 		bool finished = LLAppViewer::getTextureFetch()->getRequestFinished(getID(), fetch_discard, mRawImage, mAuxRawImage);
@@ -1320,11 +1609,24 @@ bool LLViewerFetchedTexture::updateFetch()
 						(*iter)->dirtyTexture() ;
 					}
 				}			
-				mIsRawImageValid = TRUE;
-				gTextureList.mCreateTextureList.insert(this);
-				mNeedsCreateTexture = TRUE;
 				mFullWidth = mRawImage->getWidth() << mRawDiscardLevel;
 				mFullHeight = mRawImage->getHeight() << mRawDiscardLevel;
+
+				if(mFullWidth > MAX_IMAGE_SIZE || mFullHeight > MAX_IMAGE_SIZE)
+				{ 
+					//discard all oversized textures.
+					destroyRawImage();
+					setIsMissingAsset();
+					mRawDiscardLevel = INVALID_DISCARD_LEVEL ;
+					mIsFetching = FALSE ;
+				}
+				else
+				{
+					mIsRawImageValid = TRUE;			
+					addToCreateTexture() ;
+				}
+
+				return TRUE ;
 			}
 			else
 			{
@@ -1347,13 +1649,13 @@ bool LLViewerFetchedTexture::updateFetch()
 				}
 				else
 				{
-					llwarns << mID << ": Setting min discard to " << current_discard << llendl;
+					//llwarns << mID << ": Setting min discard to " << current_discard << llendl;
 					mMinDiscardLevel = current_discard;
 					desired_discard = current_discard;
 				}
 				destroyRawImage();
 			}
-			else if (mRawImage.isNull())
+			else if (mRawImage.notNull())
 			{
 				// We have data, but our fetch failed to return raw data
 				// *TODO: FIgure out why this is happening and fix it
@@ -1362,12 +1664,29 @@ bool LLViewerFetchedTexture::updateFetch()
 		}
 		else
 		{
+// 			// Useful debugging code for undesired deprioritization of textures.
+// 			if (decode_priority <= 0.0f && desired_discard >= 0 && desired_discard < current_discard)
+// 			{
+// 				llinfos << "Calling updateRequestPriority() with decode_priority = 0.0f" << llendl;
+// 				calcDecodePriority();
+// 			}
 			LLAppViewer::getTextureFetch()->updateRequestPriority(mID, decode_priority);
 		}
 	}
 
-	bool make_request = true;
-	
+	if (!mDontDiscard)
+	{
+		if (mBoostLevel == 0)
+		{
+			desired_discard = llmax(desired_discard, current_discard-1);
+		}
+		else
+		{
+			desired_discard = llmax(desired_discard, current_discard-2);
+		}
+	}
+
+	bool make_request = true;	
 	if (decode_priority <= 0)
 	{
 		make_request = false;
@@ -1380,6 +1699,10 @@ bool LLViewerFetchedTexture::updateFetch()
 	{
 		make_request = false;
 	}
+	else if (!isJustBound() && mCachedRawImageReady)
+	{
+		make_request = false;
+	}
 	else
 	{
 		if (mIsFetching)
@@ -1407,33 +1730,12 @@ bool LLViewerFetchedTexture::updateFetch()
 			h = mGLTexturep->getHeight(0);
 			c = mComponents;
 		}
-		if (!mDontDiscard)
-		{
-			if (mBoostLevel == 0)
-			{
-				desired_discard = llmax(desired_discard, current_discard-1);
-			}
-			else
-			{
-				desired_discard = llmax(desired_discard, current_discard-2);
-			}
-		}
-
+		
 		// bypass texturefetch directly by pulling from LLTextureCache
 		bool fetch_request_created = false;
-		if (mLocalFileName.empty())
-		{
-			fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(getID(), getTargetHost(), decode_priority,
-											 w, h, c, desired_discard,
-											 needsAux());
-		}
-		else
-		{
-			fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mLocalFileName, getID(),getTargetHost(), decode_priority,
-											 w, h, c, desired_discard,
-											 needsAux());
-		}
-
+		fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mUrl, getID(),getTargetHost(), decode_priority,
+																			  w, h, c, desired_discard, needsAux());
+		
 		if (fetch_request_created)
 		{
 			mHasFetcher = TRUE;
@@ -1463,9 +1765,82 @@ bool LLViewerFetchedTexture::updateFetch()
 	return mIsFetching ? true : false;
 }
 
+//
+//force to fetch a new raw image for this texture
+//
+BOOL LLViewerFetchedTexture::forceFetch()
+{
+	if(!mForceToSaveRawImage)
+	{
+		return false ;
+	}
+	if(mDesiredSavedRawDiscardLevel < getDiscardLevel())
+	{
+		//no need to force fetching. normal fetching flow will do the work.
+		//return false ;
+	}
+	if (mNeedsCreateTexture)
+	{
+		// We may be fetching still (e.g. waiting on write)
+		// but don't check until we've processed the raw data we have
+		//return false;
+	}
+	if(mIsFetching)
+	{
+		return false ;
+	}
+	if (mIsMissingAsset)
+	{
+		mForceToSaveRawImage = false ;
+		llassert_always(!mHasFetcher);
+		return false; // skip
+	}
+	if (!mLoadedCallbackList.empty() && mRawImage.notNull())
+	{
+		return false; // process any raw image data in callbacks before replacing
+	}
+	if(mRawImage.notNull() && mRawDiscardLevel <= mDesiredSavedRawDiscardLevel)
+	{
+		return false ; // mRawImage is enough
+	}
+
+	S32 desired_discard = mDesiredSavedRawDiscardLevel ;
+	S32 current_discard = getDiscardLevel();
+	
+	bool fetch_request_created = false;
+	S32 w=0, h=0, c=0;
+	if (current_discard >= 0)
+	{
+		w = getWidth(0);
+		h = getHeight(0);
+		c = getComponents();
+	}
+	fetch_request_created = LLAppViewer::getTextureFetch()->createRequest(mUrl, getID(),getTargetHost(), maxDecodePriority(),
+																		  w, h, c, desired_discard, needsAux());
+
+	if (fetch_request_created)
+	{				
+		mHasFetcher = TRUE;
+		mIsFetching = TRUE;
+		mRequestedDiscardLevel = desired_discard ;
+
+		mFetchState = LLAppViewer::getTextureFetch()->getFetchState(mID, mDownloadProgress, mRequestedDownloadPriority,
+																	mFetchPriority, mFetchDeltaTime, mRequestDeltaTime);
+	}	
+
+	return mIsFetching ? true : false;
+}
+
 void LLViewerFetchedTexture::setIsMissingAsset()
 {
-	llwarns << mLocalFileName << " " << mID << ": Marking image as missing" << llendl;
+	if (mUrl.empty())
+	{
+		llwarns << mID << ": Marking image as missing" << llendl;
+	}
+	else
+	{
+		llwarns << mUrl << ": Marking image as missing" << llendl;
+	}
 	if (mHasFetcher)
 	{
 		LLAppViewer::getTextureFetch()->deleteRequest(getID(), true);
@@ -1487,7 +1862,13 @@ void LLViewerFetchedTexture::setLoadedCallback( loaded_callback_func loaded_call
 	{
 		// Put in list to call this->doLoadedCallbacks() periodically
 		gTextureList.mCallbackList.insert(this);
+		mLoadedCallbackDesiredDiscardLevel = (S8)discard_level;
 	}
+	else
+	{
+		mLoadedCallbackDesiredDiscardLevel = llmin(mLoadedCallbackDesiredDiscardLevel, (S8)discard_level) ;
+	}
+
 	LLLoadedCallbackEntry* entryp = new LLLoadedCallbackEntry(loaded_callback, discard_level, keep_imageraw, userdata);
 	mLoadedCallbackList.push_back(entryp);
 	mNeedsAux |= needs_aux;
@@ -1616,7 +1997,7 @@ bool LLViewerFetchedTexture::doLoadedCallbacks()
 		// We have GL data.
 
 		destroyRawImage();
-		readBackRawImage(gl_discard);
+		reloadRawImage(mLoadedCallbackDesiredDiscardLevel);
 		llassert_always(mRawImage.notNull());
 		llassert_always(!mNeedsAux || mAuxRawImage.notNull());
 	}
@@ -1725,8 +2106,7 @@ void LLViewerFetchedTexture::forceImmediateUpdate()
 	return ;
 }
 
-// Was in LLImageGL
-LLImageRaw* LLViewerFetchedTexture::readBackRawImage(S8 discard_level)
+LLImageRaw* LLViewerFetchedTexture::reloadRawImage(S8 discard_level)
 {
 	llassert_always(mGLTexturep.notNull()) ;
 	llassert_always(discard_level >= 0);
@@ -1736,25 +2116,216 @@ LLImageRaw* LLViewerFetchedTexture::readBackRawImage(S8 discard_level)
 		llerrs << "called with existing mRawImage" << llendl;
 		mRawImage = NULL;
 	}
-	mRawImage = new LLImageRaw(mGLTexturep->getWidth(discard_level), mGLTexturep->getHeight(discard_level), mComponents);
-	sRawCount++;
-	mRawDiscardLevel = discard_level;
-	mGLTexturep->readBackRaw(mRawDiscardLevel, mRawImage, false);
-	mIsRawImageValid = TRUE;
+
+	if(mSavedRawDiscardLevel >= 0 && mSavedRawDiscardLevel <= discard_level)
+	{
+		mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()) ;
+		mRawImage->copy(getSavedRawImage()) ;
+		mRawDiscardLevel = discard_level ;
+	}
+	else
+	{		
+		//force to fetch raw image again if cached raw image is not good enough.
+		if(mCachedRawDiscardLevel > discard_level)
+		{
+			mRawImage = mCachedRawImage ;
+			mRawDiscardLevel = mCachedRawDiscardLevel;
+
+			forceToSaveRawImage(discard_level) ;
+		}
+		else //cached raw image is good enough, copy it.
+		{
+			mRawImage = new LLImageRaw(getWidth(discard_level), getHeight(discard_level), getComponents()) ;
+			mRawImage->copy(mCachedRawImage) ;
+			mRawDiscardLevel = discard_level ;
+		}
+	}
+	mIsRawImageValid = TRUE ;
+	sRawCount++;	
 	
 	return mRawImage;
 }
 
 void LLViewerFetchedTexture::destroyRawImage()
-{
-	if (mRawImage.notNull()) sRawCount--;
+{	
 	if (mAuxRawImage.notNull()) sAuxCount--;
+
+	if (mRawImage.notNull()) 
+	{
+		sRawCount--;
+		setCachedRawImage() ;
+
+		if(mForceToSaveRawImage)
+		{
+			saveRawImage() ;
+		}		
+	}
+
 	mRawImage = NULL;
 	mAuxRawImage = NULL;
 	mIsRawImageValid = FALSE;
 	mRawDiscardLevel = INVALID_DISCARD_LEVEL;
+
+	if(mForceToSaveRawImage)
+	{
+		forceFetch() ;
+	}
+}
+
+//use the mCachedRawImage to (re)generate the gl texture.
+//virtual
+void LLViewerFetchedTexture::switchToCachedImage()
+{
+	if(mCachedRawImage.notNull())
+	{
+		mRawImage = mCachedRawImage ;
+						
+		if (getComponents() != mRawImage->getComponents())
+		{
+			// We've changed the number of components, so we need to move any
+			// objects using this pool to a different pool.
+			mComponents = mRawImage->getComponents();
+			mGLTexturep->setComponents(mComponents) ;
+			gTextureList.dirtyImage(this);
+		}			
+
+		mIsRawImageValid = TRUE;
+		mRawDiscardLevel = mCachedRawDiscardLevel ;
+		gTextureList.mCreateTextureList.insert(this);
+		mNeedsCreateTexture = TRUE;		
+	}
 }
 
+void LLViewerFetchedTexture::setCachedRawImage()
+{	
+	if(mRawImage == mCachedRawImage)
+	{
+		return ;
+	}
+	if(!mIsRawImageValid)
+	{
+		return ;
+	}
+
+	if(mCachedRawImageReady)
+	{
+		return ;
+	}
+
+	if(mCachedRawDiscardLevel < 0 || mCachedRawDiscardLevel > mRawDiscardLevel)
+	{
+		S32 i = 0 ;
+		S32 w = mRawImage->getWidth() ;
+		S32 h = mRawImage->getHeight() ;
+
+		S32 max_size = MAX_CACHED_RAW_IMAGE_AREA ;
+		if(LLViewerTexture::BOOST_TERRAIN == mBoostLevel)
+		{
+			max_size = MAX_CACHED_RAW_TERRAIN_IMAGE_AREA ;
+		}		
+		if(mForSculpt)
+		{
+			max_size = MAX_CACHED_RAW_SCULPT_IMAGE_AREA ;
+			mCachedRawImageReady = !mRawDiscardLevel ;
+		}
+		else
+		{
+			mCachedRawImageReady = (!mRawDiscardLevel || ((w * h) >= max_size)) ;
+		}
+
+		while(((w >> i) * (h >> i)) > max_size)
+		{
+			++i ;
+		}
+		
+		if(i)
+		{
+			if(!(w >> i) || !(h >> i))
+			{
+				--i ;
+			}
+			//if(mForSculpt)
+			//{
+			//	mRawImage->scaleDownWithoutBlending(w >> i, h >> i) ;
+			//}
+			//else
+			{
+				mRawImage->scale(w >> i, h >> i) ;
+			}
+		}
+		mCachedRawImage = mRawImage ;
+		mCachedRawDiscardLevel = mRawDiscardLevel + i ;			
+	}
+}
+
+void LLViewerFetchedTexture::checkCachedRawSculptImage()
+{
+	if(mCachedRawImageReady && mCachedRawDiscardLevel > 0)
+	{
+		if(getDiscardLevel() != 0)
+		{
+			mCachedRawImageReady = FALSE ;
+		}
+		else if(isForSculptOnly())
+		{
+			resetTextureStats() ; //do not update this image any more.
+		}
+	}
+}
+
+void LLViewerFetchedTexture::saveRawImage() 
+{
+	if(mRawImage.isNull() || mSavedRawDiscardLevel == mRawDiscardLevel)
+	{
+		return ;
+	}
+
+	mSavedRawDiscardLevel = mRawDiscardLevel ;
+	mSavedRawImage = new LLImageRaw(mRawImage->getData(), mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents()) ;
+
+	if(mSavedRawDiscardLevel <= mDesiredSavedRawDiscardLevel)
+	{
+		mForceToSaveRawImage = FALSE ;
+	}
+
+	mLastReferencedSavedRawImageTime = sCurrentTime ;
+}
+
+void LLViewerFetchedTexture::forceToSaveRawImage(S32 desired_discard) 
+{ 
+	if(!mForceToSaveRawImage && (mDesiredSavedRawDiscardLevel < 0 || mDesiredSavedRawDiscardLevel > desired_discard))
+	{
+		mForceToSaveRawImage = TRUE ;
+		mDesiredSavedRawDiscardLevel = desired_discard ;
+	
+		forceFetch() ;
+	}
+}
+void LLViewerFetchedTexture::destroySavedRawImage()
+{
+	mSavedRawImage = NULL ;
+	mForceToSaveRawImage  = FALSE ;
+	mSavedRawDiscardLevel = -1 ;
+	mDesiredSavedRawDiscardLevel = -1 ;
+	mLastReferencedSavedRawImageTime = 0.0f ;
+}
+
+LLImageRaw* LLViewerFetchedTexture::getSavedRawImage() 
+{
+	mLastReferencedSavedRawImageTime = sCurrentTime ;
+
+	return mSavedRawImage ;
+}
+	
+BOOL LLViewerFetchedTexture::hasSavedRawImage() const
+{
+	return mSavedRawImage.notNull() ;
+}
+	
+F32 LLViewerFetchedTexture::getElapsedLastReferencedSavedRawImageTime() const
+{ 
+	return mLastReferencedSavedRawImageTime - sCurrentTime ;
+}
 //----------------------------------------------------------------------------------------------
 //atlasing
 //----------------------------------------------------------------------------------------------
@@ -1952,14 +2523,14 @@ BOOL LLViewerFetchedTexture::insertToAtlas()
 //----------------------------------------------------------------------------------------------
 //start of LLViewerLODTexture
 //----------------------------------------------------------------------------------------------
-LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, BOOL usemipmaps)
-	: LLViewerFetchedTexture(id, usemipmaps)
+LLViewerLODTexture::LLViewerLODTexture(const LLUUID& id, const LLHost& host, BOOL usemipmaps)
+	: LLViewerFetchedTexture(id, host, usemipmaps)
 {
 	init(TRUE) ;
 }
 
-LLViewerLODTexture::LLViewerLODTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps)
-	: LLViewerFetchedTexture(full_path, id, usemipmaps)
+LLViewerLODTexture::LLViewerLODTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps)
+	: LLViewerFetchedTexture(url, id, usemipmaps)
 {
 	init(TRUE) ;
 }
@@ -1977,12 +2548,25 @@ S8 LLViewerLODTexture::getType() const
 	return LLViewerTexture::LOD_TEXTURE ;
 }
 
+BOOL LLViewerLODTexture::isUpdateFrozen()
+{
+	return LLViewerTexture::sFreezeImageScalingDown && !getDiscardLevel() ;
+}
+
 // This is gauranteed to get called periodically for every texture
 //virtual
 void LLViewerLODTexture::processTextureStats()
 {
+	updateVirtualSize() ;
+
+	static LLCachedControl<bool> textures_fullres(gSavedSettings,"TextureLoadFullRes");
+	
+	if (textures_fullres)
+	{
+		mDesiredDiscardLevel = 0;
+	}
 	// Generate the request priority and render priority
-	if (mDontDiscard || !mUseMipMaps)
+	else if (mDontDiscard || !mUseMipMaps)
 	{
 		mDesiredDiscardLevel = 0;
 		if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
@@ -2011,13 +2595,7 @@ void LLViewerLODTexture::processTextureStats()
 		// If we know the output width and height, we can force the discard
 		// level to the correct value, and thus not decode more texture
 		// data than we need to.
-		/*if (mBoostLevel == LLViewerTexture::BOOST_UI ||
-			mBoostLevel == LLViewerTexture::BOOST_PREVIEW ||
-			mBoostLevel == LLViewerTexture::BOOST_AVATAR_SELF)	// what about AVATAR_BAKED_SELF?
-		{
-			discard_level = 0; // full res
-		}
-		else*/ if (mKnownDrawWidth && mKnownDrawHeight)
+		if (mKnownDrawWidth && mKnownDrawHeight)
 		{
 			S32 draw_texels = mKnownDrawWidth * mKnownDrawHeight;
 
@@ -2028,6 +2606,12 @@ void LLViewerLODTexture::processTextureStats()
 		}
 		else
 		{
+			if(isLargeImage() && !isJustBound() && mAdditionalDecodePriority < 1.0f)
+			{
+				//if is a big image and not being used recently, nor close to the view point, do not load hi-res data.
+				mMaxVirtualSize = llmin(mMaxVirtualSize, (F32)LLViewerTexture::sMinLargeImageSize) ;
+			}
+
 			if ((mCalculatedDiscardLevel >= 0.f) &&
 				(llabs(mMaxVirtualSize - mDiscardVirtualSize) < mMaxVirtualSize*.20f))
 			{
@@ -2044,13 +2628,11 @@ void LLViewerLODTexture::processTextureStats()
 		}
 		if (mBoostLevel < LLViewerTexture::BOOST_HIGH)
 		{
-			static const F32 discard_bias = -.5f; // Must be < 1 or highest discard will never load!
-			discard_level += discard_bias;
 			discard_level += sDesiredDiscardBias;
 			discard_level *= sDesiredDiscardScale; // scale
+			discard_level += sCameraMovingDiscardBias ;
 		}
 		discard_level = floorf(discard_level);
-// 		discard_level -= (gTextureList.mVideoMemorySetting>>1); // more video ram = higher detail
 
 		F32 min_discard = 0.f;
 		if (mFullWidth > MAX_IMAGE_SIZE_DEFAULT || mFullHeight > MAX_IMAGE_SIZE_DEFAULT)
@@ -2069,46 +2651,39 @@ void LLViewerLODTexture::processTextureStats()
 		// proper action if we don't.
 		//
 
-		BOOL increase_discard = FALSE;
 		S32 current_discard = getDiscardLevel();
 		if ((sDesiredDiscardBias > 0.0f) &&
 			(current_discard >= 0 && mDesiredDiscardLevel >= current_discard))
 		{
-			if ( BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) > sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale)			
+			// Limit the amount of GL memory bound each frame
+			if ( BYTES_TO_MEGA_BYTES(sBoundTextureMemoryInBytes) > sMaxBoundTextureMemInMegaBytes * texmem_middle_bound_scale &&
+				(!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel))
 			{
-				// Limit the amount of GL memory bound each frame
-				if (mDesiredDiscardLevel > current_discard)
-				{
-					increase_discard = TRUE;
-				}
-			}
-			if ( BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) > sMaxTotalTextureMemInMegaBytes*texmem_middle_bound_scale)			
-			{
-				// Only allow GL to have 2x the video card memory
-				if (!mGLTexturep->getBoundRecently())
-				{
-					increase_discard = TRUE;
-				}
+				scaleDown() ;
 			}
-			if (increase_discard)
+			// Only allow GL to have 2x the video card memory
+			else if ( BYTES_TO_MEGA_BYTES(sTotalTextureMemoryInBytes) > sMaxTotalTextureMemInMegaBytes*texmem_middle_bound_scale &&
+				(!getBoundRecently() || mDesiredDiscardLevel >= mCachedRawDiscardLevel))
 			{
-				// 			llinfos << "DISCARDED: " << mID << " Discard: " << current_discard << llendl;
-				sBoundTextureMemoryInBytes -= mGLTexturep->mTextureMemory;
-				sTotalTextureMemoryInBytes -= mGLTexturep->mTextureMemory;
-				// Increase the discard level (reduce the texture res)
-				S32 new_discard = current_discard+1;
-				mGLTexturep->setDiscardLevel(new_discard);
-				sBoundTextureMemoryInBytes += mGLTexturep->mTextureMemory;
-				sTotalTextureMemoryInBytes += mGLTexturep->mTextureMemory;
-				if(LLViewerTextureManager::sTesterp)
-				{
-					LLViewerTextureManager::sTesterp->setStablizingTime() ;
-				}
+				scaleDown() ;
+				
 			}
 		}
 	}
 }
 
+void LLViewerLODTexture::scaleDown()
+{
+	if(hasGLTexture() && mCachedRawDiscardLevel > getDiscardLevel())
+	{		
+		switchToCachedImage() ;	
+
+		if(LLViewerTextureManager::sTesterp)
+		{
+			LLViewerTextureManager::sTesterp->setStablizingTime() ;
+		}
+	}
+}
 //----------------------------------------------------------------------------------------------
 //end of LLViewerLODTexture
 //----------------------------------------------------------------------------------------------
@@ -2189,6 +2764,8 @@ LLViewerMediaTexture::LLViewerMediaTexture(const LLUUID& id, BOOL usemipmaps, LL
 	mIsPlaying = FALSE ;
 
 	setMediaImpl() ;
+
+	setCategory(LLViewerTexture::MEDIA) ;
 }
 
 //virtual 
@@ -2723,7 +3300,7 @@ void LLTexturePipelineTester::updateTextureLoadingStats(const LLViewerFetchedTex
 		mTotalBytesLoadedForLargeImage += data_size ;
 	}
 
-	if(imagep->isForSculpt())
+	if(imagep->forSculpt())
 	{
 		mTotalBytesLoadedForSculpties += data_size ;
 
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index 596bfea670b33b91fa42b5dfdc31dc9c259e009f..6620e9fca3b4386dfc83ae43f7870d9952e8266d 100644
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -121,11 +121,23 @@ class LLViewerTexture : public LLTexture
 		BOOST_UI			= 15,
 		BOOST_PREVIEW		= 16,
 		BOOST_MAP			= 17,
-		BOOST_MAP_LAYER		= 18,
+		BOOST_MAP_VISIBLE	= 18,
 		BOOST_AVATAR_SELF	= 19, // needed for baking avatar
-		BOOST_MAX_LEVEL
+		BOOST_MAX_LEVEL,
+
+		//other texture Categories
+		LOCAL = BOOST_MAX_LEVEL,
+		AVATAR_SCRATCH_TEX,
+		DYNAMIC_TEX,
+		MEDIA,
+		ATLAS,
+		OTHER,
+		MAX_GL_IMAGE_CATEGORY
 	};
-	
+	static S32 getTotalNumOfCategories() ;
+	static S32 getIndexFromCategory(S32 category) ;
+	static S32 getCategoryFromIndex(S32 index) ;
+
 	typedef std::list<LLFace*> ll_face_list_t ;
 
 protected:
@@ -146,7 +158,7 @@ class LLViewerTexture : public LLTexture
 	virtual BOOL isMissingAsset()const ;
 	virtual void dump();	// debug info to llinfos
 	
-	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) const ;
+	/*virtual*/ bool bindDefaultImage(const S32 stage = 0) ;
 	/*virtual*/ void forceImmediateUpdate() ;
 	
 	const LLUUID& getID() const { return mID; }
@@ -154,9 +166,9 @@ class LLViewerTexture : public LLTexture
 	void setBoostLevel(S32 level);
 	S32  getBoostLevel() { return mBoostLevel; }
 
-	//maxVirtualSize of the texture
-	void addTextureStats(F32 virtual_size) const ;
-	void resetTextureStats(BOOL zero = FALSE);
+	void addTextureStats(F32 virtual_size, BOOL needs_gltexture = TRUE) const;
+	void resetTextureStats();	
+
 	virtual F32  getMaxVirtualSize() ;
 
 	LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;}
@@ -180,7 +192,7 @@ class LLViewerTexture : public LLTexture
 	BOOL       hasGLTexture() const ;
 	LLGLuint   getTexName() const ;		
 	BOOL       createGLTexture() ;
-	BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0);
+	BOOL       createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename = 0, BOOL to_create = TRUE, S32 category = LLViewerTexture::OTHER);
 
 	void       setFilteringOption(LLTexUnit::eTextureFilterOptions option);
 	void       setExplicitFormat(LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format = 0, BOOL swap_bytes = FALSE);
@@ -188,7 +200,8 @@ class LLViewerTexture : public LLTexture
 	BOOL       setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height);
 	BOOL       setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height);
 	void       setGLTextureCreated (bool initialized);
-	
+	void       setCategory(S32 category) ;
+
 	LLTexUnit::eTextureAddressMode getAddressMode(void) const ;
 	S32        getMaxDiscardLevel() const;
 	S32        getDiscardLevel() const;
@@ -201,8 +214,8 @@ class LLViewerTexture : public LLTexture
 	BOOL       getMask(const LLVector2 &tc);
 	F32        getTimePassedSinceLastBound();
 	BOOL       getMissed() const ;
-	BOOL       isValidForSculpt(S32 discard_level, S32 image_width, S32 image_height, S32 ncomponents) ;
-	BOOL       readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok) const;
+	BOOL       isJustBound()const ;
+	void       forceUpdateBindStats(void) const;
 
 	U32        getTexelsInAtlas() const ;
 	U32        getTexelsInGLTexture() const ;
@@ -220,6 +233,7 @@ class LLViewerTexture : public LLTexture
 	BOOL getDontDiscard() const { return mDontDiscard; }
 	//-----------------	
 	
+	BOOL isLargeImage() ;	
 	/*virtual*/ void updateBindStatsForTester() ;
 protected:
 	void cleanup() ;
@@ -228,6 +242,7 @@ class LLViewerTexture : public LLTexture
 private:
 	//note: do not make this function public.
 	/*virtual*/ LLImageGL* getGLTexture() const ;
+	virtual void switchToCachedImage();
 
 protected:
 	LLUUID mID;
@@ -237,7 +252,9 @@ class LLViewerTexture : public LLTexture
 	BOOL  mUseMipMaps ;
 	S8  mComponents;
 	mutable F32 mMaxVirtualSize;	// The largest virtual size of the image, in pixels - how much data to we need?
+	mutable S8  mNeedsGLTexture;
 	mutable BOOL mNeedsResetMaxVirtualSize ;
+	mutable F32 mAdditionalDecodePriority;  // priority add to mDecodePriority.
 	LLFrameTimer mLastReferencedTimer;
 
 	ll_face_list_t mFaceList ; //reverse pointer pointing to the faces using this image as texture
@@ -270,7 +287,12 @@ class LLViewerTexture : public LLTexture
 	static S32 sMaxBoundTextureMemInMegaBytes;
 	static S32 sMaxTotalTextureMemInMegaBytes;
 	static S32 sMaxDesiredTextureMemInBytes ;
-	static BOOL sDontLoadVolumeTextures;
+	static S8  sCameraMovingDiscardBias;
+	static S32 sMaxSculptRez ;
+	static S32 sMinLargeImageSize ;
+	static S32 sMaxSmallImageSize ;
+	static BOOL sFreezeImageScalingDown ;//do not scale down image res if set.
+	static F32  sCurrentTime ;
 	static BOOL sUseTextureAtlas ;
 
 	static LLPointer<LLViewerTexture> sNullImagep; // Null texture for non-textured objects.
@@ -290,9 +312,9 @@ class LLViewerFetchedTexture : public LLViewerTexture
 protected:
 	/*virtual*/ ~LLViewerFetchedTexture();
 public:
-	LLViewerFetchedTexture(const LLUUID& id, BOOL usemipmaps = TRUE);
+	LLViewerFetchedTexture(const LLUUID& id, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE);
 	LLViewerFetchedTexture(const LLImageRaw* raw, BOOL usemipmaps);
-	LLViewerFetchedTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps = TRUE);
+	LLViewerFetchedTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps = TRUE);
 
 public:
 	static F32 maxDecodePriority();
@@ -328,6 +350,8 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	bool hasCallbacks() { return mLoadedCallbackList.empty() ? false : true; }	
 	bool doLoadedCallbacks();
 
+	void addToCreateTexture();
+
 	 // ONLY call from LLViewerTextureList
 	BOOL createTexture(S32 usename = 0);
 	void destroyTexture() ;	
@@ -346,7 +370,12 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	// the priority list, and cause horrible things to happen.
 	void setDecodePriority(F32 priority = -1.0f);
 	F32 getDecodePriority() const { return mDecodePriority; };
+
+	void setAdditionalDecodePriority(F32 priority) ;
+	F32  maxAdditionalDecodePriority() ;
 	
+	void updateVirtualSize() ;
+
 	// setDesiredDiscardLevel is only used by LLViewerTextureList
 	void setDesiredDiscardLevel(S32 discard) { mDesiredDiscardLevel = discard; }
 	S32  getDesiredDiscardLevel()			 { return mDesiredDiscardLevel; }
@@ -370,15 +399,15 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	BOOL isInImageList() const {return mInImageList ;}
 	void setInImageList(BOOL flag) {mInImageList = flag ;}
 
-	const std::string& getLocalFileName() const {return mLocalFileName ;}
 	LLFrameTimer* getLastPacketTimer() {return &mLastPacketTimer;}
 
 	U32 getFetchPriority() const { return mFetchPriority ;}
 	F32 getDownloadProgress() const {return mDownloadProgress ;}
 
-	LLImageRaw* readBackRawImage(S8 discard_level) ;
+	LLImageRaw* reloadRawImage(S8 discard_level) ;
 	void destroyRawImage();
 
+	const std::string& getUrl() const {return mUrl;}
 	//---------------
 	BOOL isDeleted() ;
 	BOOL isInactive() ;
@@ -389,13 +418,36 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	//---------------
 
 	void setForSculpt();
-	BOOL isForSculpt() const {return mForSculpt;}
+	BOOL forSculpt() const {return mForSculpt;}
+	BOOL isForSculptOnly() const;
+
+	//raw image management	
+	void        checkCachedRawSculptImage() ;
+	LLImageRaw* getRawImage()const { return mRawImage ;}
+	S32         getRawImageLevel() const {return mRawDiscardLevel;}
+	LLImageRaw* getCachedRawImage() const { return mCachedRawImage ;}
+	S32         getCachedRawImageLevel() const {return mCachedRawDiscardLevel;}
+	BOOL        isCachedRawImageReady() const {return mCachedRawImageReady ;}
+	BOOL        isRawImageValid()const { return mIsRawImageValid ; }	
+	void        forceToSaveRawImage(S32 desired_discard = 0) ;
+	void        destroySavedRawImage() ;
+	LLImageRaw* getSavedRawImage() ;
+	BOOL        hasSavedRawImage() const ;
+	F32         getElapsedLastReferencedSavedRawImageTime() const ;
+	BOOL		isFullyLoaded() const;
+
+protected:
+	/*virtual*/ void switchToCachedImage();
 
 private:
 	void init(bool firstinit) ;
 	void cleanup() ;
 
 	F32 calcDecodePriorityForUnknownTexture(F32 pixel_priority) ;
+	void saveRawImage() ;
+	BOOL forceFetch() ;
+	void setCachedRawImage() ;
+	BOOL keepReuestedDiscardLevel();
 
 	//for atlas
 	void resetFaceAtlas() ;
@@ -414,12 +466,8 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	S32 mKnownDrawWidth;
 	S32	mKnownDrawHeight;
 
-	std::string mLocalFileName;
-
-	S8  mDesiredDiscardLevel;			// The discard level we'd LIKE to have - if we have it and there's space	
-	S8  mMinDesiredDiscardLevel;	// The minimum discard level we'd like to have
-	S32	mMinDiscardLevel;
-
+	std::string mUrl;
+	
 	S32 mRequestedDiscardLevel;
 	F32 mRequestedDownloadPriority;
 	S32 mFetchState;
@@ -429,6 +477,10 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	F32 mRequestDeltaTime;
 	S32 mDecodeFrame;
 	S32 mVisibleFrame; // decode frame where image was last visible
+	F32 mDecodePriority;			// The priority for decoding this image.
+	S32	mMinDiscardLevel;
+	S8  mDesiredDiscardLevel;			// The discard level we'd LIKE to have - if we have it and there's space	
+	S8  mMinDesiredDiscardLevel;	// The minimum discard level we'd like to have
 
 	S8  mNeedsAux;					// We need to decode the auxiliary channels
 	S8  mDecodingAux;				// Are we decoding high components
@@ -436,10 +488,10 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	S8  mHasFetcher;				// We've made a fecth request
 	S8  mIsFetching;				// Fetch request is active
 	
-	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.	
+	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		
 
-	F32 mDecodePriority;			// The priority for decoding this image.
 	typedef std::list<LLLoadedCallbackEntry*> callback_list_t;
+	S8              mLoadedCallbackDesiredDiscardLevel;
 	callback_list_t mLoadedCallbackList;
 
 	LLPointer<LLImageRaw> mRawImage;
@@ -449,6 +501,19 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	// doing if you use it for anything else! - djs
 	LLPointer<LLImageRaw> mAuxRawImage;
 
+	//keep a copy of mRawImage for some special purposes
+	//when mForceToSaveRawImage is set.
+	BOOL mForceToSaveRawImage ;
+	LLPointer<LLImageRaw> mSavedRawImage;
+	S32 mSavedRawDiscardLevel;
+	S32 mDesiredSavedRawDiscardLevel;
+	F32 mLastReferencedSavedRawImageTime ;
+
+	//a small version of the copy of the raw image (<= 64 * 64)
+	LLPointer<LLImageRaw> mCachedRawImage;
+	S32 mCachedRawDiscardLevel;
+	BOOL mCachedRawImageReady; //the rez of the mCachedRawImage reaches the upper limit.	
+
 	LLHost mTargetHost;	// if LLHost::invalid, just request from agent's simulator
 
 	// Timers
@@ -477,15 +542,17 @@ class LLViewerLODTexture : public LLViewerFetchedTexture
 	/*virtual*/ ~LLViewerLODTexture(){}
 
 public:
-	LLViewerLODTexture(const LLUUID& id, BOOL usemipmaps = TRUE);
-	LLViewerLODTexture(const std::string& full_path, const LLUUID& id, BOOL usemipmaps = TRUE);
+	LLViewerLODTexture(const LLUUID& id, const LLHost& host = LLHost::invalid, BOOL usemipmaps = TRUE);
+	LLViewerLODTexture(const std::string& url, const LLUUID& id, BOOL usemipmaps = TRUE);
 
 	/*virtual*/ S8 getType() const;
 	// Process image stats to determine priority/quality requirements.
 	/*virtual*/ void processTextureStats();
-	
+	BOOL isUpdateFrozen() ;
+
 private:
 	void init(bool firstinit) ;
+	void scaleDown() ;		
 
 private:
 	
@@ -608,6 +675,15 @@ class LLViewerTextureManager
 									 const LLUUID& force_id = LLUUID::null
 									 );
 
+	static LLViewerFetchedTexture* getFetchedTextureFromUrl(const std::string& url,									 
+									 BOOL usemipmap = TRUE,
+									 BOOL level_immediate = FALSE,		// Get the requested level immediately upon creation.
+									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+									 LLGLint internal_format = 0,
+									 LLGLenum primary_format = 0,
+									 const LLUUID& force_id = LLUUID::null
+									 );
+
 	static LLViewerFetchedTexture* getFetchedTextureFromHost(const LLUUID& image_id, LLHost host) ;
 
 	static void init() ;
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 4ad4c8e1ea1dc8dd1f41dce300f98f14c50a0e8a..31aedf666bbcde358dc43c42c5fe4864ab363ea4 100644
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -44,6 +44,7 @@
 #include "llimagetga.h"
 #include "llimagejpeg.h"
 #include "llimagepng.h"
+#include "llimageworker.h"
 
 #include "llsdserialize.h"
 #include "llsys.h"
@@ -68,10 +69,15 @@
 
 void (*LLViewerTextureList::sUUIDCallback)(void **, const LLUUID&) = NULL;
 
-const S32 IMAGES_PER_REQUEST = 42;
-const S32 IMAGES_MIN_UPDATES = 4;  // Always update the highest N images each frame
-const S32 IMAGES_MAX_PACKET_UPDATES = 1; // Only send N packets of IMAGES_PER_REQUEST in a frame
-const F32 RESEND_IMAGE_REQUEST_TIME = 15.f; // seconds
+U32 LLViewerTextureList::sTextureBits = 0;
+U32 LLViewerTextureList::sTexturePackets = 0;
+S32 LLViewerTextureList::sNumImages = 0;
+LLStat LLViewerTextureList::sNumImagesStat(32, TRUE);
+LLStat LLViewerTextureList::sNumRawImagesStat(32, TRUE);
+LLStat LLViewerTextureList::sGLTexMemStat(32, TRUE);
+LLStat LLViewerTextureList::sGLBoundMemStat(32, TRUE);
+LLStat LLViewerTextureList::sRawMemStat(32, TRUE);
+LLStat LLViewerTextureList::sFormattedMemStat(32, TRUE);
 
 LLViewerTextureList gTextureList;
 static LLFastTimer::DeclareTimer FTM_PROCESS_IMAGES("Process Images");
@@ -88,7 +94,7 @@ LLViewerTextureList::LLViewerTextureList()
 
 void LLViewerTextureList::init()
 {
-	mNumImages = 0;
+	sNumImages = 0;
 	mMaxResidentTexMemInMegaBytes = 0;
 	mMaxTotalTextureMemInMegaBytes = 0 ;
 	if (gNoRender)
@@ -231,6 +237,10 @@ void LLViewerTextureList::shutdown()
 		{
 			continue; // avoid UI, baked, and other special images
 		}
+		if(!image->getBoundRecently())
+		{
+			continue ;
+		}
 		S32 desired = image->getDesiredDiscardLevel();
 		if (desired >= 0 && desired < MAX_DISCARD_LEVEL)
 		{
@@ -321,17 +331,30 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
 												   LLGLenum primary_format, 
 												   const LLUUID& force_id)
 {
-	if (gNoRender)
+	std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename);
+	if (full_path.empty())
 	{
-		// Never mind that this ignores image_set_id;
-		// getImage() will handle that later.
+		llwarns << "Failed to find local image file: " << filename << llendl;
 		return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE);
 	}
 
-	std::string full_path = gDirUtilp->findSkinnedFilename("textures", filename);
-	if (full_path.empty())
+	std::string url = "file://" + full_path;
+
+	return getImageFromUrl(url, usemipmaps, level_immediate, texture_type, internal_format, primary_format, force_id);
+}
+
+LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string& url,
+												   BOOL usemipmaps,
+												   BOOL level_immediate,
+												   S8 texture_type,
+												   LLGLint internal_format,
+												   LLGLenum primary_format, 
+												   const LLUUID& force_id)
+{
+	if (gNoRender)
 	{
-		llwarns << "Failed to find local image file: " << filename << llendl;
+		// Never mind that this ignores image_set_id;
+		// getImage() will handle that later.
 		return LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT, TRUE, TRUE);
 	}
 
@@ -343,7 +366,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
 	}
 	else
 	{
-		new_id.generate(full_path);
+		new_id.generate(url);
 	}
 
 	LLPointer<LLViewerFetchedTexture> imagep = findImage(new_id);
@@ -353,10 +376,10 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
 		switch(texture_type)
 		{
 		case LLViewerTexture::FETCHED_TEXTURE:
-			imagep = new LLViewerFetchedTexture(full_path, new_id, usemipmaps);
+			imagep = new LLViewerFetchedTexture(url, new_id, usemipmaps);
 			break ;
 		case LLViewerTexture::LOD_TEXTURE:
-			imagep = new LLViewerLODTexture(full_path, new_id, usemipmaps);
+			imagep = new LLViewerLODTexture(url, new_id, usemipmaps);
 			break ;
 		default:
 			llerrs << "Invalid texture type " << texture_type << llendl ;
@@ -372,7 +395,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string&
 		if (level_immediate)
 		{
 			imagep->dontDiscard();
-			imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_UI);
+			imagep->setBoostLevel(LLViewerTexture::BOOST_UI);
 		}
 	}
 
@@ -424,18 +447,15 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
 	switch(texture_type)
 	{
 	case LLViewerTexture::FETCHED_TEXTURE:
-		imagep = new LLViewerFetchedTexture(image_id, usemipmaps);
+		imagep = new LLViewerFetchedTexture(image_id, request_from_host, usemipmaps);
 		break ;
 	case LLViewerTexture::LOD_TEXTURE:
-		imagep = new LLViewerLODTexture(image_id, usemipmaps);
+		imagep = new LLViewerLODTexture(image_id, request_from_host, usemipmaps);
 		break ;
 	default:
 		llerrs << "Invalid texture type " << texture_type << llendl ;
 	}
 	
-	// Might want to request from host other than where the agent is. JC
-	imagep->setTargetHost(request_from_host);
-	
 	if (internal_format && primary_format)
 	{
 		imagep->setExplicitFormat(internal_format, primary_format);
@@ -446,7 +466,7 @@ LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
 	if (level_immediate)
 	{
 		imagep->dontDiscard();
-		imagep->setBoostLevel(LLViewerFetchedTexture::BOOST_UI);
+		imagep->setBoostLevel(LLViewerTexture::BOOST_UI);
 	}
 	else
 	{
@@ -509,7 +529,7 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image)
 	{
 		llwarns << "Image with ID " << image_id << " already in list" << llendl;
 	}
-	mNumImages++;
+	sNumImages++;
 	
 	addImageToList(new_image);
 	mUUIDMap[image_id] = new_image;
@@ -526,7 +546,7 @@ void LLViewerTextureList::deleteImage(LLViewerFetchedTexture *image)
 		}
 
 		llverify(mUUIDMap.erase(image->getID()) == 1);
-		mNumImages--;
+		sNumImages--;
 		removeImageFromList(image);
 	}
 }
@@ -546,7 +566,9 @@ static LLFastTimer::DeclareTimer FTM_IMAGE_MARK_DIRTY("Dirty Images");
 
 void LLViewerTextureList::updateImages(F32 max_time)
 {
-	LLViewerStats::getInstance()->mNumImagesStat.addValue(mNumImages);
+	LLAppViewer::getTextureFetch()->setTextureBandwidth(LLViewerStats::getInstance()->mTextureKBitStat.getMeanPerSec());
+
+	LLViewerStats::getInstance()->mNumImagesStat.addValue(sNumImages);
 	LLViewerStats::getInstance()->mNumRawImagesStat.addValue(LLImageRaw::sRawImageCount);
 	LLViewerStats::getInstance()->mGLTexMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sGlobalTextureMemoryInBytes));
 	LLViewerStats::getInstance()->mGLBoundMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageGL::sBoundTextureMemoryInBytes));
@@ -554,10 +576,13 @@ void LLViewerTextureList::updateImages(F32 max_time)
 	LLViewerStats::getInstance()->mFormattedMemStat.addValue((F32)BYTES_TO_MEGA_BYTES(LLImageFormatted::sGlobalFormattedMemory));
 	
 	updateImagesDecodePriorities();
+
+	F32 total_max_time = max_time;
 	max_time -= updateImagesFetchTextures(max_time);
-	max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f);
+	
+	max_time = llmax(max_time, total_max_time*.25f); // at least 25% of max_time
 	max_time -= updateImagesCreateTextures(max_time);
-	max_time = llmin(llmax(max_time, 0.001f*10.f*gFrameIntervalSeconds), 0.001f);
+	
 	if (!mDirtyTextureList.empty())
 	{
 		LLFastTimer t(FTM_IMAGE_MARK_DIRTY);
@@ -570,7 +595,7 @@ void LLViewerTextureList::updateImages(F32 max_time)
 	{
 		//trigger loaded callbacks on local textures immediately
 		LLViewerFetchedTexture* image = *iter++;
-		if (!image->getLocalFileName().empty())
+		if (!image->getUrl().empty())
 		{
 			// Do stuff to handle callbacks, update priorities, etc.
 			didone = image->doLoadedCallbacks();
@@ -628,6 +653,14 @@ void LLViewerTextureList::updateImagesDecodePriorities()
 			}
 			else
 			{
+				if(imagep->hasSavedRawImage())
+				{
+					if(imagep->getElapsedLastReferencedSavedRawImageTime() > MAX_INACTIVE_TIME)
+					{
+						imagep->destroySavedRawImage() ;
+					}
+				}
+
 				if(imagep->isDeleted())
 				{
 					continue ;
@@ -758,74 +791,76 @@ F32 LLViewerTextureList::updateImagesFetchTextures(F32 max_time)
 	const size_t max_update_count = llmin((S32) (1024*10.f*gFrameIntervalSeconds)+1, 256);
 	
 	// 32 high priority entries
-	std::set<LLViewerFetchedTexture*> entries;
+	typedef std::vector<LLViewerFetchedTexture*> entries_list_t;
+	entries_list_t entries;
 	size_t update_counter = llmin(max_priority_count, mImageList.size());
 	image_priority_list_t::iterator iter1 = mImageList.begin();
 	while(update_counter > 0)
 	{
-		// added extra granularity and verbosity for crash logging during 1.19.1 RC. -Brad
-		if(iter1 == mImageList.end())
-		{
-			llerrs << "DEV-12002: update_counter not calculated correctly!" << llendl;
-			return 0.f;
-		}
-
-		LLPointer<LLViewerFetchedTexture> const & ptr = *iter1;
-
-		LLViewerFetchedTexture * img = ptr.get();
-
-		// added extra granularity and verbosity for crash logging during 1.19.1 RC. -Brad
-		if(img == NULL)
-		{
-			llwarns << "DEV-12002: image is NULL!" << llendl;
-		}
-
-		entries.insert(img);
-
+		entries.push_back(*iter1);
+		
 		++iter1;
 		update_counter--;
 	}
 	
 	// 256 cycled entries
-	update_counter = llmin(max_update_count, mUUIDMap.size());
-	uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID);
-	while(update_counter > 0)
+	update_counter = llmin(max_update_count, mUUIDMap.size());	
+	if(update_counter > 0)
 	{
-		if (iter2 == mUUIDMap.end())
+		uuid_map_t::iterator iter2 = mUUIDMap.upper_bound(mLastFetchUUID);
+		uuid_map_t::iterator iter2p = iter2;
+		while(update_counter > 0)
 		{
-			iter2 = mUUIDMap.begin();
+			if (iter2 == mUUIDMap.end())
+			{
+				iter2 = mUUIDMap.begin();
+			}
+			entries.push_back(iter2->second);
+			iter2p = iter2++;
+			update_counter--;
 		}
-		mLastFetchUUID = iter2->first;
-		entries.insert(iter2->second);
-		++iter2;
-		update_counter--;
+
+		mLastFetchUUID = iter2p->first;
 	}
 	
+	S32 fetch_count = 0;
 	S32 min_count = max_priority_count + max_update_count/4;
-	for (std::set<LLViewerFetchedTexture*>::iterator iter3 = entries.begin();
+	for (entries_list_t::iterator iter3 = entries.begin();
 		 iter3 != entries.end(); )
 	{
 		LLPointer<LLViewerFetchedTexture> imagep = *iter3++;
 		
-		imagep->updateFetch();
+		bool fetching = imagep->updateFetch();
+		if (fetching)
+		{
+			fetch_count++;
+		}
 		if (min_count <= 0 && image_op_timer.getElapsedTimeF32() > max_time)
 		{
 			break;
 		}
 		min_count--;
 	}
+	if (fetch_count == 0)
+	{
+		gDebugTimers[0].pause();
+	}
+	else
+	{
+		gDebugTimers[0].unpause();
+	}
 	return image_op_timer.getElapsedTimeF32();
 }
 
 void LLViewerTextureList::updateImagesUpdateStats()
 {
-	if (mUpdateStats)
+	if (mUpdateStats && mForceResetTextureStats)
 	{
 		for (image_priority_list_t::iterator iter = mImageList.begin();
 			 iter != mImageList.end(); )
 		{
 			LLViewerFetchedTexture* imagep = *iter++;
-			imagep->resetTextureStats(mForceResetTextureStats);
+			imagep->resetTextureStats();
 		}
 		mUpdateStats = FALSE;
 		mForceResetTextureStats = FALSE;
@@ -1011,6 +1046,9 @@ LLPointer<LLImageJ2C> LLViewerTextureList::convertToUploadFile(LLPointer<LLImage
 	return compressedImage;
 }
 
+const S32 MIN_VIDEO_RAM = 32;
+const S32 MAX_VIDEO_RAM = 512; // 512MB max for performance reasons.
+
 // Returns min setting for TextureMemory (in MB)
 S32 LLViewerTextureList::getMinVideoRamSetting()
 {
@@ -1129,13 +1167,13 @@ void LLViewerTextureList::receiveImageHeader(LLMessageSystem *msg, void **user_d
 	
 	if (msg->getReceiveCompressedSize())
 	{
-		gTextureList.mTextureBits += msg->getReceiveCompressedSize() * 8;
+		gTextureList.sTextureBits += msg->getReceiveCompressedSize() * 8;
 	}
 	else
 	{
-		gTextureList.mTextureBits += msg->getReceiveSize() * 8;
+		gTextureList.sTextureBits += msg->getReceiveSize() * 8;
 	}
-	gTextureList.mTexturePackets++;
+	gTextureList.sTexturePackets++;
 	
 	U8 codec;
 	U16 packets;
@@ -1194,13 +1232,13 @@ void LLViewerTextureList::receiveImagePacket(LLMessageSystem *msg, void **user_d
 	
 	if (msg->getReceiveCompressedSize())
 	{
-		gTextureList.mTextureBits += msg->getReceiveCompressedSize() * 8;
+		gTextureList.sTextureBits += msg->getReceiveCompressedSize() * 8;
 	}
 	else
 	{
-		gTextureList.mTextureBits += msg->getReceiveSize() * 8;
+		gTextureList.sTextureBits += msg->getReceiveSize() * 8;
 	}
-	gTextureList.mTexturePackets++;
+	gTextureList.sTexturePackets++;
 	
 	//llprintline("Start decode, image header...");
 	msg->getUUIDFast(_PREHASH_ImageID, _PREHASH_ID, id);
@@ -1385,7 +1423,7 @@ void LLUIImageList::onUIImageLoaded( BOOL success, LLViewerFetchedTexture *src_v
 
 		// for images grabbed from local files, apply clipping rectangle to restore original dimensions
 		// from power-of-2 gl image
-		if (success && imagep.notNull() && src_vi && !src_vi->getLocalFileName().empty())
+		if (success && imagep.notNull() && src_vi && (src_vi->getUrl().compare(0, 7, "file://")==0))
 		{
 			F32 clip_x = (F32)src_vi->getOriginalWidth() / (F32)src_vi->getFullWidth();
 			F32 clip_y = (F32)src_vi->getOriginalHeight() / (F32)src_vi->getFullHeight();
@@ -1442,6 +1480,11 @@ bool LLUIImageList::initFromFile()
 		llwarns << "Unable to parse UI image list file " << base_file_path << llendl;
 		return false;
 	}
+	if (!root->hasAttribute("version"))
+	{
+		llwarns << "No valid version number in UI image list file " << base_file_path << llendl;
+		return false;
+	}
 
 	std::vector<std::string> paths;
 	// path to current selected skin
diff --git a/indra/newview/llviewertexturelist.h b/indra/newview/llviewertexturelist.h
index 11d1dd855fab40ae2be32bc7ce6e7fff8b6c62da..2a86b88163d3607928f641b337115c316b8abaea 100644
--- a/indra/newview/llviewertexturelist.h
+++ b/indra/newview/llviewertexturelist.h
@@ -53,7 +53,6 @@ const BOOL GL_TEXTURE_NO = FALSE;
 const BOOL IMMEDIATE_YES = TRUE;
 const BOOL IMMEDIATE_NO = FALSE;
 
-class LLImageJ2C;
 class LLMessageSystem;
 class LLTextureView;
 
@@ -146,6 +145,15 @@ class LLViewerTextureList
 									 LLGLenum primary_format = 0,
 									 const LLUUID& force_id = LLUUID::null
 									 );
+	
+	LLViewerFetchedTexture* getImageFromUrl(const std::string& url,
+									 BOOL usemipmap = TRUE,
+									 BOOL level_immediate = FALSE,		// Get the requested level immediately upon creation.
+									 S8 texture_type = LLViewerTexture::FETCHED_TEXTURE,
+									 LLGLint internal_format = 0,
+									 LLGLenum primary_format = 0,
+									 const LLUUID& force_id = LLUUID::null
+									 );
 
 	LLViewerFetchedTexture* createImage(const LLUUID &image_id,
 									 BOOL usemipmap = TRUE,
@@ -190,11 +198,18 @@ class LLViewerTextureList
 	LLFrameTimer mForceDecodeTimer;
 	
 public:
-	U32 mTextureBits;
-	U32 mTexturePackets;
+	static U32 sTextureBits;
+	static U32 sTexturePackets;
+
+	static LLStat sNumImagesStat;
+	static LLStat sNumRawImagesStat;
+	static LLStat sGLTexMemStat;
+	static LLStat sGLBoundMemStat;
+	static LLStat sRawMemStat;
+	static LLStat sFormattedMemStat;
 
 private:
-	S32 mNumImages;
+	static S32 sNumImages;
 	static void (*sUUIDCallback)(void**, const LLUUID &);
 };
 
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 5f95e9ccf1b5c67c1ff8c74a98074dab50300c64..cee3a2a65b53725b1fa049c6cf5d9ff16eaf24de 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -117,6 +117,7 @@
 #include "llhudview.h"
 #include "llimagebmp.h"
 #include "llimagej2c.h"
+#include "llimageworker.h"
 #include "llkeyboard.h"
 #include "lllineeditor.h"
 #include "llmenugl.h"
@@ -157,7 +158,6 @@
 #include "lltoolselectland.h"
 #include "lltrans.h"
 #include "lluictrlfactory.h"
-#include "lluploaddialog.h"
 #include "llurldispatcher.h"		// SLURL from other app instance
 #include "llvieweraudio.h"
 #include "llviewercamera.h"
@@ -189,6 +189,7 @@
 #include "llbottomtray.h"
 #include "llnearbychatbar.h"
 #include "llagentui.h"
+#include "llwearablelist.h"
 
 #include "llnotificationmanager.h"
 
@@ -326,7 +327,9 @@ class LLDebugText
 				S32 hours = (S32)(time / (60*60));
 				S32 mins = (S32)((time - hours*(60*60)) / 60);
 				S32 secs = (S32)((time - hours*(60*60) - mins*60));
-				addText(xpos, ypos, llformat(" Debug %d: %d:%02d:%02d", idx, hours,mins,secs)); ypos += y_inc2;
+				std::string label = gDebugTimerLabel[idx];
+				if (label.empty()) label = llformat("Debug: %d", idx);
+				addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2;
 			}
 			
 			F32 time = gFrameTimeSeconds;
@@ -1299,6 +1302,7 @@ LLViewerWindow::LLViewerWindow(
 		
 	// Init the image list.  Must happen after GL is initialized and before the images that
 	// LLViewerWindow needs are requested.
+	LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ;
 	gTextureList.init();
 	LLViewerTextureManager::init() ;
 	gBumpImageList.init();
@@ -1657,6 +1661,8 @@ void LLViewerWindow::shutdownGL()
 	gSky.cleanup();
 	stop_glerror();
 
+	LLWearableList::instance().cleanup() ;
+
 	gTextureList.shutdown();
 	stop_glerror();
 
@@ -1670,7 +1676,10 @@ void LLViewerWindow::shutdownGL()
 	stop_glerror();
 
 	LLViewerTextureManager::cleanup() ;
-	
+	LLImageGL::cleanupClass() ;
+
+	llinfos << "All texturs and llimagegl images are destroyed!" << llendl ;
+
 	llinfos << "Cleaning up select manager" << llendl;
 	LLSelectMgr::getInstance()->cleanup();
 
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 231b857d1f0497420c99e48b4f88f9900de9c9e1..a279bd8a68125783d9d7890889293fc75f9281c0 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -321,7 +321,7 @@ class LLViewerWindow : public LLWindowCallbacks
 	} ESnapshotType;
 	BOOL			saveSnapshot(const std::string&  filename, S32 image_width, S32 image_height, BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR);
 	BOOL			rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, BOOL keep_window_aspect = TRUE, BOOL is_texture = FALSE,
-								BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_IMAGE_SIZE );
+								BOOL show_ui = TRUE, BOOL do_rebuild = FALSE, ESnapshotType type = SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE );
 	BOOL			thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type) ;
 	BOOL			isSnapshotLocSet() const { return ! sSnapshotDir.empty(); }
 	void			resetSnapshotLoc() const { sSnapshotDir.clear(); }
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index d124cbcdced8357d26f03281adbadf1ceb519606..999701ece1656d7d504659e41e03c9f52039b29f 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -279,7 +279,6 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
 		if (mRawImages[i].isNull())
 		{
 			// Read back a raw image for this discard level, if it exists
-			mRawImages[i] = new LLImageRaw;
 			S32 min_dim = llmin(mDetailTextures[i]->getFullWidth(), mDetailTextures[i]->getFullHeight());
 			S32 ddiscard = 0;
 			while (min_dim > BASE_SIZE && ddiscard < MAX_DISCARD_LEVEL)
@@ -287,12 +286,18 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
 				ddiscard++;
 				min_dim /= 2;
 			}
-			if (!mDetailTextures[i]->readBackRaw(ddiscard, mRawImages[i], false))
+
+			mDetailTextures[i]->reloadRawImage(ddiscard) ;
+			if(mDetailTextures[i]->getRawImageLevel() != ddiscard)//raw iamge is not ready, will enter here again later.
 			{
-				llwarns << "Unable to read raw data for terrain detail texture: " << mDetailTextures[i]->getID() << llendl;
-				mRawImages[i] = NULL;
+				mDetailTextures[i]->destroyRawImage() ;
+				lldebugs << "cached raw data for terrain detail texture is not ready yet: " << mDetailTextures[i]->getID() << llendl;
 				return FALSE;
 			}
+
+			mRawImages[i] = mDetailTextures[i]->getRawImage() ;
+			mDetailTextures[i]->destroyRawImage() ;
+
 			if (mDetailTextures[i]->getWidth(ddiscard) != BASE_SIZE ||
 				mDetailTextures[i]->getHeight(ddiscard) != BASE_SIZE ||
 				mDetailTextures[i]->getComponents() != 3)
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 469aef62093d0ac7fe952ec5acbb33cb7833a5d6..229227c1444b18f49fb80cff4def2e2138bb399b 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -988,7 +988,7 @@ void LLVOAvatar::resetImpostors()
 
 // static
 void LLVOAvatar::deleteCachedImages(bool clearAll)
-{
+{	
 	if (LLTexLayerSet::sHasCaches)
 	{
 		lldebugs << "Deleting layer set caches" << llendl;
@@ -3897,7 +3897,7 @@ U32 LLVOAvatar::renderFootShadows()
 	LLGLDepthTest test(GL_TRUE, GL_FALSE);
 	//render foot shadows
 	LLGLEnable blend(GL_BLEND);
-	gGL.getTexUnit(0)->bind(mShadowImagep.get());
+	gGL.getTexUnit(0)->bind(mShadowImagep, TRUE);
 	glColor4fv(mShadow0Facep->getRenderColor().mV);
 	mShadow0Facep->renderIndexed(foot_mask);
 	glColor4fv(mShadow1Facep->getRenderColor().mV);
@@ -3945,7 +3945,7 @@ U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
 //------------------------------------------------------------------------
 // LLVOAvatar::updateTextures()
 //------------------------------------------------------------------------
-void LLVOAvatar::updateTextures(LLAgent &agent)
+void LLVOAvatar::updateTextures()
 {
 	BOOL render_avatar = TRUE;
 
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index e3add8aa78f2dcd3d802d87133dcaa7e0adbbc94..c4e68064e75ff898e1adfc1061ebd56440ab79bf 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -125,7 +125,7 @@ class LLVOAvatar :
 	virtual BOOL   	 	 	updateLOD();
 	BOOL  	 	 	 	 	updateJointLODs();
 	virtual BOOL   	 	 	isActive() const; // Whether this object needs to do an idleUpdate.
-	virtual void   	 	 	updateTextures(LLAgent &agent);
+	virtual void   	 	 	updateTextures();
 	virtual S32    	 	 	setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim.
 	virtual void   	 	 	onShift(const LLVector3& shift_vector);
 	virtual U32    	 	 	getPartitionType() const;
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index 9a115ea4e6c45ea8b8f6b531a78c79131281088d..673e699c30a79f8270a03dd24fbb1d087fff0de7 100644
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -1141,26 +1141,6 @@ void LLVOAvatarSelf::localTextureLoaded(BOOL success, LLViewerFetchedTexture *sr
 	}
 }
 
-// virtual
-/* //unused
-BOOL LLVOAvatarSelf::getLocalTextureRaw(ETextureIndex index, LLImageRaw* image_raw) const
-{
-	if (!isIndexLocalTexture(index)) return FALSE;
-	if (getLocalTextureID(index) == IMG_DEFAULT_AVATAR)	return TRUE;
-
-	const LocalTextureData *local_tex_data = getLocalTextureData(index)[0];
-	if (local_tex_data->mImage->readBackRaw(-1, image_raw, false))
-	{
-
-		return TRUE;
-	}
-	
-	// No data loaded yet
-	setLocalTexture((ETextureIndex)index, getTEImage(index), FALSE); // <-- non-const, move this elsewhere
-	return FALSE;
-}
-*/
-
 // virtual
 BOOL LLVOAvatarSelf::getLocalTextureGL(ETextureIndex type, LLViewerTexture** tex_pp, U32 index) const
 {
@@ -1812,12 +1792,13 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
 
 	if (!covered_by_baked)
 	{
-		if (getLocalTextureID(type, index) != IMG_DEFAULT_AVATAR)
+		if (getLocalTextureID(type, index) != IMG_DEFAULT_AVATAR && imagep->getDiscardLevel() != 0)
 		{
 			F32 desired_pixels;
 			desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
 			imagep->setBoostLevel(getAvatarBoostLevel());
 			imagep->addTextureStats( desired_pixels / texel_area_ratio );
+			imagep->forceUpdateBindStats() ;
 			if (imagep->getDiscardLevel() < 0)
 			{
 				mHasGrey = TRUE; // for statistics gathering
@@ -2115,6 +2096,49 @@ BOOL LLVOAvatarSelf::needsRenderBeam()
 // static
 void LLVOAvatarSelf::deleteScratchTextures()
 {
+	if(gAuditTexture)
+	{
+		S32 total_tex_size = sScratchTexBytes ;
+		S32 tex_size = SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT ;
+
+		if( sScratchTexNames.checkData( GL_LUMINANCE ) )
+		{
+			LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+			total_tex_size -= tex_size ;
+		}
+		if( sScratchTexNames.checkData( GL_ALPHA ) )
+		{
+			LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+			total_tex_size -= tex_size ;
+		}
+		if( sScratchTexNames.checkData( GL_COLOR_INDEX ) )
+		{
+			LLImageGL::decTextureCounter(tex_size, 1, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+			total_tex_size -= tex_size ;
+		}
+		if( sScratchTexNames.checkData( GL_LUMINANCE_ALPHA ) )
+		{
+			LLImageGL::decTextureCounter(tex_size, 2, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+			total_tex_size -= 2 * tex_size ;
+		}
+		if( sScratchTexNames.checkData( GL_RGB ) )
+		{
+			LLImageGL::decTextureCounter(tex_size, 3, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+			total_tex_size -= 3 * tex_size ;
+		}
+		if( sScratchTexNames.checkData( GL_RGBA ) )
+		{
+			LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+			total_tex_size -= 4 * tex_size ;
+		}
+		//others
+		while(total_tex_size > 0)
+		{
+			LLImageGL::decTextureCounter(tex_size, 4, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+			total_tex_size -= 4 * tex_size ;
+		}
+	}
+
 	for( LLGLuint* namep = sScratchTexNames.getFirstData(); 
 		 namep; 
 		 namep = sScratchTexNames.getNextData() )
@@ -2137,7 +2161,8 @@ void LLVOAvatarSelf::deleteScratchTextures()
 BOOL LLVOAvatarSelf::bindScratchTexture( LLGLenum format )
 {
 	U32 texture_bytes = 0;
-	GLuint gl_name = getScratchTexName( format, &texture_bytes );
+	S32 components = 0; 
+	GLuint gl_name = getScratchTexName( format, components, &texture_bytes );
 	if( gl_name )
 	{
 		gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, gl_name);
@@ -2149,12 +2174,12 @@ BOOL LLVOAvatarSelf::bindScratchTexture( LLGLenum format )
 			if( *last_bind_time != LLImageGL::sLastFrameTime )
 			{
 				*last_bind_time = LLImageGL::sLastFrameTime;
-				LLImageGL::updateBoundTexMem(texture_bytes);
+				LLImageGL::updateBoundTexMem(texture_bytes, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
 			}
 		}
 		else
 		{
-			LLImageGL::updateBoundTexMem(texture_bytes);
+			LLImageGL::updateBoundTexMem(texture_bytes, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
 			sScratchTexLastBindTime.addData( format, new F32(LLImageGL::sLastFrameTime) );
 		}
 		return TRUE;
@@ -2162,9 +2187,8 @@ BOOL LLVOAvatarSelf::bindScratchTexture( LLGLenum format )
 	return FALSE;
 }
 
-LLGLuint LLVOAvatarSelf::getScratchTexName( LLGLenum format, U32* texture_bytes )
-{
-	S32 components;
+LLGLuint LLVOAvatarSelf::getScratchTexName( LLGLenum format, S32& components, U32* texture_bytes )
+{	
 	GLenum internal_format;
 	switch( format )
 	{
@@ -2210,6 +2234,11 @@ LLGLuint LLVOAvatarSelf::getScratchTexName( LLGLenum format, U32* texture_bytes
 
 	sScratchTexBytes += *texture_bytes;
 	LLImageGL::sGlobalTextureMemoryInBytes += *texture_bytes;
+
+	if(gAuditTexture)
+	{
+		LLImageGL::incTextureCounter(SCRATCH_TEX_WIDTH * SCRATCH_TEX_HEIGHT, components, LLViewerTexture::AVATAR_SCRATCH_TEX) ;
+	}
 	return name;
 }
 
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index a555d04a6331d4105725ec4171e044b4924a0e37..06b3b25eecd9ea7c0dd1ee8fe7ccf9331ac3a9aa 100644
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -239,7 +239,7 @@ class LLVOAvatarSelf :
 	BOOL			bindScratchTexture(LLGLenum format);
 	static void		deleteScratchTextures();
 protected:
-	LLGLuint		getScratchTexName(LLGLenum format, U32* texture_bytes);
+	LLGLuint		getScratchTexName(LLGLenum format, S32& components, U32* texture_bytes);
 private:
 	static S32 		sScratchTexBytes;
 	static LLMap< LLGLenum, LLGLuint*> sScratchTexNames;
diff --git a/indra/newview/llvoclouds.cpp b/indra/newview/llvoclouds.cpp
index 8d3c8b6f1a98b5f18094e69f3d40600f08c5adbd..177cb16c50802a5e17ab62533a0c7459ffd220af 100644
--- a/indra/newview/llvoclouds.cpp
+++ b/indra/newview/llvoclouds.cpp
@@ -101,7 +101,7 @@ void LLVOClouds::setPixelAreaAndAngle(LLAgent &agent)
 	mPixelArea = 1500*100;
 }
 
-void LLVOClouds::updateTextures(LLAgent &agent)
+void LLVOClouds::updateTextures()
 {
 	getTEImage(0)->addTextureStats(mPixelArea);
 }
diff --git a/indra/newview/llvoclouds.h b/indra/newview/llvoclouds.h
index 95e6b96e4ed5c257fd540d5fd86578af9fd9a6b0..c4a75f5b5ef3028b799d8bebcf9c7aaa2877feb2 100644
--- a/indra/newview/llvoclouds.h
+++ b/indra/newview/llvoclouds.h
@@ -65,7 +65,7 @@ class LLVOClouds : public LLAlphaObject
 	/*virtual*/ BOOL    isActive() const; // Whether this object needs to do an idleUpdate.
 	F32 getPartSize(S32 idx);
 
-	/*virtual*/ void updateTextures(LLAgent &agent);
+	/*virtual*/ void updateTextures();
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
 	
 	void updateFaceSize(S32 idx) { }
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index 570a3334b9ec4b25da058e7571bed200db5be109..33c10450a151096bde19297c52f18516d9215fec 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -322,7 +322,7 @@ void LLVOGrass::setPixelAreaAndAngle(LLAgent &agent)
 
 
 // BUG could speed this up by caching the relative_position and range calculations
-void LLVOGrass::updateTextures(LLAgent &agent)
+void LLVOGrass::updateTextures()
 {
 	if (getTEImage(0))
 	{
diff --git a/indra/newview/llvograss.h b/indra/newview/llvograss.h
index 124400d35607f1d17ae5139d368a9f0e3bb8b64b..6a6fcc31c3b7d4f50ace57c1747d05b3e424fedb 100644
--- a/indra/newview/llvograss.h
+++ b/indra/newview/llvograss.h
@@ -72,7 +72,7 @@ class LLVOGrass : public LLAlphaObject
 								LLStrider<U16>& indicesp);
 
 	void updateFaceSize(S32 idx) { }
-	/*virtual*/ void updateTextures(LLAgent &agent);											
+	/*virtual*/ void updateTextures();											
 	/*virtual*/ BOOL updateLOD();
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
 
diff --git a/indra/newview/llvoground.cpp b/indra/newview/llvoground.cpp
index ac2484ddfddcbb1c9ab40d1645caddc67d84fe9d..221c6b61ec2c0c1904b4f352a131daacdcb17a9e 100644
--- a/indra/newview/llvoground.cpp
+++ b/indra/newview/llvoground.cpp
@@ -70,7 +70,7 @@ BOOL LLVOGround::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 }
 
 
-void LLVOGround::updateTextures(LLAgent &agent)
+void LLVOGround::updateTextures()
 {
 }
 
diff --git a/indra/newview/llvoground.h b/indra/newview/llvoground.h
index af3fcd65d46827791cd18c6a88d467db3de30b60..0ccb0834a2fe388db6ce30d6ece03c6f04a48452 100644
--- a/indra/newview/llvoground.h
+++ b/indra/newview/llvoground.h
@@ -51,7 +51,7 @@ class LLVOGround : public LLStaticViewerObject
 	
 	// Graphical stuff for objects - maybe broken out into render class
 	// later?
-	/*virtual*/ void updateTextures(LLAgent &agent);
+	/*virtual*/ void updateTextures();
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
 	/*virtual*/ BOOL		updateGeometry(LLDrawable *drawable);
 
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 7585842623bee5b7886487e6473cf9db12ff07c3..f1e42f93758971a52a67e0ff06539d074f1dca77 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -108,7 +108,7 @@ void LLVOPartGroup::setPixelAreaAndAngle(LLAgent &agent)
 	}
 }
 
-void LLVOPartGroup::updateTextures(LLAgent &agent)
+void LLVOPartGroup::updateTextures()
 {
 	// Texture stats for particles need to be updated in a different way...
 }
diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h
index 3dc32929920f519cb196bf71e0979b6939245599..18583b4be9ae0b015979c811230e6dd2169eb484 100644
--- a/indra/newview/llvopartgroup.h
+++ b/indra/newview/llvopartgroup.h
@@ -61,7 +61,7 @@ class LLVOPartGroup : public LLAlphaObject
 	virtual U32 getPartitionType() const;
 	
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent);
-	/*virtual*/ void updateTextures(LLAgent &agent);
+	/*virtual*/ void updateTextures();
 
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
 	/*virtual*/ BOOL        updateGeometry(LLDrawable *drawable);
diff --git a/indra/newview/llvosky.cpp b/indra/newview/llvosky.cpp
index d44c5432669c4aa0759bb371debf2ef791f02fc6..ddf7ea03826f2e56db66d7ce3fb8417054e44804 100644
--- a/indra/newview/llvosky.cpp
+++ b/indra/newview/llvosky.cpp
@@ -289,7 +289,7 @@ void LLSkyTex::create(const F32 brightness)
 
 void LLSkyTex::createGLImage(S32 which)
 {	
-	mTexture[which]->createGLTexture(0, mImageRaw[which]);
+	mTexture[which]->createGLTexture(0, mImageRaw[which], 0, TRUE, LLViewerTexture::LOCAL);
 	mTexture[which]->setAddressMode(LLTexUnit::TAM_CLAMP);
 }
 
@@ -1180,7 +1180,7 @@ BOOL LLVOSky::updateSky()
 	return TRUE;
 }
 
-void LLVOSky::updateTextures(LLAgent &agent)
+void LLVOSky::updateTextures()
 {
 	if (mSunTexturep)
 	{
diff --git a/indra/newview/llvosky.h b/indra/newview/llvosky.h
index 62c934fb41085bdba8dbd5ebcf8d5c33c5b1489b..ef74324e58d8ded0a5bbefd183179be912c9d428 100644
--- a/indra/newview/llvosky.h
+++ b/indra/newview/llvosky.h
@@ -492,7 +492,7 @@ class LLVOSky : public LLStaticViewerObject
 	
 	// Graphical stuff for objects - maybe broken out into render class
 	// later?
-	/*virtual*/ void updateTextures(LLAgent &agent);
+	/*virtual*/ void updateTextures();
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
 	/*virtual*/ BOOL		updateGeometry(LLDrawable *drawable);
 
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index 164f0f0cade67b0c1d7ffbb63c5cc2b1904491e2..ef7b16100361789cd5a138270d44081600ccc993 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -134,7 +134,7 @@ void LLVOSurfacePatch::setPixelAreaAndAngle(LLAgent &agent)
 }
 
 
-void LLVOSurfacePatch::updateTextures(LLAgent &agent)
+void LLVOSurfacePatch::updateTextures()
 {
 }
 
diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h
index aaf4d41fa1e02b733e58d946b26b95cab5028c93..10a5888526ca0a17dbdf44d651a0cd7aed241291 100644
--- a/indra/newview/llvosurfacepatch.h
+++ b/indra/newview/llvosurfacepatch.h
@@ -75,7 +75,7 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 								LLStrider<LLVector2> &texCoords1p,
 								LLStrider<U16> &indicesp);
 
-	/*virtual*/ void updateTextures(LLAgent &agent);
+	/*virtual*/ void updateTextures();
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
 
 	/*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
diff --git a/indra/newview/llvotextbubble.cpp b/indra/newview/llvotextbubble.cpp
index f5094c025ec27a610a2c07b2cfefd00e67604db9..75beab519e0c5406704ced2b2d4ec72a265b9fec 100644
--- a/indra/newview/llvotextbubble.cpp
+++ b/indra/newview/llvotextbubble.cpp
@@ -115,7 +115,7 @@ BOOL LLVOTextBubble::idleUpdate(LLAgent &agent, LLWorld	&world, const F64 &time)
 }
 
 
-void LLVOTextBubble::updateTextures(LLAgent &agent)
+void LLVOTextBubble::updateTextures()
 {
 	// Update the image levels of all textures...
 
diff --git a/indra/newview/llvotextbubble.h b/indra/newview/llvotextbubble.h
index 45d4df2a7e1845f49431e6ed3912ca12c304d447..7f84dbf631e7e625fb2b2527976da7918d4b31ac 100644
--- a/indra/newview/llvotextbubble.h
+++ b/indra/newview/llvotextbubble.h
@@ -44,7 +44,7 @@ class LLVOTextBubble : public LLAlphaObject
 	/*virtual*/ BOOL    isActive() const; // Whether this object needs to do an idleUpdate.
 	/*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
 
-	/*virtual*/ void updateTextures(LLAgent &agent);
+	/*virtual*/ void updateTextures();
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
 	/*virtual*/ BOOL		updateGeometry(LLDrawable *drawable);
 	/*virtual*/ BOOL		updateLOD();
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 615ae13bc2c40c19e1f75225bf470a8ea95e4b2f..ee0c36eb9a309db91070bb0b84da647a55edccd0 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -463,7 +463,7 @@ void LLVOTree::setPixelAreaAndAngle(LLAgent &agent)
 #endif
 }
 
-void LLVOTree::updateTextures(LLAgent &agent)
+void LLVOTree::updateTextures()
 {
 	if (mTreeImagep)
 	{
diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h
index 13817fa111de24a71cec418e4022083eb4fa4f21..feac9e0675e2b1c0a6c9c9ec3e3110e90aa21276 100644
--- a/indra/newview/llvotree.h
+++ b/indra/newview/llvotree.h
@@ -69,7 +69,7 @@ class LLVOTree : public LLViewerObject
 	// Graphical stuff for objects - maybe broken out into render class later?
 	/*virtual*/ void render(LLAgent &agent);
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent);
-	/*virtual*/ void updateTextures(LLAgent &agent);
+	/*virtual*/ void updateTextures();
 
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
 	/*virtual*/ BOOL		updateGeometry(LLDrawable *drawable);
diff --git a/indra/newview/llvotreenew.h b/indra/newview/llvotreenew.h
index 3fec5855efe77732f7543758e51f4c610cfc74ba..426470101dee6cf474cf654ff40b08a9e01b31ac 100644
--- a/indra/newview/llvotreenew.h
+++ b/indra/newview/llvotreenew.h
@@ -156,7 +156,7 @@ class LLVOTreeNew : public LLViewerObject
 	/*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
 
 	/*virtual*/ void render(LLAgent &agent);
-	/*virtual*/ void updateTextures(LLAgent &agent);
+	/*virtual*/ void updateTextures();
 
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
 	/*virtual*/ BOOL		updateGeometry(LLDrawable *drawable);
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 583246c23e801a75b13b3050f4920329b0ba2445..08b342b978142d244a1bebbfc612d36f31407ed3 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -53,12 +53,10 @@
 #include "lldrawpoolbump.h"
 #include "llface.h"
 #include "llspatialpartition.h"
-
-// TEMP HACK ventrella
 #include "llhudmanager.h"
 #include "llflexibleobject.h"
-
 #include "llsky.h"
+#include "lltexturefetch.h"
 #include "llviewercamera.h"
 #include "llviewertexturelist.h"
 #include "llviewerregion.h"
@@ -75,7 +73,6 @@ const S32 MIN_QUIET_FRAMES_COALESCE = 30;
 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
 const F32 FORCE_CULL_AREA = 8.f;
 const F32 MAX_LOD_DISTANCE = 24.f;
-const S32 MAX_SCULPT_REZ = 128;
 
 
 BOOL gAnimateTextures = TRUE;
@@ -100,7 +97,6 @@ LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *re
 	mRelativeXformInvTrans.setIdentity();
 
 	mLOD = MIN_LOD;
-	mSculptLevel = -2;
 	mTextureAnimp = NULL;
 	mVObjRadius = LLVector3(1,1,0.5f).length();
 	mNumFaces = 0;
@@ -499,28 +495,32 @@ BOOL LLVOVolume::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	return TRUE;
 }
 
-void LLVOVolume::updateTextures(LLAgent &agent)
+void LLVOVolume::updateTextures()
 {
 	const F32 TEXTURE_AREA_REFRESH_TIME = 5.f; // seconds
-	if (mDrawable.notNull() && mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
+	if (mTextureUpdateTimer.getElapsedTimeF32() > TEXTURE_AREA_REFRESH_TIME)
 	{
-		if (mDrawable->isVisible())
-		{
-			updateTextures();
-		}
+		updateTextureVirtualSize();		
 	}
 }
 
-void LLVOVolume::updateTextures()
+void LLVOVolume::updateTextureVirtualSize()
 {
 	// Update the pixel area of all faces
 
+	if(mDrawable.isNull() || !mDrawable->isVisible())
+	{
+		return ;
+	}
+
 	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
 	{
 		return;
 	}
-	
-	if (LLViewerTexture::sDontLoadVolumeTextures || mDrawable.isNull()) // || !mDrawable->isVisible())
+
+	static LLCachedControl<bool> dont_load_textures(gSavedSettings,"TextureDisable");
+		
+	if (dont_load_textures || LLAppViewer::getTextureFetch()->mDebugPause) // || !mDrawable->isVisible())
 	{
 		return;
 	}
@@ -537,14 +537,15 @@ void LLVOVolume::updateTextures()
 		LLFace* face = mDrawable->getFace(i);
 		const LLTextureEntry *te = face->getTextureEntry();
 		LLViewerTexture *imagep = face->getTexture();
-		if (!imagep || !te ||
+		if (!imagep || !te ||			
 			face->mExtents[0] == face->mExtents[1])
 		{
 			continue;
 		}
 		
 		F32 vsize;
-		
+		F32 old_size = face->getVirtualSize();
+
 		if (isHUDAttachment())
 		{
 			F32 area = (F32) LLViewerCamera::getInstance()->getScreenPixelArea();
@@ -554,12 +555,10 @@ void LLVOVolume::updateTextures()
 		}
 		else
 		{
-			vsize = getTextureVirtualSize(face);
+			vsize = face->getTextureVirtualSize();
 		}
 
-		mPixelArea = llmax(mPixelArea, face->getPixelArea());
-
-		F32 old_size = face->getVirtualSize();
+		mPixelArea = llmax(mPixelArea, face->getPixelArea());		
 
 		if (face->mTextureMatrix != NULL)
 		{
@@ -571,7 +570,6 @@ void LLVOVolume::updateTextures()
 		}
 		
 		face->setVirtualSize(vsize);
-		imagep->addTextureStats(vsize);
 		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
 		{
 			if (vsize < min_vsize) min_vsize = vsize;
@@ -603,32 +601,44 @@ void LLVOVolume::updateTextures()
 		mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
 		if (mSculptTexture.notNull())
 		{
-			S32 lod = llmin(mLOD, 3);
-			F32 lodf = ((F32)(lod + 1.0f)/4.f); 
-			F32 tex_size = lodf * MAX_SCULPT_REZ;
-			mSculptTexture->addTextureStats(2.f * tex_size * tex_size);
 			mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
 												(S32)LLViewerTexture::BOOST_SCULPTED));
 			mSculptTexture->setForSculpt() ;
-		}
-
-		S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture
-		S32 current_discard = mSculptLevel;
+			
+			if(!mSculptTexture->isCachedRawImageReady())
+			{
+				S32 lod = llmin(mLOD, 3);
+				F32 lodf = ((F32)(lod + 1.0f)/4.f);
+				F32 tex_size = lodf * LLViewerTexture::sMaxSculptRez ;
+				mSculptTexture->addTextureStats(2.f * tex_size * tex_size, FALSE);
+			
+				//if the sculpty very close to the view point, load first
+				{				
+					LLVector3 lookAt = getPositionAgent() - LLViewerCamera::getInstance()->getOrigin();
+					F32 dist = lookAt.normVec() ;
+					F32 cos_angle_to_view_dir = lookAt * LLViewerCamera::getInstance()->getXAxis() ;				
+					mSculptTexture->setAdditionalDecodePriority(0.8f * LLFace::calcImportanceToCamera(cos_angle_to_view_dir, dist)) ;
+				}
+			}
+	
+			S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture
+			S32 current_discard = getVolume() ? getVolume()->getSculptLevel() : -2 ;
 
-		if (texture_discard >= 0 && //texture has some data available
-			(texture_discard < current_discard || //texture has more data than last rebuild
-			current_discard < 0)) //no previous rebuild
-		{
-			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
-			mSculptChanged = TRUE;
-		}
+			if (texture_discard >= 0 && //texture has some data available
+				(texture_discard < current_discard || //texture has more data than last rebuild
+				current_discard < 0)) //no previous rebuild
+			{
+				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
+				mSculptChanged = TRUE;
+			}
 
-		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED))
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED))
 			{
 				setDebugText(llformat("T%d C%d V%d\n%dx%d",
-									  texture_discard, current_discard, getVolume()->getSculptLevel(),
-									  mSculptTexture->getHeight(), mSculptTexture->getWidth()));
+										  texture_discard, current_discard, getVolume()->getSculptLevel(),
+										  mSculptTexture->getHeight(), mSculptTexture->getWidth()));
 			}
+		}
 	}
 
 	if (getLightTextureID().notNull())
@@ -649,10 +659,10 @@ void LLVOVolume::updateTextures()
 	{
 		setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
 	}
-	else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
-	{
-		setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
-	}
+ 	else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY))
+ 	{
+ 		setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
+ 	}
 	else if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_FACE_AREA))
 	{
 		setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
@@ -664,36 +674,6 @@ void LLVOVolume::updateTextures()
 	}
 }
 
-F32 LLVOVolume::getTextureVirtualSize(LLFace* face)
-{
-	//get area of circle around face
-	LLVector3 center = face->getPositionAgent();
-	LLVector3 size = (face->mExtents[1] - face->mExtents[0]) * 0.5f;
-	
-	F32 face_area = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
-
-	face->setPixelArea(face_area);
-
-	if (face_area <= 0)
-	{
-		return 0.f;
-	}
-
-	//get area of circle in texture space
-	LLVector2 tdim = face->mTexExtents[1] - face->mTexExtents[0];
-	F32 texel_area = (tdim * 0.5f).lengthSquared()*3.14159f;
-	if (texel_area <= 0)
-	{
-		// Probably animated, use default
-		texel_area = 1.f;
-	}
-
-	//apply texel area to face area to get accurate ratio
-	face_area /= llclamp(texel_area, 1.f/64.f, 16.f);
-
-	return face_area;
-}
-
 BOOL LLVOVolume::isActive() const
 {
 	return !mStatic || mTextureAnimp || (mVolumeImpl && mVolumeImpl->isActive());
@@ -770,7 +750,6 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 	return mDrawable;
 }
 
-
 BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
 {
 	// Check if we need to change implementations
@@ -825,7 +804,6 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
 				{
 					sculpt();
 				}
-				mSculptLevel = getVolume()->getSculptLevel();
 			}
 		}
 		else
@@ -840,32 +818,22 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
 
 // sculpt replaces generate() for sculpted surfaces
 void LLVOVolume::sculpt()
-{
-	U16 sculpt_height = 0;
-	U16 sculpt_width = 0;
-	S8 sculpt_components = 0;
-	const U8* sculpt_data = NULL;
-
+{	
 	if (mSculptTexture.notNull())
-	{
-		S32 discard_level;
-		S32 desired_discard = 0; // lower discard levels have MUCH less resolution 
-
-		discard_level = desired_discard;
+	{				
+		U16 sculpt_height = 0;
+		U16 sculpt_width = 0;
+		S8 sculpt_components = 0;
+		const U8* sculpt_data = NULL;
+	
+		S32 discard_level = mSculptTexture->getDiscardLevel() ;
+		LLImageRaw* raw_image = mSculptTexture->getCachedRawImage() ;
 		
 		S32 max_discard = mSculptTexture->getMaxDiscardLevel();
 		if (discard_level > max_discard)
 			discard_level = max_discard;    // clamp to the best we can do
 
-		S32 best_discard = mSculptTexture->getDiscardLevel();
-		if (discard_level < best_discard)
-			discard_level = best_discard;   // clamp to what we have
-
-		if (best_discard == -1)
-			discard_level = -1;  // and if we have nothing, set to nothing
-
-		
-		S32 current_discard = getVolume()->getSculptLevel();
+		S32 current_discard = getVolume()->getSculptLevel() ;
 		if(current_discard < -2)
 		{
 			llwarns << "WARNING!!: Current discard of sculpty at " << current_discard 
@@ -886,18 +854,7 @@ void LLVOVolume::sculpt()
 		if (current_discard == discard_level)  // no work to do here
 			return;
 		
-		LLPointer<LLImageRaw> raw_image = new LLImageRaw();
-		BOOL is_valid = mSculptTexture->readBackRaw(discard_level, raw_image, FALSE);
-
-		sculpt_height = raw_image->getHeight();
-		sculpt_width = raw_image->getWidth();
-		sculpt_components = raw_image->getComponents();		
-
-		if(is_valid)
-		{
-			is_valid = mSculptTexture->isValidForSculpt(discard_level, sculpt_width, sculpt_height, sculpt_components) ;
-		}
-		if(!is_valid)
+		if(!raw_image)
 		{
 			sculpt_width = 0;
 			sculpt_height = 0;
@@ -909,10 +866,10 @@ void LLVOVolume::sculpt()
 			}
 		}
 		else
-		{
-			if (raw_image->getDataSize() < sculpt_height * sculpt_width * sculpt_components)
-				llerrs << "Sculpt: image data size = " << raw_image->getDataSize()
-					   << " < " << sculpt_height << " x " << sculpt_width << " x " <<sculpt_components << llendl;
+		{					
+			sculpt_height = raw_image->getHeight();
+			sculpt_width = raw_image->getWidth();
+			sculpt_components = raw_image->getComponents();		
 					   
 			sculpt_data = raw_image->getData();
 
@@ -948,12 +905,6 @@ BOOL LLVOVolume::calcLOD()
 		return FALSE;
 	}
 
-	//update face texture sizes on lod calculation
-	//if (mDrawable->isVisible())
-	//{
-	//	updateTextures();
-	//}
-
 	S32 cur_detail = 0;
 	
 	F32 radius = getVolume()->mLODScaleBias.scaledVec(getScale()).length();
@@ -2608,7 +2559,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 		if (face == -1)
 		{
 			start_face = 0;
-			end_face = volume->getNumFaces();
+			end_face = volume->getNumVolumeFaces();
 		}
 		else
 		{
@@ -2623,8 +2574,8 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 			
 			if (face_hit >= 0 && mDrawable->getNumFaces() > face_hit)
 			{
-				LLFace* face = mDrawable->getFace(face_hit);
-			
+				LLFace* face = mDrawable->getFace(face_hit);				
+
 				if (pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n)))
 				{
 					v_end = p;
@@ -2870,7 +2821,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 		LLVOVolume* vobj = drawablep->getVOVolume();
 		llassert_always(vobj);
-		vobj->updateTextures();
+		vobj->updateTextureVirtualSize();
 		vobj->preRebuild();
 
 		drawablep->clearState(LLDrawable::HAS_ALPHA);
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 250c3ed9170a6045a13e8de959e70c2df91db54a..6d90de2a6f9ee54469377e0eef86ad94116f4e8d 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -139,7 +139,7 @@ class LLVOVolume : public LLViewerObject
 
 				
 				BOOL	getVolumeChanged() const				{ return mVolumeChanged; }
-				F32		getTextureVirtualSize(LLFace* face);
+				
 	/*virtual*/ F32  	getRadius() const						{ return mVObjRadius; };
 				const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const;
 
@@ -187,8 +187,8 @@ class LLVOVolume : public LLViewerObject
 	/*virtual*/ void	updateFaceSize(S32 idx);
 	/*virtual*/ BOOL	updateLOD();
 				void	updateRadius();
-	/*virtual*/ void	updateTextures(LLAgent &agent);
-				void	updateTextures();
+	/*virtual*/ void	updateTextures();
+				void	updateTextureVirtualSize();
 
 				void	updateFaceFlags();
 				void	regenFaces();
@@ -267,7 +267,6 @@ class LLVOVolume : public LLViewerObject
 	LLFrameTimer mTextureUpdateTimer;
 	S32			mLOD;
 	BOOL		mLODChanged;
-	S32         mSculptLevel;
 	BOOL		mSculptChanged;
 	F32			mSpotLightPriority;
 	LLMatrix4	mRelativeXform;
diff --git a/indra/newview/llvowater.cpp b/indra/newview/llvowater.cpp
index 0c967f9020c4580cebaa026f399e74a5e484976a..e5ff62746e387a352414452dd244b775b66bb002 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -100,7 +100,7 @@ void LLVOWater::setPixelAreaAndAngle(LLAgent &agent)
 
 
 // virtual
-void LLVOWater::updateTextures(LLAgent &agent)
+void LLVOWater::updateTextures()
 {
 }
 
diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h
index 28a5633c58ecf8b14321df75965cead93d1ff026..3cc031e589a63d530096d941d0dda2ef7a42439c 100644
--- a/indra/newview/llvowater.h
+++ b/indra/newview/llvowater.h
@@ -68,7 +68,7 @@ class LLVOWater : public LLStaticViewerObject
 	/*virtual*/ BOOL        updateGeometry(LLDrawable *drawable);
 	/*virtual*/ void		updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
 
-	/*virtual*/ void updateTextures(LLAgent &agent);
+	/*virtual*/ void updateTextures();
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
 
 	virtual U32 getPartitionType() const;
diff --git a/indra/newview/llwearablelist.cpp b/indra/newview/llwearablelist.cpp
index da62223aac203da585296d1f9e1623d225df771b..9bde85dcaf8629984c6d552d20878815e3fe3a15 100644
--- a/indra/newview/llwearablelist.cpp
+++ b/indra/newview/llwearablelist.cpp
@@ -69,6 +69,11 @@ struct LLWearableArrivedData
 // LLWearableList
 
 LLWearableList::~LLWearableList()
+{
+	llassert_always(mList.empty()) ;
+}
+
+void LLWearableList::cleanup() 
 {
 	for_each(mList.begin(), mList.end(), DeletePairedPointer());
 	mList.clear();
diff --git a/indra/newview/llwearablelist.h b/indra/newview/llwearablelist.h
index e5155c66a4b47ae9f5d1b4e4ecd6ae0c16891e74..cf1a9bddff62db7c13717a5f21605736b5db6737 100644
--- a/indra/newview/llwearablelist.h
+++ b/indra/newview/llwearablelist.h
@@ -44,6 +44,7 @@ class LLWearableList : public LLSingleton<LLWearableList>
 public:
 	LLWearableList()	{}
 	~LLWearableList();
+	void cleanup() ;
 
 	S32					getLength() const { return mList.size(); }
 
diff --git a/indra/newview/llworldmap.cpp b/indra/newview/llworldmap.cpp
index 829d631473b3c43b0426ad6ada28ff7e383f4615..5e83ab8c3c12e0b16153d24316a5869140d93d52 100644
--- a/indra/newview/llworldmap.cpp
+++ b/indra/newview/llworldmap.cpp
@@ -34,58 +34,82 @@
 
 #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 "lltracker.h"
 #include "llviewertexturelist.h"
-#include "llviewerregion.h"
-#include "llregionflags.h"
 #include "lltrans.h"
 
-const F32 REQUEST_ITEMS_TIMER =  10.f * 60.f; // 10 minutes
+// 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
+//---------------------------------------------------------------------------
 
-// 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
 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)
+{
+}
+
+void LLSimInfo::setLandForSaleImage (LLUUID image_id) 
 {
+	mMapImageID = image_id;
+
+	// Fetch the image
+	if (mMapImageID.notNull())
+	{
+		mOverlayImage = LLViewerTextureManager::getFetchedTexture(mMapImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+		mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP);
+	}
+	else
+	{
+		mOverlayImage = NULL;
+	}
 }
 
+LLPointer<LLViewerFetchedTexture> LLSimInfo::getLandForSaleImage () 
+{
+	if (mOverlayImage.isNull() && mMapImageID.notNull())
+	{
+		// Fetch the image if it hasn't been done yet (unlikely but...)
+		mOverlayImage = LLViewerTextureManager::getFetchedTexture(mMapImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+		mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP);
+	}
+	if (!mOverlayImage.isNull())
+	{
+		// Boost the fetch level when we try to access that image
+		mOverlayImage->setBoostLevel(LLViewerTexture::BOOST_MAP);
+	}
+	return mOverlayImage;
+}
 
-LLVector3d LLSimInfo::getGlobalPos(LLVector3 local_pos) const
+LLVector3d LLSimInfo::getGlobalPos(const LLVector3& local_pos) const
 {
 	LLVector3d pos = from_region_handle(mHandle);
 	pos.mdV[VX] += local_pos.mV[VX];
@@ -94,128 +118,184 @@ LLVector3d LLSimInfo::getGlobalPos(LLVector3 local_pos) const
 	return pos;
 }
 
+LLVector3d LLSimInfo::getGlobalOrigin() const
+{
+	return from_region_handle(mHandle);
+}
 LLVector3 LLSimInfo::getLocalPos(LLVector3d global_pos) const
 {
 	LLVector3d sim_origin = from_region_handle(mHandle);
 	return LLVector3(global_pos - sim_origin);
 }
 
+void LLSimInfo::clearImage()
+{
+	if (!mOverlayImage.isNull())
+	{
+		mOverlayImage->setBoostLevel(0);
+		mOverlayImage = NULL;
+	}
+}
 
-
-//---------------------------------------------------------------------------
-// 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)
-{
-	for (S32 map=0; map<MAP_SIM_IMAGE_TYPES; ++map)
+void LLSimInfo::dropImagePriority()
+{
+	if (!mOverlayImage.isNull())
 	{
-		mMapLoaded[map] = FALSE;
-		mMapBlockLoaded[map] = new BOOL[MAP_BLOCK_RES*MAP_BLOCK_RES];
-		for (S32 idx=0; idx<MAP_BLOCK_RES*MAP_BLOCK_RES; ++idx)
-		{
-			mMapBlockLoaded[map][idx] = FALSE;
-		}
+		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;
+	}
+}
 
-LLWorldMap::~LLWorldMap()
+// Get the total agents count
+const S32 LLSimInfo::getAgentCount() const
 {
-	reset();
-	for (S32 map=0; map<MAP_SIM_IMAGE_TYPES; ++map)
+	S32 total_agent_count = 0;
+	for (LLSimInfo::item_info_list_t::const_iterator it = mAgentLocations.begin(); it != mAgentLocations.end(); ++it)
 	{
-		delete[] mMapBlockLoaded[map];
+		total_agent_count += it->getCount();
 	}
+	return total_agent_count;
 }
 
+bool LLSimInfo::isName(const std::string& name) const
+{
+	return (LLStringUtil::compareInsensitive(name, mName) == 0);
+}
 
-void LLWorldMap::reset()
+void LLSimInfo::dump() const
 {
-	for_each(mSimInfoMap.begin(), mSimInfoMap.end(), DeletePairedPointer());
-	mSimInfoMap.clear();
+	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();
 
-	for (S32 m=0; m<MAP_SIM_IMAGE_TYPES; ++m)
+	// 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())
 	{
-		mMapLoaded[m] = FALSE;
+		mAgentLocations.erase(mAgentLocations.begin(), lastiter);
 	}
 
+	// Now append the new location
+	mAgentLocations.push_back(item); 
+}
+
+//---------------------------------------------------------------------------
+// World Map
+//---------------------------------------------------------------------------
+
+LLWorldMap::LLWorldMap() :
+	mIsTrackingLocation( false ),
+	mIsTrackingFound( false ),
+	mIsInvalidLocation( false ),
+	mIsTrackingDoubleClick( false ),
+	mIsTrackingCommit( false ),
+	mTrackingLocation( 0, 0, 0 ),
+	mFirstRequest(true)
+{
+	//LL_INFOS("World Map") << "Creating the World Map -> LLWorldMap::LLWorldMap()" << LL_ENDL;
+	mMapBlockLoaded = new bool[MAP_BLOCK_RES*MAP_BLOCK_RES];
 	clearSimFlags();
-	
-	eraseItems();
+}
 
-	mMinX = U32_MAX;
-	mMaxX = U32_MIN;
 
-	mMinY = U32_MAX;
-	mMaxY = U32_MIN;
+LLWorldMap::~LLWorldMap()
+{
+	//LL_INFOS("World Map") << "Destroying the World Map -> LLWorldMap::~LLWorldMap()" << LL_ENDL;
+	reset();
+	delete[] mMapBlockLoaded;
+}
 
-	delete [] mNeighborMap;
-	mNeighborMap = NULL;
-	delete [] mTelehubCoverageMap;
-	mTelehubCoverageMap = NULL;
 
-	mNeighborMapWidth = 0;
-	mNeighborMapHeight = 0;
+void LLWorldMap::reset()
+{
+	clearItems(true);		// Clear the items lists
+	clearImageRefs();		// Clear the world mipmap and the land for sale tiles
+	clearSimFlags();		// Clear the block info flags array 
 
-	for (S32 i=0; i<MAP_SIM_IMAGE_TYPES; i++)
-	{
-		mMapLayers[i].clear();
-	}
+	// Finally, clear the region map itself
+	for_each(mSimInfoMap.begin(), mSimInfoMap.end(), DeletePairedPointer());
+	mSimInfoMap.clear();
 }
 
-void LLWorldMap::eraseItems()
+// Returns true if the items have been cleared
+bool LLWorldMap::clearItems(bool force)
 {
-	if (mRequestTimer.getElapsedTimeF32() > 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)
-		{
-			info->mCurrentImage->setBoostLevel(0);
-			info->mCurrentImage = NULL;
-		}
-		if (info->mOverlayImage)
+		sim_info = it->second;
+		if (sim_info)
 		{
-			info->mOverlayImage->setBoostLevel(0);
-			info->mOverlayImage = NULL;
+			sim_info->clearImage();
 		}
 	}
 }
@@ -223,15 +303,25 @@ void LLWorldMap::clearImageRefs()
 // Doesn't clear the already-loaded sim infos, just re-requests them
 void LLWorldMap::clearSimFlags()
 {
-	for (S32 map=0; map<MAP_SIM_IMAGE_TYPES; ++map)
+	for (S32 idx=0; idx<MAP_BLOCK_RES*MAP_BLOCK_RES; ++idx)
 	{
-		for (S32 idx=0; idx<MAP_BLOCK_RES*MAP_BLOCK_RES; ++idx)
-		{
-			mMapBlockLoaded[map][idx] = FALSE;
-		}
+		mMapBlockLoaded[idx] = false;
 	}
 }
 
+LLSimInfo* LLWorldMap::createSimInfoFromHandle(const U64 handle)
+{
+	LLSimInfo* sim_info = new LLSimInfo(handle);
+	mSimInfoMap[handle] = sim_info;
+	return sim_info;
+}
+
+void LLWorldMap::equalizeBoostLevels()
+{
+	mWorldMipmap.equalizeBoostLevels();
+	return;
+}
+
 LLSimInfo* LLWorldMap::simInfoFromPosGlobal(const LLVector3d& pos_global)
 {
 	U64 handle = to_region_handle(pos_global);
@@ -243,11 +333,7 @@ LLSimInfo* LLWorldMap::simInfoFromHandle(const U64 handle)
 	sim_info_map_t::iterator it = mSimInfoMap.find(handle);
 	if (it != mSimInfoMap.end())
 	{
-		LLSimInfo* sim_info = (*it).second;
-		if (sim_info)
-		{
-			return sim_info;
-		}
+		return it->second;
 	}
 	return NULL;
 }
@@ -258,762 +344,272 @@ 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);
+
+		// 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))
+		{
+			if (siminfo->isDown())
+			{
+				// We were tracking this location, but it's no available
+				LLWorldMap::getInstance()->setTrackingInvalid();
+			}
+			else
+			{
+				// We were tracking this location, and it does exist and is available
+				LLWorldMap::getInstance()->setTrackingValid();
+			}
+		}
+		// return insert region success
+		return true;
 	}
 }
 
-// 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**)
+// 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)
 {
-	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 adjust = FALSE;
-	for (S32 block=0; block<num_blocks; ++block)
-	{
-		LLWorldMapLayer new_layer;
-		new_layer.LayerDefined = TRUE;
-		msg->getUUIDFast(_PREHASH_LayerData, _PREHASH_ImageID, new_layer.LayerImageID, block);
-		new_layer.LayerImage = LLViewerTextureManager::getFetchedTexture(new_layer.LayerImageID, MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-
-		gGL.getTexUnit(0)->bind(new_layer.LayerImage);
-		new_layer.LayerImage->setAddressMode(LLTexUnit::TAM_CLAMP);
-		
-		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);
-
-		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();
-}
+	// Create an item record for the received object
+	LLItemInfo new_item((F32)x_world, (F32)y_world, name, uuid);
 
-// public static
-void LLWorldMap::processMapBlockReply(LLMessageSystem* msg, void**)
-{
-	U32 agent_flags;
-	msg->getU32Fast(_PREHASH_AgentData, _PREHASH_Flags, agent_flags);
+	// 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);
 
-	if ((S32)agent_flags < 0 || agent_flags >= MAP_SIM_IMAGE_TYPES)
+	// 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)
 	{
-		llwarns << "Invalid map image type returned! " << agent_flags << llendl;
-		return;
+		siminfo = LLWorldMap::getInstance()->createSimInfoFromHandle(handle);
 	}
 
-	S32 num_blocks = msg->getNumberOfBlocksFast(_PREHASH_Data);
-
-	bool found_null_sim = false;
-
-	BOOL adjust = FALSE;
-	for (S32 block=0; block<num_blocks; ++block)
+	//LL_INFOS("World Map") << "Process item : type = " << type << LL_ENDL;
+	switch (type)
 	{
-		U16 x_regions;
-		U16 y_regions;
-		std::string name;
-		U8 accesscode;
-		U32 region_flags;
-		U8 water_height;
-		U8 agents;
-		LLUUID image_id;
-		msg->getU16Fast(_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)
-		{
-			// 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)
-			{
-				// We were tracking this location, but it doesn't exist
-				LLWorldMap::getInstance()->mInvalidLocation = TRUE;
-			}
-
-			found_null_sim = true;
-		}
-		else
+		case MAP_ITEM_TELEHUB: // telehubs
 		{
-			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; image<MAP_SIM_IMAGE_TYPES; ++image)
-				{
-					siminfo->mMapImageID[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
-			siminfo->mCurrentImage = LLViewerTextureManager::getFetchedTexture(siminfo->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-			siminfo->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP);
-#endif
+			/* 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 = LLViewerTextureManager::getFetchedTexture(siminfo->mMapImageID[2], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-#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))
+			std::string timeStr = "["+ LLTrans::getString ("TimeHour")+"]:["
+					                   +LLTrans::getString ("TimeMin")+"] ["
+									   +LLTrans::getString ("TimeAMPM")+"]";
+			LLSD substitution;
+			substitution["datetime"] = (S32) extra;
+			LLStringUtil::format (timeStr, substitution);				
+			new_item.setTooltip(timeStr);
+
+			// 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);
 			}
-		}
-	}
-
-	if(adjust) gFloaterWorldMap->adjustZoomSliderBounds();
-	gFloaterWorldMap->updateSims(found_null_sim);
-}
-
-// public static
-void LLWorldMap::processMapItemReply(LLMessageSystem* msg, void**)
-{
-	U32 type;
-	msg->getU32Fast(_PREHASH_RequestData, _PREHASH_ItemType, type);
-
-	S32 num_blocks = msg->getNumberOfBlocks("Data");
-
-	for (S32 block=0; block<num_blocks; ++block)
-	{
-		U32 X, Y;
-		std::string name;
-		S32 extra, extra2;
-		LLUUID uuid;
-		msg->getU32Fast(_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);
-
-		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);
-
-		switch (type)
-		{
-			case MAP_ITEM_TELEHUB: // telehubs
+			else if (type == MAP_ITEM_MATURE_EVENT)
 			{
-				// 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;
+				siminfo->insertMatureEvent(new_item);
 			}
-			case MAP_ITEM_PG_EVENT: // events
-			case MAP_ITEM_MATURE_EVENT:
-			case MAP_ITEM_ADULT_EVENT:
+			else if (type == MAP_ITEM_ADULT_EVENT)
 			{
-				std::string timeStr = "["+ LLTrans::getString ("TimeHour")+"]:["
-					                   +LLTrans::getString ("TimeMin")+"] ["
-									   +LLTrans::getString ("TimeAMPM")+"]";
-				LLSD substitution;
-				substitution["datetime"] = (S32) extra;
-				LLStringUtil::format (timeStr, substitution);
-				new_item.mToolTip = timeStr;
-
-				// 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;
+				siminfo->insertAdultEvent(new_item);
 			}
-			case MAP_ITEM_LAND_FOR_SALE: // land for sale
-			case MAP_ITEM_LAND_FOR_SALE_ADULT: // adult land for sale 
+			break;
+		}
+		case MAP_ITEM_LAND_FOR_SALE:		// land for sale
+		case MAP_ITEM_LAND_FOR_SALE_ADULT:	// adult land for sale 
+		{
+			std::string tooltip = llformat("%d sq. m. L$%d", extra, extra2);
+			new_item.setTooltip(tooltip);
+			if (type == MAP_ITEM_LAND_FOR_SALE)
 			{
-				new_item.mToolTip = llformat("%d sq. m. L$%d", new_item.mExtra, 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;
+				siminfo->insertLandForSale(new_item);
 			}
-			case MAP_ITEM_CLASSIFIED: // classifieds
+			else if (type == MAP_ITEM_LAND_FOR_SALE_ADULT)
 			{
-				//DEPRECATED: no longer used
-				break;
+				siminfo->insertLandForSaleAdult(new_item);
 			}
-			case MAP_ITEM_AGENT_LOCATIONS: // agent locations
+			break;
+		}
+		case MAP_ITEM_CLASSIFIED: // classifieds
+		{
+			//DEPRECATED: no longer used
+			break;
+		}
+		case MAP_ITEM_AGENT_LOCATIONS: // agent locations
+		{
+// 				LL_INFOS("World Map") << "New Location " << new_item.mName << LL_ENDL;
+			if (extra > 0)
 			{
-				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;
+				new_item.setCount(extra);
+				siminfo->insertAgentLocation(new_item);
 			}
-			default:
-				break;
-		};
-	}
-}
-
-void LLWorldMap::dump()
-{
-	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)
-		{
-			llinfos << "image discard " << (S32)info->mCurrentImage->getDiscardLevel()
-					<< " fullwidth " << info->mCurrentImage->getFullWidth()
-					<< " fullheight " << info->mCurrentImage->getFullHeight()
-					<< " maxvirt " << info->mCurrentImage->getMaxVirtualSize()
-					//<< " maxdisc " << (S32)info->mCurrentImage->getMaxDiscardLevel()
-					<< llendl;
+			break;
 		}
+		default:
+			break;
 	}
+	return true;
 }
 
-
-BOOL LLWorldMap::extendAABB(U32 min_x, U32 min_y, U32 max_x, U32 max_y)
+bool LLWorldMap::isTrackingInRectangle(F64 x0, F64 y0, F64 x1, F64 y1)
 {
-	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;
+	if (!mIsTrackingLocation)
+		return false;
+	return ((mTrackingLocation[0] >= x0) && (mTrackingLocation[0] < x1) && (mTrackingLocation[1] >= y0) && (mTrackingLocation[1] < y1));
 }
 
-
-U32 LLWorldMap::getWorldWidth() const
+// Drop priority of all images being fetched by the map
+void LLWorldMap::dropImagePriorities()
 {
-	return mMaxX - mMinX;
-}
-
-
-U32 LLWorldMap::getWorldHeight() const
-{
-	return mMaxY - mMinY;
-}
-
-BOOL LLWorldMap::coveredByTelehub(LLSimInfo* infop)
-{
-	/*if (!mTelehubCoverageMap)
+	// Drop the download of tiles priority to nil
+	mWorldMipmap.dropBoostLevels();
+	// Same for the "land for sale" tiles per region
+	for (sim_info_map_t::iterator it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
 	{
-		return FALSE;
+		LLSimInfo* info = it->second;
+		info->dropImagePriority();
 	}
-	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()
+// 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)
 {
-	/*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));
+	// 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;
 
-	// leave 1 sim border
-	S32 min_x = (mMinX / REGION_WIDTH_UNITS) - 1;
-	S32 min_y = (mMinY / REGION_WIDTH_UNITS) - 1;
-
- 	std::map<U64, LLSimInfo*>::const_iterator it;
-	for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
+	// Load the region info those blocks
+	for (S32 block_x = llmax(x0, 0); block_x <= llmin(x1, MAP_BLOCK_RES-1); ++block_x)
 	{
-		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])
+		for (S32 block_y = llmax(y0, 0); block_y <= llmin(y1, MAP_BLOCK_RES-1); ++block_y)
 		{
-			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++)
+			S32 offset = block_x | (block_y * MAP_BLOCK_RES);
+			if (!mMapBlockLoaded[offset])
 			{
-				memset(&mTelehubCoverageMap[x_start + y_index * mNeighborMapWidth], 0xff, sizeof(U8) * x_span);
+ 				//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;
 			}
 		}
 	}
+}
 
-	for (it = mSimInfoMap.begin(); it != mSimInfoMap.end(); ++it)
+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);
-		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];
-	}*/
+		LLSimInfo* info = it->second;
+		if (info)
+		{
+			info->dump();
+		}
+	}
 }
+
diff --git a/indra/newview/llworldmap.h b/indra/newview/llworldmap.h
index 366de8f07191e347589ffd53a943d849f4944f11..7e37727b866613564435806a0e0650a7201cf034 100644
--- a/indra/newview/llworldmap.h
+++ b/indra/newview/llworldmap.h
@@ -33,203 +33,243 @@
 #ifndef LL_LLWORLDMAP_H
 #define LL_LLWORLDMAP_H
 
-#include <map>
-#include <string>
-#include <vector>
+#include "llworldmipmap.h"
 #include <boost/function.hpp>
 
-#include "v3math.h"
 #include "v3dmath.h"
-#include "llframetimer.h"
-#include "llmapimagetype.h"
 #include "lluuid.h"
 #include "llpointer.h"
 #include "llsingleton.h"
+#include "llviewerregion.h"
 #include "llviewertexture.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);
-
-	std::string mName;
-	std::string mToolTip;
-	LLVector3d	mPosGlobal;
-	LLUUID		mID;
-	BOOL		mSelected;
-	S32			mExtra;
-	S32			mExtra2;
-	U64			mRegionHandle;
-};
+	LLItemInfo(F32 global_x, F32 global_y, const std::string& name, LLUUID id);
+
+	// 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
 
-// Map layers, see indra_constants.h
-// 0 - Prim
-// 1 - Terrain Only
-// 2 - Overlay: Land For Sale
+	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
+};
+
+// 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;
 	LLVector3 getLocalPos(LLVector3d global_pos) const;
 
-public:
-	U64 mHandle;
-	std::string mName;
-
-	F64 mAgentsUpdateTime;
-	BOOL mShowAgentLocations;	// are agents visible?
+	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
 
-	U8 mAccess;
-	U32 mRegionFlags;
-	F32 mWaterHeight;
+	// 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; }
 
-	F32 mAlpha;
+	// Accessors
+	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); }
 
-	// Image ID for the current overlay mode.
-	LLUUID mMapImageID[MAP_SIM_IMAGE_TYPES];
+	const S32 getAgentCount() const;				// Compute the total agents count
+	LLPointer<LLViewerFetchedTexture> getLandForSaleImage();	// Get the overlay image, fetch it if necessary
 
-	// Hold a reference to the currently displayed image.
-	LLPointer<LLViewerFetchedTexture> mCurrentImage;
-	LLPointer<LLViewerFetchedTexture> mOverlayImage;
-};
+	bool isName(const std::string& name) const;
+	bool isDown() { return (mAccess == SIM_ACCESS_DOWN); }
+	bool isPG() { return (mAccess <= SIM_ACCESS_PG); }
 
-#define MAP_BLOCK_RES 256
+	// Debug only
+	void dump() const;	// Print the region info to the standard output
 
-struct LLWorldMapLayer
-{
-	BOOL LayerDefined;
-	LLPointer<LLViewerFetchedTexture> LayerImage;
-	LLUUID LayerImageID;
-	LLRect LayerExtents;
+	// Items lists handling
+	typedef std::vector<LLItemInfo> 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; }
 
-	LLWorldMapLayer() : LayerDefined(FALSE) { }
+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<LLViewerFetchedTexture> 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<LLWorldMap>
 {
 public:
-	typedef boost::function<void(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)>
-		url_callback_t;
-
 	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<U64, LLSimInfo*> 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);
-
-	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);
-
-	static void processMapLayerReply(LLMessageSystem*, void**);
-	static void processMapBlockReply(LLMessageSystem*, void**);
-	static void processMapItemReply(LLMessageSystem*, void**);
-
-	void dump();
-
-	// 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<U64, LLSimInfo*> sim_info_map_t;
-	sim_info_map_t mSimInfoMap;
+	// Debug only
+	void dump();	// Print the world info to the standard output
 
-	BOOL			mIsTrackingUnknownLocation, mInvalidLocation, mIsTrackingDoubleClick, mIsTrackingCommit;
-	LLVector3d		mUnknownLocation;
+	// Track handling
+	void cancelTracking() { mIsTrackingLocation = false; mIsTrackingFound = false; mIsInvalidLocation = false; mIsTrackingDoubleClick = false; mIsTrackingCommit = false; }
 
-	bool mRequestLandForSale;
+	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; }
 
-	typedef std::vector<LLItemInfo> 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<U64,S32> mNumAgents;
-
-	typedef std::map<U64, item_info_list_t> agent_list_map_t;
-	agent_list_map_t mAgentLocationsMap;
-	
-	std::vector<LLWorldMapLayer>	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;
+	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);
+
+	LLVector3d getTrackedPositionGlobal() const { return mTrackingLocation; }
+
+	// World Mipmap delegation: currently used when drawing the mipmap
+	void	equalizeBoostLevels();
+	LLPointer<LLViewerFetchedTexture> getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load = true) { return mWorldMipmap.getObjectsTile(grid_x, grid_y, level, load); }
 
 private:
-	LLTimer	mRequestTimer;
-
-	// search for named region for url processing
-	std::string mSLURLRegionName;
-	U64 mSLURLRegionHandle;
-	std::string mSLURL;
-	url_callback_t mSLURLCallback;
-	bool mSLURLTeleport;
+	bool clearItems(bool force = false);	// Clears the item lists
+	void clearSimFlags();					// Clears the block flags indicating that we've already requested region infos
+
+	// Create a region record corresponding to the handle, insert it in the region map and returns a pointer
+	LLSimInfo* createSimInfoFromHandle(const U64 handle);
+
+	// 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 0000000000000000000000000000000000000000..6a074d9697fc70402087c999fca59cfae8b12864
--- /dev/null
+++ b/indra/newview/llworldmapmessage.cpp
@@ -0,0 +1,261 @@
+/** 
+ * @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"
+
+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)
+	{
+		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; block<num_blocks; ++block)
+	{
+		U16 x_regions;
+		U16 y_regions;
+		std::string name;
+		U8 accesscode;
+		U32 region_flags;
+//		U8 water_height;
+//		U8 agents;
+		LLUUID image_id;
+		msg->getU16Fast(_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);
+			}
+		}
+	}
+	// 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; block<num_blocks; ++block)
+	{
+		U32 X, Y;
+		std::string name;
+		S32 extra, extra2;
+		LLUUID uuid;
+		msg->getU32Fast(_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 0000000000000000000000000000000000000000..2c8fedcb10e292bac1b8369405f2a7d321b015c6
--- /dev/null
+++ b/indra/newview/llworldmapmessage.h
@@ -0,0 +1,83 @@
+/** 
+ * @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<LLWorldMapMessage>
+{
+public:
+	typedef boost::function<void(U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)>
+		url_callback_t;
+
+	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 3aad5c7378b7ee322cf56e8fdbe177366a0d5514..ede9ddb837b4056f5d769e40ed479626ce4ae40e 100644
--- a/indra/newview/llworldmapview.cpp
+++ b/indra/newview/llworldmapview.cpp
@@ -46,7 +46,6 @@
 #include "llagent.h"
 #include "llcallingcard.h"
 #include "llviewercontrol.h"
-#include "llcylinder.h"
 #include "llfloatermap.h"
 #include "llfloaterworldmap.h"
 #include "llfocusmgr.h"
@@ -57,25 +56,29 @@
 #include "llviewercamera.h"
 #include "llviewertexture.h"
 #include "llviewertexturelist.h"
-#include "llviewermenu.h"
-#include "llviewerparceloverlay.h"
 #include "llviewerregion.h"
 #include "llviewerwindow.h"
-#include "llworldmap.h"
-#include "lltexturefetch.h"
-#include "llappviewer.h"				// Only for constants!
 #include "lltrans.h"
 
 #include "llglheaders.h"
 
+// Basically a C++ implementation of the OCEAN_COLOR defined in mapstitcher.py 
+// Please ensure consistency between those 2 files (TODO: would be better to get that color from an asset source...)
+// # Constants
+// OCEAN_COLOR = "#1D475F"
+const F32 OCEAN_RED   = (F32)(0x1D)/255.f;
+const F32 OCEAN_GREEN = (F32)(0x47)/255.f;
+const F32 OCEAN_BLUE  = (F32)(0x5F)/255.f;
+
 const F32 GODLY_TELEPORT_HEIGHT = 200.f;
 const S32 SCROLL_HINT_WIDTH = 65;
 const F32 BIG_DOT_RADIUS = 5.f;
 BOOL LLWorldMapView::sHandledLastClick = FALSE;
 
-LLUIImagePtr LLWorldMapView::sAvatarYouSmallImage = NULL;
 LLUIImagePtr LLWorldMapView::sAvatarSmallImage = NULL;
-LLUIImagePtr LLWorldMapView::sAvatarLargeImage = NULL;
+LLUIImagePtr LLWorldMapView::sAvatarYouImage = NULL;
+LLUIImagePtr LLWorldMapView::sAvatarYouLargeImage = NULL;
+LLUIImagePtr LLWorldMapView::sAvatarLevelImage = NULL;
 LLUIImagePtr LLWorldMapView::sAvatarAboveImage = NULL;
 LLUIImagePtr LLWorldMapView::sAvatarBelowImage = NULL;
 
@@ -93,35 +96,34 @@ LLUIImagePtr LLWorldMapView::sClassifiedsImage = NULL;
 LLUIImagePtr LLWorldMapView::sForSaleImage = NULL;
 LLUIImagePtr LLWorldMapView::sForSaleAdultImage = NULL;
 
-F32 LLWorldMapView::sThresholdA = 48.f;
-F32 LLWorldMapView::sThresholdB = 96.f;
 F32 LLWorldMapView::sPanX = 0.f;
 F32 LLWorldMapView::sPanY = 0.f;
 F32 LLWorldMapView::sTargetPanX = 0.f;
 F32 LLWorldMapView::sTargetPanY = 0.f;
 S32 LLWorldMapView::sTrackingArrowX = 0;
 S32 LLWorldMapView::sTrackingArrowY = 0;
-F32 LLWorldMapView::sPixelsPerMeter = 1.f;
-F32 CONE_SIZE = 0.6f;
+bool LLWorldMapView::sVisibleTilesLoaded = false;
+F32 LLWorldMapView::sMapScale = 128.f;
 
 std::map<std::string,std::string> LLWorldMapView::sStringsMap;
 
-#define SIM_NULL_MAP_SCALE 1 // width in pixels, where we start drawing "null" sims
-#define SIM_MAP_AGENT_SCALE 2 // width in pixels, where we start drawing agents
-#define SIM_MAP_SCALE 1 // width in pixels, where we start drawing sim tiles
-
-// Updates for agent locations.
-#define AGENTS_UPDATE_TIME 60.0 // in seconds
+// Fetch and draw info thresholds
+const F32 DRAW_TEXT_THRESHOLD = 96.f;		// Don't draw text under that resolution value (res = width region in meters)
+const S32 DRAW_SIMINFO_THRESHOLD = 3;		// Max level for which we load or display sim level information (level in LLWorldMipmap sense)
+const S32 DRAW_LANDFORSALE_THRESHOLD = 2;	// Max level for which we load or display land for sale picture data (level in LLWorldMipmap sense)
 
+// When on, draw an outline for each mipmap tile gotten from S3
+#define DEBUG_DRAW_TILE 0
 
 
 void LLWorldMapView::initClass()
 {
-	sAvatarYouSmallImage =	LLUI::getUIImage("map_avatar_you_8.tga");
-	sAvatarSmallImage = 	LLUI::getUIImage("map_avatar_8.tga");
-	sAvatarLargeImage = 	LLUI::getUIImage("map_avatar_16.tga");
-	sAvatarAboveImage = 	LLUI::getUIImage("map_avatar_above_8.tga");
-	sAvatarBelowImage = 	LLUI::getUIImage("map_avatar_below_8.tga");
+	sAvatarSmallImage =		LLUI::getUIImage("map_avatar_8.tga");
+	sAvatarYouImage =		LLUI::getUIImage("map_avatar_16.tga");
+	sAvatarYouLargeImage =	LLUI::getUIImage("map_avatar_you_32.tga");
+	sAvatarLevelImage =		LLUI::getUIImage("map_avatar_32.tga");
+	sAvatarAboveImage =		LLUI::getUIImage("map_avatar_above_32.tga");
+	sAvatarBelowImage =		LLUI::getUIImage("map_avatar_below_32.tga");
 
 	sHomeImage =			LLUI::getUIImage("map_home.tga");
 	sTelehubImage = 		LLUI::getUIImage("map_telehub.tga");
@@ -145,9 +147,10 @@ void LLWorldMapView::initClass()
 // static
 void LLWorldMapView::cleanupClass()
 {
-	sAvatarYouSmallImage = NULL;
 	sAvatarSmallImage = NULL;
-	sAvatarLargeImage = NULL;
+	sAvatarYouImage = NULL;
+	sAvatarYouLargeImage = NULL;
+	sAvatarLevelImage = NULL;
 	sAvatarAboveImage = NULL;
 	sAvatarBelowImage = NULL;
 
@@ -167,7 +170,7 @@ void LLWorldMapView::cleanupClass()
 
 LLWorldMapView::LLWorldMapView()
 :	LLPanel(),
-	mBackgroundColor( LLColor4( 4.f/255.f, 4.f/255.f, 75.f/255.f, 1.f ) ),
+	mBackgroundColor( LLColor4( OCEAN_RED, OCEAN_GREEN, OCEAN_BLUE, 1.f ) ),
 	mItemPicked(FALSE),
 	mPanning( FALSE ),
 	mMouseDownPanX( 0 ),
@@ -176,7 +179,8 @@ LLWorldMapView::LLWorldMapView()
 	mMouseDownY( 0 ),
 	mSelectIDStart(0)
 {
-	sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS;
+	//LL_INFOS("World Map") << "Creating the Map -> LLWorldMapView::LLWorldMapView()" << LL_ENDL;
+
 	clearLastClick();
 }
 
@@ -215,6 +219,7 @@ BOOL LLWorldMapView::postBuild()
 
 LLWorldMapView::~LLWorldMapView()
 {
+	//LL_INFOS("World Map") << "Destroying the map -> LLWorldMapView::~LLWorldMapView()" << LL_ENDL;
 	cleanupTextures();
 }
 
@@ -228,14 +233,14 @@ void LLWorldMapView::cleanupTextures()
 // static
 void LLWorldMapView::setScale( F32 scale )
 {
-	if (scale != gMapScale)
+	if (scale != sMapScale)
 	{
-		F32 old_scale = gMapScale;
+		F32 old_scale = sMapScale;
 
-		gMapScale = scale;
-		if (gMapScale == 0.f)
+		sMapScale = scale;
+		if (sMapScale <= 0.f)
 		{
-			gMapScale = 0.1f;
+			sMapScale = 0.1f;
 		}
 
 		F32 ratio = (scale / old_scale);
@@ -243,8 +248,7 @@ void LLWorldMapView::setScale( F32 scale )
 		sPanY *= ratio;
 		sTargetPanX = sPanX;
 		sTargetPanY = sPanY;
-
-		sPixelsPerMeter = gMapScale / REGION_WIDTH_METERS;
+		sVisibleTilesLoaded = false;
 	}
 }
 
@@ -256,6 +260,7 @@ void LLWorldMapView::translatePan( S32 delta_x, S32 delta_y )
 	sPanY += delta_y;
 	sTargetPanX = sPanX;
 	sTargetPanY = sPanY;
+	sVisibleTilesLoaded = false;
 }
 
 
@@ -269,18 +274,22 @@ void LLWorldMapView::setPan( S32 x, S32 y, BOOL snap )
 		sPanX = sTargetPanX;
 		sPanY = sTargetPanY;
 	}
+	sVisibleTilesLoaded = false;
 }
 
+bool LLWorldMapView::showRegionInfo()
+{
+	return (LLWorldMipmap::scaleToLevel(sMapScale) <= DRAW_SIMINFO_THRESHOLD ? true : false);
+}
 
 ///////////////////////////////////////////////////////////////////////////////////
 // HELPERS
 
 BOOL is_agent_in_region(LLViewerRegion* region, LLSimInfo* info)
 {
-	return ((region && info) && (info->mName == region->getName()));
+	return (region && info && info->isName(region->getName()));
 }
 
-
 ///////////////////////////////////////////////////////////////////////////////////
 
 void LLWorldMapView::draw()
@@ -292,7 +301,7 @@ void LLWorldMapView::draw()
 	F64 current_time = LLTimer::getElapsedSeconds();
 
 	mVisibleRegions.clear();
-	
+
 	// animate pan if necessary
 	sPanX = lerp(sPanX, sTargetPanX, LLCriticalDamp::getInterpolant(0.1f));
 	sPanY = lerp(sPanY, sTargetPanY, LLCriticalDamp::getInterpolant(0.1f));
@@ -303,10 +312,12 @@ void LLWorldMapView::draw()
 	const F32 half_height = F32(height) / 2.0f;
 	LLVector3d camera_global = gAgent.getCameraPositionGlobal();
 
+	S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
+
 	LLLocalClipRect clip(getLocalRect());
 	{
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-	
+
 		glMatrixMode(GL_MODELVIEW);
 
 		// Clear the background alpha to 0
@@ -319,307 +330,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_idx<LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap].size(); ++layer_idx)
-	{
-		if (!LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap][layer_idx].LayerDefined)
-		{
-			continue;
-		}
-		LLWorldMapLayer *layer = &LLWorldMap::getInstance()->mMapLayers[LLWorldMap::getInstance()->mCurrentMap][layer_idx];
-		LLViewerFetchedTexture *current_image = layer->LayerImage;
-
-		if (current_image->isMissingAsset())
-		{
-			continue; // better to draw nothing than the missing asset image
-		}
-		
-		LLVector3d origin_global((F64)layer->LayerExtents.mLeft * REGION_WIDTH_METERS, (F64)layer->LayerExtents.mBottom * REGION_WIDTH_METERS, 0.f);
-
-		// Find x and y position relative to camera's center.
-		LLVector3d rel_region_pos = origin_global - camera_global;
-		F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale;
-		F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale;
-
-		F32 pix_width = gMapScale*(layer->LayerExtents.getWidth() + 1);
-		F32 pix_height = gMapScale*(layer->LayerExtents.getHeight() + 1);
-
-		// When the view isn't panned, 0,0 = center of rectangle
-		F32 bottom =	sPanY + half_height + relative_y;
-		F32 left =		sPanX + half_width + relative_x;
-		F32 top =		bottom + pix_height;
-		F32 right =		left + pix_width;
-		F32 pixel_area = pix_width*pix_height;
-		// discard layers that are outside the rectangle
-		// and discard small layers
-		if (top < 0.f ||
-			bottom > height ||
-			right < 0.f ||
-			left > width ||
-			(pixel_area < 4*4))
-		{
-			current_image->setBoostLevel(0);
-			continue;
-		}
-		
-		current_image->setBoostLevel(LLViewerTexture::BOOST_MAP_LAYER);
-		current_image->setKnownDrawSize(llround(pix_width * LLUI::sGLScaleFactor.mV[VX]), llround(pix_height * LLUI::sGLScaleFactor.mV[VY]));
-		
-		if (!current_image->hasGLTexture())
-		{
-			continue; // better to draw nothing than the default image
-		}
-
-// 		LLTextureView::addDebugImage(current_image);
-		
-		// Draw using the texture.  If we don't clamp we get artifact at
-		// the edge.
-		gGL.getTexUnit(0)->bind(current_image);
-
-		// Draw map image into RGB
-		//gGL.blendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-		gGL.flush();
-		gGL.setColorMask(true, false);
-		gGL.color4f(1.f, 1.f, 1.f, layer_alpha);
-
-		gGL.begin(LLRender::QUADS);
-			gGL.texCoord2f(0.0f, 1.0f);
-			gGL.vertex3f(left, top, -1.0f);
-			gGL.texCoord2f(0.0f, 0.0f);
-			gGL.vertex3f(left, bottom, -1.0f);
-			gGL.texCoord2f(1.0f, 0.0f);
-			gGL.vertex3f(right, bottom, -1.0f);
-			gGL.texCoord2f(1.0f, 1.0f);
-			gGL.vertex3f(right, top, -1.0f);
-		gGL.end();
-
-		// draw an alpha of 1 where the sims are visible
-		gGL.flush();
-		gGL.setColorMask(false, true);
-		gGL.color4f(1.f, 1.f, 1.f, 1.f);
-
-		gGL.begin(LLRender::QUADS);
-			gGL.texCoord2f(0.0f, 1.0f);
-			gGL.vertex2f(left, top);
-			gGL.texCoord2f(0.0f, 0.0f);
-			gGL.vertex2f(left, bottom);
-			gGL.texCoord2f(1.0f, 0.0f);
-			gGL.vertex2f(right, bottom);
-			gGL.texCoord2f(1.0f, 1.0f);
-			gGL.vertex2f(right, top);
-		gGL.end();
-	}
 
+#if 1
+	// Draw the image tiles
+	drawMipmap(width, height);
 	gGL.flush();
+
 	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	gGL.setColorMask(true, true);
 
-	// there used to be an #if 1 here, but it was uncommented; perhaps marking a block of code?
-	F32 sim_alpha = 1.f;
-
-	// Draw one image per region, centered on the camera position.
-	const S32 MAX_SIMULTANEOUS_TEX = 100;
-	const S32 MAX_REQUEST_PER_TICK = 5;
-	const S32 MIN_REQUEST_PER_TICK = 1;
-	S32 textures_requested_this_tick = 0;
-
-	for (LLWorldMap::sim_info_map_t::iterator it = LLWorldMap::getInstance()->mSimInfoMap.begin();
-		 it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it)
+	// Draw per sim overlayed information (names, mature, offline...)
+	for (LLWorldMap::sim_info_map_t::const_iterator it = LLWorldMap::getInstance()->getRegionMap().begin();
+		 it != LLWorldMap::getInstance()->getRegionMap().end(); ++it)
 	{
-		U64 handle = (*it).first;
-		LLSimInfo* info = (*it).second;
+		U64 handle = it->first;
+		LLSimInfo* info = it->second;
 
-		LLViewerFetchedTexture* simimage = info->mCurrentImage;
-		LLViewerFetchedTexture* overlayimage = info->mOverlayImage;
-
-		if (gMapScale < SIM_MAP_SCALE)
-		{
-			if (simimage != NULL) simimage->setBoostLevel(0);
-			if (overlayimage != NULL) overlayimage->setBoostLevel(0);
-			continue;
-		}
-		
 		LLVector3d origin_global = from_region_handle(handle);
-		LLVector3d camera_global = gAgent.getCameraPositionGlobal();
 
 		// Find x and y position relative to camera's center.
 		LLVector3d rel_region_pos = origin_global - camera_global;
-		F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * gMapScale;
-		F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * gMapScale;
+		F32 relative_x = (rel_region_pos.mdV[0] / REGION_WIDTH_METERS) * sMapScale;
+		F32 relative_y = (rel_region_pos.mdV[1] / REGION_WIDTH_METERS) * sMapScale;
 
+		// Coordinates of the sim in pixels in the UI panel
 		// When the view isn't panned, 0,0 = center of rectangle
-		F32 bottom =	sPanY + half_height + relative_y;
-		F32 left =		sPanX + half_width + relative_x;
-		F32 top =		bottom + gMapScale ;
-		F32 right =		left + gMapScale ;
-
-		// Switch to world map texture (if available for this region) if either:
-		// 1. Tiles are zoomed out small enough, or
-		// 2. Sim's texture has not been loaded yet
-		F32 map_scale_cutoff = SIM_MAP_SCALE;
-		if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) > 0)
-		{
-			map_scale_cutoff = SIM_NULL_MAP_SCALE;
-		}
-
-		info->mShowAgentLocations = (gMapScale >= SIM_MAP_AGENT_SCALE);
-
-		bool sim_visible =
-			(gMapScale >= map_scale_cutoff) &&
-			(simimage != NULL) &&
-			(simimage->hasGLTexture());
-
-		if (sim_visible)
-		{
-			// Fade in
-			if (info->mAlpha < 0.0f)
-				info->mAlpha = 1.f; // don't fade initially
-			else
-				info->mAlpha = lerp(info->mAlpha, 1.f, LLCriticalDamp::getInterpolant(0.15f));
-		}
-		else
-		{
-			// Fade out
-			if (info->mAlpha < 0.0f)
-				info->mAlpha = 0.f; // don't fade initially
-			else
-				info->mAlpha = lerp(info->mAlpha, 0.f, LLCriticalDamp::getInterpolant(0.15f));
-		}
-
-		// discard regions that are outside the rectangle
-		// and discard small regions
-		if (top < 0.f ||
-			bottom > height ||
-			right < 0.f ||
-			left > width )
+		F32 bottom =    sPanY + half_height + relative_y;
+		F32 left =      sPanX + half_width + relative_x;
+		F32 top =       bottom + sMapScale ;
+		F32 right =     left + sMapScale ;
+
+		// Discard if region is outside the screen rectangle (not visible on screen)
+		if ((top < 0.f)   || (bottom > height) ||
+			(right < 0.f) || (left > width)       )
 		{
-			if (simimage != NULL) simimage->setBoostLevel(0);
-			if (overlayimage != NULL) overlayimage->setBoostLevel(0);
+			// Drop the "land for sale" fetching priority since it's outside the view rectangle
+			info->dropImagePriority();
 			continue;
 		}
 
-		if (info->mCurrentImage.isNull())
-		{
-			if ((textures_requested_this_tick < MIN_REQUEST_PER_TICK) ||
-				((LLAppViewer::getTextureFetch()->getNumRequests() < MAX_SIMULTANEOUS_TEX) &&
-				 (textures_requested_this_tick < MAX_REQUEST_PER_TICK)))
-			{
-				textures_requested_this_tick++;
-				info->mCurrentImage = LLViewerTextureManager::getFetchedTexture(info->mMapImageID[LLWorldMap::getInstance()->mCurrentMap], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-                info->mCurrentImage->setAddressMode(LLTexUnit::TAM_CLAMP);
-				simimage = info->mCurrentImage;
-				gGL.getTexUnit(0)->bind(simimage);
-			}
-		}
-		if (info->mOverlayImage.isNull() && info->mMapImageID[2].notNull())
-		{
-			if ((textures_requested_this_tick < MIN_REQUEST_PER_TICK) ||
-				((LLAppViewer::getTextureFetch()->getNumRequests() < MAX_SIMULTANEOUS_TEX) &&
-				 (textures_requested_this_tick < MAX_REQUEST_PER_TICK)))
-			{
-				textures_requested_this_tick++;
-				info->mOverlayImage = LLViewerTextureManager::getFetchedTexture(info->mMapImageID[2], MIPMAP_TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-				info->mOverlayImage->setAddressMode(LLTexUnit::TAM_CLAMP);
-				overlayimage = info->mOverlayImage;
-				gGL.getTexUnit(0)->bind(overlayimage);
-			}
-		}
-
+		// This list is used by other methods to know which regions are indeed displayed on screen
 		mVisibleRegions.push_back(handle);
-		// See if the agents need updating
-		if (current_time - info->mAgentsUpdateTime > AGENTS_UPDATE_TIME)
-		{
-			LLWorldMap::getInstance()->sendItemRequest(MAP_ITEM_AGENT_LOCATIONS, info->mHandle);
-			info->mAgentsUpdateTime = current_time;
-		}
-		
-		// Bias the priority escalation for images nearer
-		LLVector3d center_global = origin_global;
-		center_global.mdV[VX] += 128.0;
-		center_global.mdV[VY] += 128.0;
-
-		S32 draw_size = llround(gMapScale);
-		if (simimage != NULL)
-		{
-			simimage->setBoostLevel(LLViewerTexture::BOOST_MAP);
-			simimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY]));
-		}
 
-		if (overlayimage != NULL)
+		// Update the agent count for that region if we're not too zoomed out already
+		if (level <= DRAW_SIMINFO_THRESHOLD)
 		{
-			overlayimage->setBoostLevel(LLViewerTexture::BOOST_MAP);
-			overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY]));
-		}
-			
-// 		LLTextureView::addDebugImage(simimage);
-
-		if (sim_visible && info->mAlpha > 0.001f)
-		{
-			// Draw using the texture.  If we don't clamp we get artifact at
-			// the edge.
-			LLGLSUIDefault gls_ui;
-			if (simimage != NULL)
-				gGL.getTexUnit(0)->bind(simimage);
-
-			gGL.setSceneBlendType(LLRender::BT_ALPHA);
-			F32 alpha = sim_alpha * info->mAlpha;
-			gGL.color4f(1.f, 1.0f, 1.0f, alpha);
-
-			gGL.begin(LLRender::QUADS);
-				gGL.texCoord2f(0.f, 1.f);
-				gGL.vertex3f(left, top, 0.f);
-				gGL.texCoord2f(0.f, 0.f);
-				gGL.vertex3f(left, bottom, 0.f);
-				gGL.texCoord2f(1.f, 0.f);
-				gGL.vertex3f(right, bottom, 0.f);
-				gGL.texCoord2f(1.f, 1.f);
-				gGL.vertex3f(right, top, 0.f);
-			gGL.end();
-
-			if (gSavedSettings.getBOOL("MapShowLandForSale") && overlayimage && overlayimage->hasGLTexture())
-			{
-				gGL.getTexUnit(0)->bind(overlayimage);
-				gGL.color4f(1.f, 1.f, 1.f, alpha);
-				gGL.begin(LLRender::QUADS);
-					gGL.texCoord2f(0.f, 1.f);
-					gGL.vertex3f(left, top, -0.5f);
-					gGL.texCoord2f(0.f, 0.f);
-					gGL.vertex3f(left, bottom, -0.5f);
-					gGL.texCoord2f(1.f, 0.f);
-					gGL.vertex3f(right, bottom, -0.5f);
-					gGL.texCoord2f(1.f, 1.f);
-					gGL.vertex3f(right, top, -0.5f);
-				gGL.end();
-			}
-			
-			if ((info->mRegionFlags & REGION_FLAGS_NULL_LAYER) == 0)
-			{
-				// draw an alpha of 1 where the sims are visible (except NULL sims)
-				gGL.flush();
-				gGL.setSceneBlendType(LLRender::BT_REPLACE);
-				gGL.setColorMask(false, true);
-				gGL.color4f(1.f, 1.f, 1.f, 1.f);
-
-				gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-				gGL.begin(LLRender::QUADS);
-					gGL.vertex2f(left, top);
-					gGL.vertex2f(left, bottom);
-					gGL.vertex2f(right, bottom);
-					gGL.vertex2f(right, top);
-				gGL.end();
-
-				gGL.flush();
-				gGL.setColorMask(true, true);
-			}
+			info->updateAgentCount(current_time);
 		}
 
-		if (info->mAccess == SIM_ACCESS_DOWN)
+		if (info->isDown())
 		{
 			// Draw a transparent red square over down sims
 			gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_SOURCE_ALPHA);
@@ -633,18 +395,15 @@ void LLWorldMapView::draw()
 				gGL.vertex2f(right, top);
 			gGL.end();
 		}
-
-		// As part of the AO project, we no longer want to draw access indicators;
-		// it's too complicated to get all the rules straight and will only 
+        // As part of the AO project, we no longer want to draw access indicators;
+		// it's too complicated to get all the rules straight and will only
 		// cause confusion.
 		/**********************
-		 // If this is mature, and you are not, draw a line across it
-		if (info->mAccess != SIM_ACCESS_DOWN
-			&& info->mAccess > SIM_ACCESS_PG
-			&& gAgent.isTeen())
+        else if (!info->isPG() && gAgent.isTeen())
 		{
+			// If this is a mature region, and you are not, draw a line across it
 			gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO);
-			
+
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 			gGL.color3f(1.f, 0.f, 0.f);
 			gGL.begin(LLRender::LINES);
@@ -655,68 +414,67 @@ void LLWorldMapView::draw()
 			gGL.end();
 		}
 		 **********************/
-
-		// Draw the region name in the lower left corner
-		LLFontGL* font = LLFontGL::getFontSansSerifSmall();
-
-		std::string mesg;
-		if (gMapScale < sThresholdA)
+		else if (gSavedSettings.getBOOL("MapShowLandForSale") && (level <= DRAW_LANDFORSALE_THRESHOLD))
 		{
+			// Draw the overlay image "Land for Sale / Land for Auction"
+			LLViewerFetchedTexture* overlayimage = info->getLandForSaleImage();
+			if (overlayimage)
+			{
+				// Inform the fetch mechanism of the size we need
+				S32 draw_size = llround(sMapScale);
+				overlayimage->setKnownDrawSize(llround(draw_size * LLUI::sGLScaleFactor.mV[VX]), llround(draw_size * LLUI::sGLScaleFactor.mV[VY]));
+				// Draw something whenever we have enough info
+				if (overlayimage->hasGLTexture())
+				{
+					gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO);
+					gGL.getTexUnit(0)->bind(overlayimage);
+					gGL.color4f(1.f, 1.f, 1.f, 1.f);
+					gGL.begin(LLRender::QUADS);
+						gGL.texCoord2f(0.f, 1.f);
+						gGL.vertex3f(left, top, -0.5f);
+						gGL.texCoord2f(0.f, 0.f);
+						gGL.vertex3f(left, bottom, -0.5f);
+						gGL.texCoord2f(1.f, 0.f);
+						gGL.vertex3f(right, bottom, -0.5f);
+						gGL.texCoord2f(1.f, 1.f);
+						gGL.vertex3f(right, top, -0.5f);
+					gGL.end();
+				}
+			}
 		}
-		else if (gMapScale < sThresholdB)
+		else
 		{
-			//	mesg = llformat( info->mAgents);
+			// If we're not displaying the "land for sale", drop its fetching priority
+			info->dropImagePriority();
 		}
-		else
+
+		// Draw the region name in the lower left corner
+		if (sMapScale >= DRAW_TEXT_THRESHOLD)
 		{
-			//mesg = llformat("%d / %s (%s)",
-			//			info->mAgents,
-			//			info->mName.c_str(),
-			//			LLViewerRegion::accessToShortString(info->mAccess).c_str() );
-			if (info->mAccess == SIM_ACCESS_DOWN)
+			LLFontGL* font = LLFontGL::getFontSansSerifSmall();
+			std::string mesg;
+			if (info->isDown())
 			{
-				mesg = llformat( "%s (%s)", info->mName.c_str(), sStringsMap["offline"].c_str());
+				mesg = llformat( "%s (%s)", info->getName().c_str(), sStringsMap["offline"].c_str());
 			}
 			else
 			{
-				mesg = info->mName;
+				mesg = info->getName();
 			}
-		}
-
-		if (!mesg.empty())
-		{
-			font->renderUTF8(
-				mesg, 0,
-				llfloor(left + 3), 
-				llfloor(bottom + 2),
-				LLColor4::white,
-				LLFontGL::LEFT,
-				LLFontGL::BASELINE,
-				LLFontGL::NORMAL,
-				LLFontGL::DROP_SHADOW);
-			
-			// If map texture is still loading,
-			// display "Loading" placeholder text.
-			if ((simimage != NULL) &&
-				simimage->getDiscardLevel() != 1 &&
-				simimage->getDiscardLevel() != 0)
+			if (!mesg.empty())
 			{
 				font->renderUTF8(
-					sStringsMap["loading"], 0,
-					llfloor(left + 18), 
-					llfloor(top - 25),
+					mesg, 0,
+					llfloor(left + 3), llfloor(bottom + 2),
 					LLColor4::white,
-					LLFontGL::LEFT,
-					LLFontGL::BASELINE,
-					LLFontGL::NORMAL,
-					LLFontGL::DROP_SHADOW);			
+					LLFontGL::LEFT, LLFontGL::BASELINE, LLFontGL::DROP_SHADOW);
 			}
 		}
 	}
-	// #endif used to be here
+	#endif
 
 
-	// there used to be an #if 1 here, but it was uncommented; perhaps marking a block of code?
+	#if 1
 	// Draw background rectangle
 	LLGLSUIDefault gls_ui;
 	{
@@ -726,69 +484,49 @@ void LLWorldMapView::draw()
 		gGL.color4fv( mBackgroundColor.mV );
 		gl_rect_2d(0, height, width, 0);
 	}
-	
+
 	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
-	// Infohubs
-	if (gSavedSettings.getBOOL("MapShowInfohubs"))   //(gMapScale >= sThresholdB)
+	// Draw item infos if we're not zoomed out too much and there's something to draw
+	if ((level <= DRAW_SIMINFO_THRESHOLD) && (gSavedSettings.getBOOL("MapShowInfohubs") || 
+											  gSavedSettings.getBOOL("MapShowTelehubs") ||
+											  gSavedSettings.getBOOL("MapShowLandForSale") || 
+											  gSavedSettings.getBOOL("MapShowEvents") || 
+											  gSavedSettings.getBOOL("ShowMatureEvents") ||
+											  gSavedSettings.getBOOL("ShowAdultEvents")))
 	{
-		drawGenericItems(LLWorldMap::getInstance()->mInfohubs, sInfohubImage);
+		drawItems();
 	}
 
-	// Telehubs
-	if (gSavedSettings.getBOOL("MapShowTelehubs"))   //(gMapScale >= sThresholdB)
-	{
-		drawGenericItems(LLWorldMap::getInstance()->mTelehubs, sTelehubImage);
-	}
-
-	// Home Sweet Home
+	// Draw the Home location (always)
 	LLVector3d home;
 	if (gAgent.getHomePosGlobal(&home))
 	{
 		drawImage(home, sHomeImage);
 	}
 
-	if (gSavedSettings.getBOOL("MapShowLandForSale"))
-	{
-		drawGenericItems(LLWorldMap::getInstance()->mLandForSale, sForSaleImage);
-		// for 1.23, we're showing normal land and adult land in the same UI; you don't
-		// get a choice about which ones you want. If you're currently asking for adult
-		// content and land you'll get the adult land.
-		if (gAgent.canAccessAdult())
-		{
-			drawGenericItems(LLWorldMap::getInstance()->mLandForSaleAdult, sForSaleAdultImage);
-		}
-	}
-	
-	if (gSavedSettings.getBOOL("MapShowEvents") ||
-		gSavedSettings.getBOOL("ShowMatureEvents") ||
-		gSavedSettings.getBOOL("ShowAdultEvents") )
-	{
-		drawEvents();
-	}
-
-	// Now draw your avatar after all that other stuff.
+	// Draw the current agent after all that other stuff.
 	LLVector3d pos_global = gAgent.getPositionGlobal();
-	drawImage(pos_global, sAvatarLargeImage);
+	drawImage(pos_global, sAvatarYouImage);
 
 	LLVector3 pos_map = globalPosToView(pos_global);
 	if (!pointInView(llround(pos_map.mV[VX]), llround(pos_map.mV[VY])))
 	{
-		drawTracking(pos_global, 
-			lerp(LLColor4::yellow, LLColor4::orange, 0.4f), 
-			TRUE, 
-			"You are here", 
-			"", 
-			llround(LLFontGL::getFontSansSerifSmall()->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking
+		drawTracking(pos_global,
+					 lerp(LLColor4::yellow, LLColor4::orange, 0.4f),
+					 TRUE,
+					 "You are here",
+					 "",
+					 llround(LLFontGL::getFontSansSerifSmall()->getLineHeight())); // offset vertically by one line, to avoid overlap with target tracking
 	}
 
-	// Show your viewing angle
+	// Draw the current agent viewing angle
 	drawFrustum();
 
 	// Draw icons for the avatars in each region.
-	// Drawn after your avatar so you can see nearby people.
-	if (gSavedSettings.getBOOL("MapShowPeople"))
+	// Drawn this after the current agent avatar so one can see nearby people
+	if (gSavedSettings.getBOOL("MapShowPeople") && (level <= DRAW_SIMINFO_THRESHOLD))
 	{
 		drawAgents();
 	}
@@ -798,9 +536,9 @@ void LLWorldMapView::draw()
 	if ( LLTracker::TRACKING_AVATAR == tracking_status )
 	{
 		drawTracking( LLAvatarTracker::instance().getGlobalPos(), map_track_color, TRUE, LLTracker::getLabel(), "" );
-	} 
-	else if ( LLTracker::TRACKING_LANDMARK == tracking_status 
-			 || LLTracker::TRACKING_LOCATION == tracking_status )
+	}
+	else if ( LLTracker::TRACKING_LANDMARK == tracking_status
+			  || LLTracker::TRACKING_LOCATION == tracking_status )
 	{
 		// While fetching landmarks, will have 0,0,0 location for a while,
 		// so don't draw. JC
@@ -810,31 +548,33 @@ void LLWorldMapView::draw()
 			drawTracking( pos_global, map_track_color, TRUE, LLTracker::getLabel(), LLTracker::getToolTip() );
 		}
 	}
-	else if (LLWorldMap::getInstance()->mIsTrackingUnknownLocation)
+	else if (LLWorldMap::getInstance()->isTracking())
 	{
-		if (LLWorldMap::getInstance()->mInvalidLocation)
+		if (LLWorldMap::getInstance()->isTrackingInvalidLocation())
 		{
-			// We know this location to be invalid
+			// We know this location to be invalid, draw a blue circle
 			LLColor4 loading_color(0.0, 0.5, 1.0, 1.0);
-			drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, getString("InvalidLocation"), "");
+			drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, getString("InvalidLocation"), "");
 		}
 		else
 		{
+			// We don't know yet what that location is, draw a throbing blue circle
 			double value = fmod(current_time, 2);
 			value = 0.5 + 0.5*cos(value * 3.14159f);
 			LLColor4 loading_color(0.0, F32(value/2), F32(value), 1.0);
-			drawTracking( LLWorldMap::getInstance()->mUnknownLocation, loading_color, TRUE, getString("Loading"), "");
+			drawTracking( LLWorldMap::getInstance()->getTrackedPositionGlobal(), loading_color, TRUE, getString("Loading"), "");
 		}
 	}
-	// #endif used to be here
-	
+	#endif
+
 	// turn off the scissor
 	LLGLDisable no_scissor(GL_SCISSOR_TEST);
-	
+
 	updateDirections();
 
 	LLView::draw();
 
+	// Get sim info for all sims in view
 	updateVisibleBlocks();
 } // end draw()
 
@@ -845,36 +585,182 @@ void LLWorldMapView::setVisible(BOOL visible)
 	LLPanel::setVisible(visible);
 	if (!visible)
 	{
-		for (S32 map = 0; map < MAP_SIM_IMAGE_TYPES; map++)
+		// Drop the download of tiles and images priority to nil if we hide the map
+		LLWorldMap::getInstance()->dropImagePriorities();
+	}
+}
+
+void LLWorldMapView::drawMipmap(S32 width, S32 height)
+{
+	// Compute the level of the mipmap to use for the current scale level
+	S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
+	// Set the tile boost level so that unused tiles get to 0
+	LLWorldMap::getInstance()->equalizeBoostLevels();
+
+	// Render whatever we already have loaded if we haven't the current level
+	// complete and use it as a background (scaled up or scaled down)
+	if (!sVisibleTilesLoaded)
+	{
+		// Note: the (load = false) parameter avoids missing tiles to be fetched (i.e. we render what we have, no more)
+		// Check all the lower res levels and render them in reverse order (worse to best)
+		// We need to traverse all the levels as the user can zoom in very fast
+		for (S32 l = LLWorldMipmap::MAP_LEVELS; l > level; l--)
 		{
-			for (U32 layer_idx=0; layer_idx<LLWorldMap::getInstance()->mMapLayers[map].size(); ++layer_idx)
-			{
-				if (LLWorldMap::getInstance()->mMapLayers[map][layer_idx].LayerDefined)
-				{
-					LLWorldMapLayer *layer = &LLWorldMap::getInstance()->mMapLayers[map][layer_idx];
-					layer->LayerImage->setBoostLevel(0);
-				}
-			}
+			drawMipmapLevel(width, height, l, false);
+		}
+		// 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);
 		}
-		for (LLWorldMap::sim_info_map_t::iterator it = LLWorldMap::getInstance()->mSimInfoMap.begin();
-			 it != LLWorldMap::getInstance()->mSimInfoMap.end(); ++it)
+	}
+	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)
 		{
-			LLSimInfo* info = (*it).second;
-			if (info->mCurrentImage.notNull())
+			// Compute the world coordinates of the current point
+			LLVector3d pos_global(index_x, index_y, pos_SW[VZ]);
+			// Convert to the mipmap level coordinates for that point (i.e. which tile to we hit)
+			LLWorldMipmap::globalToMipmap(pos_global[VX], pos_global[VY], level, &grid_x, &grid_y);
+			// Get the tile. Note: NULL means that the image does not exist (so it's considered "complete" as far as fetching is concerned)
+			LLPointer<LLViewerFetchedTexture> simimage = LLWorldMap::getInstance()->getObjectsTile(grid_x, grid_y, level, load);
+			if (simimage)
 			{
-				info->mCurrentImage->setBoostLevel(0);
+				// Checks that the image has a valid texture
+				if (simimage->hasGLTexture())
+				{
+					// Increment the number of completly fetched tiles
+					completed_tiles++;
+
+					// Convert those coordinates (SW corner of the mipmap tile) into world (meters) coordinates
+					pos_global[VX] = grid_x * REGION_WIDTH_METERS;
+					pos_global[VY] = grid_y * REGION_WIDTH_METERS;
+					// Now to screen coordinates for SW corner of that tile
+					LLVector3 pos_screen = globalPosToView (pos_global);
+					F32 left   = pos_screen[VX];
+					F32 bottom = pos_screen[VY];
+					// Compute the NE corner coordinates of the tile now
+					pos_global[VX] += tile_width;
+					pos_global[VY] += tile_width;
+					pos_screen = globalPosToView (pos_global);
+					F32 right  = pos_screen[VX];
+					F32 top    = pos_screen[VY];
+
+					// Draw the tile
+					LLGLSUIDefault gls_ui;
+					gGL.getTexUnit(0)->bind(simimage.get());
+					simimage->setAddressMode(LLTexUnit::TAM_CLAMP);
+
+					gGL.setSceneBlendType(LLRender::BT_ALPHA);
+					gGL.color4f(1.f, 1.0f, 1.0f, 1.0f);
+
+					gGL.begin(LLRender::QUADS);
+						gGL.texCoord2f(0.f, 1.f);
+						gGL.vertex3f(left, top, 0.f);
+						gGL.texCoord2f(0.f, 0.f);
+						gGL.vertex3f(left, bottom, 0.f);
+						gGL.texCoord2f(1.f, 0.f);
+						gGL.vertex3f(right, bottom, 0.f);
+						gGL.texCoord2f(1.f, 1.f);
+						gGL.vertex3f(right, top, 0.f);
+					gGL.end();
+#if DEBUG_DRAW_TILE
+					drawTileOutline(level, top, left, bottom, right);
+#endif // DEBUG_DRAW_TILE
+				}
+				//else
+				//{
+				//	Waiting for a tile -> the level is not complete
+				//	LL_INFOS("World Map") << "Unfetched tile. level = " << level << LL_ENDL;
+				//}
 			}
-			if (info->mOverlayImage.notNull())
+			else
 			{
-				info->mOverlayImage->setBoostLevel(0);
+				// Unexistent tiles are counted as "completed"
+				completed_tiles++;
 			}
+			// Increment the number of tiles in that level / screen
+			total_tiles++;
 		}
 	}
+	return (completed_tiles == total_tiles);
+}
+
+// Draw lines (rectangle outline and cross) to visualize the position of the tile
+// Used for debug only
+void LLWorldMapView::drawTileOutline(S32 level, F32 top, F32 left, F32 bottom, F32 right)
+{
+	gGL.blendFunc(LLRender::BF_DEST_ALPHA, LLRender::BF_ZERO);
+	
+	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+	if (level == 1)
+		gGL.color3f(1.f, 0.f, 0.f);		// red
+	else if (level == 2)
+		gGL.color3f(0.f, 1.f, 0.f);		// green
+	else if (level == 3)
+		gGL.color3f(0.f, 0.f, 1.f);		// blue
+	else if (level == 4)
+		gGL.color3f(1.f, 1.f, 0.f);		// yellow
+	else if (level == 5)
+		gGL.color3f(1.f, 0.f, 1.f);		// magenta
+	else if (level == 6)
+		gGL.color3f(0.f, 1.f, 1.f);		// cyan
+	else if (level == 7)
+		gGL.color3f(1.f, 1.f, 1.f);		// white
+	else
+		gGL.color3f(0.f, 0.f, 0.f);		// black
+	gGL.begin(LLRender::LINE_STRIP);
+		gGL.vertex2f(left, top);
+		gGL.vertex2f(right, bottom);
+		gGL.vertex2f(left, bottom);
+		gGL.vertex2f(right, top);
+		gGL.vertex2f(left, top);
+		gGL.vertex2f(left, bottom);
+		gGL.vertex2f(right, bottom);
+		gGL.vertex2f(right, top);
+	gGL.end();
 }
 
-void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items, LLUIImagePtr image)
+void LLWorldMapView::drawGenericItems(const LLSimInfo::item_info_list_t& items, LLUIImagePtr image)
 {
-	LLWorldMap::item_info_list_t::const_iterator e;
+	LLSimInfo::item_info_list_t::const_iterator e;
 	for (e = items.begin(); e != items.end(); ++e)
 	{
 		drawGenericItem(*e, image);
@@ -883,7 +769,7 @@ void LLWorldMapView::drawGenericItems(const LLWorldMap::item_info_list_t& items,
 
 void LLWorldMapView::drawGenericItem(const LLItemInfo& item, LLUIImagePtr image)
 {
-	drawImage(item.mPosGlobal, image);
+	drawImage(item.getGlobalPosition(), image);
 }
 
 
@@ -906,137 +792,91 @@ void LLWorldMapView::drawImageStack(const LLVector3d& global_pos, LLUIImagePtr i
 	}
 }
 
-
-void LLWorldMapView::drawAgents()
+void LLWorldMapView::drawItems()
 {
-	static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white);
-	static LLUIColor map_avatar_friend_color = LLUIColorTable::instance().getColor("MapAvatarFriendColor", LLColor4::white);
-	
-	F32 agents_scale = (gMapScale * 0.9f) / 256.f;
+	bool mature_enabled = gAgent.canAccessMature();
+	bool adult_enabled = gAgent.canAccessAdult();
+
+    BOOL show_mature = mature_enabled && gSavedSettings.getBOOL("ShowMatureEvents");
+	BOOL show_adult = adult_enabled && gSavedSettings.getBOOL("ShowAdultEvents");
 
 	for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
 	{
 		U64 handle = *iter;
-		LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
-		if (siminfo && (siminfo->mAccess == SIM_ACCESS_DOWN))
+		LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
+		if ((info == NULL) || (info->isDown()))
 		{
 			continue;
 		}
-		LLWorldMap::agent_list_map_t::iterator counts_iter = LLWorldMap::getInstance()->mAgentLocationsMap.find(handle);
-		if (siminfo && siminfo->mShowAgentLocations && counts_iter != LLWorldMap::getInstance()->mAgentLocationsMap.end())
+		// Infohubs
+		if (gSavedSettings.getBOOL("MapShowInfohubs"))
 		{
-			// Show Individual agents (or little stacks where real agents are)
-			LLWorldMap::item_info_list_t& agentcounts = counts_iter->second;
-			S32 sim_agent_count = 0;
-			for (LLWorldMap::item_info_list_t::iterator iter = agentcounts.begin();
-				 iter != agentcounts.end(); ++iter)
-			{
-				const LLItemInfo& info = *iter;
-				S32 agent_count = info.mExtra;
-				sim_agent_count += info.mExtra;
-				// Here's how we'd choose the color if info.mID were available but it's not being sent:
-				//LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? map_avatar_friend_color : map_avatar_color;
-				drawImageStack(info.mPosGlobal, sAvatarSmallImage, agent_count, 3.f, map_avatar_color);
-			}
-			LLWorldMap::getInstance()->mNumAgents[handle] = sim_agent_count; // override mNumAgents for this sim
+			drawGenericItems(info->getInfoHub(), sInfohubImage);
 		}
-		else
+		// Telehubs
+		if (gSavedSettings.getBOOL("MapShowTelehubs"))
 		{
-			// Show agent 'stack' at center of sim
-			S32 num_agents = LLWorldMap::getInstance()->mNumAgents[handle];
-			if (num_agents > 0)
+			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())
 			{
-				LLVector3d region_center = from_region_handle(handle);
-				region_center[VX] += REGION_WIDTH_METERS / 2;
-				region_center[VY] += REGION_WIDTH_METERS / 2;
-				// Reduce the stack size as you zoom out - always display at lease one agent where there is one or more
-				S32 agent_count = (S32)(((num_agents-1) * agents_scale + (num_agents-1) * 0.1f)+.1f) + 1;
-				drawImageStack(region_center, sAvatarSmallImage, agent_count, 3.f, map_avatar_color);
+				drawGenericItems(info->getLandForSaleAdult(), sForSaleAdultImage);
 			}
 		}
+		// PG Events
+		if (gSavedSettings.getBOOL("MapShowEvents"))
+		{
+			drawGenericItems(info->getPGEvent(), sEventImage);
+		}
+		// Mature Events
+		if (show_mature)
+		{
+			drawGenericItems(info->getMatureEvent(), sEventMatureImage);
+		}
+		// Adult Events
+		if (show_adult)
+		{
+			drawGenericItems(info->getAdultEvent(), sEventAdultImage);
+		}
 	}
 }
 
-
-void LLWorldMapView::drawEvents()
+void LLWorldMapView::drawAgents()
 {
-	bool mature_enabled = gAgent.canAccessMature();
-	bool adult_enabled = gAgent.canAccessAdult();
-
-	BOOL show_pg = gSavedSettings.getBOOL("MapShowEvents");
-    BOOL show_mature = mature_enabled && gSavedSettings.getBOOL("ShowMatureEvents");
-	BOOL show_adult = adult_enabled && gSavedSettings.getBOOL("ShowAdultEvents");
+	static LLUIColor map_avatar_color = LLUIColorTable::instance().getColor("MapAvatarColor", LLColor4::white);
 
-    // First the non-selected events
-    LLWorldMap::item_info_list_t::const_iterator e;
-	if (show_pg)
+	for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
 	{
-		for (e = LLWorldMap::getInstance()->mPGEvents.begin(); e != LLWorldMap::getInstance()->mPGEvents.end(); ++e)
+		U64 handle = *iter;
+		LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
+		if ((siminfo == NULL) || (siminfo->isDown()))
 		{
-			if (!e->mSelected)
-			{
-				drawGenericItem(*e, sEventImage);   
-			}
+			continue;
 		}
-	}
-    if (show_mature)
-    {
-        for (e = LLWorldMap::getInstance()->mMatureEvents.begin(); e != LLWorldMap::getInstance()->mMatureEvents.end(); ++e)
-        {
-            if (!e->mSelected)
-            {
-                drawGenericItem(*e, sEventMatureImage);       
-            }
-        }
-    }
-	if (show_adult)
-    {
-        for (e = LLWorldMap::getInstance()->mAdultEvents.begin(); e != LLWorldMap::getInstance()->mAdultEvents.end(); ++e)
-        {
-            if (!e->mSelected)
-            {
-                drawGenericItem(*e, sEventAdultImage);       
-            }
-        }
-    }
-    // Then the selected events
-	if (show_pg)
-	{
-		for (e = LLWorldMap::getInstance()->mPGEvents.begin(); e != LLWorldMap::getInstance()->mPGEvents.end(); ++e)
+		LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAgentLocation().begin();
+		while (it != siminfo->getAgentLocation().end())
 		{
-			if (e->mSelected)
-			{
-				drawGenericItem(*e, sEventImage);
-			}
+			// Show Individual agents (or little stacks where real agents are)
+
+			// Here's how we'd choose the color if info.mID were available but it's not being sent:
+			// LLColor4 color = (agent_count == 1 && is_agent_friend(info.mID)) ? friend_color : avatar_color;
+			drawImageStack(it->getGlobalPosition(), sAvatarSmallImage, it->getCount(), 3.f, map_avatar_color);
+			++it;
 		}
 	}
-    if (show_mature)
-    {
-        for (e = LLWorldMap::getInstance()->mMatureEvents.begin(); e != LLWorldMap::getInstance()->mMatureEvents.end(); ++e)
-        {
-            if (e->mSelected)
-            {
-                drawGenericItem(*e, sEventMatureImage);       
-            }
-        }
-    }
-	if (show_adult)
-    {
-        for (e = LLWorldMap::getInstance()->mAdultEvents.begin(); e != LLWorldMap::getInstance()->mAdultEvents.end(); ++e)
-        {
-            if (e->mSelected)
-            {
-                drawGenericItem(*e, sEventAdultImage);       
-            }
-        }
-    }
 }
 
-
 void LLWorldMapView::drawFrustum()
 {
 	// Draw frustum
-	F32 meters_to_pixels = gMapScale/ REGION_WIDTH_METERS;
+	F32 meters_to_pixels = sMapScale/ REGION_WIDTH_METERS;
 
 	F32 horiz_fov = LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect();
 	F32 far_clip_meters = LLViewerCamera::getInstance()->getFar();
@@ -1077,8 +917,8 @@ LLVector3 LLWorldMapView::globalPosToView( const LLVector3d& global_pos )
 	LLVector3 pos_local;
 	pos_local.setVec(relative_pos_global);  // convert to floats from doubles
 
-	pos_local.mV[VX] *= sPixelsPerMeter;
-	pos_local.mV[VY] *= sPixelsPerMeter;
+	pos_local.mV[VX] *= sMapScale / REGION_WIDTH_METERS;
+	pos_local.mV[VY] *= sMapScale / REGION_WIDTH_METERS;
 	// leave Z component in meters
 
 
@@ -1162,7 +1002,7 @@ LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
 
 	LLVector3 pos_local( (F32)x, (F32)y, 0.f );
 
-	pos_local *= ( REGION_WIDTH_METERS / gMapScale );
+	pos_local *= ( REGION_WIDTH_METERS / sMapScale );
 	
 	LLVector3d pos_global;
 	pos_global.setVec( pos_local );
@@ -1183,23 +1023,20 @@ LLVector3d LLWorldMapView::viewPosToGlobal( S32 x, S32 y )
 BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
 {
 	LLVector3d pos_global = viewPosToGlobal(x, y);
-
+	U64 handle = to_region_handle(pos_global);
 	std::string tooltip_msg;
 
-	LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromPosGlobal(pos_global);
+	LLSimInfo* info = LLWorldMap::getInstance()->simInfoFromHandle(handle);
 	if (info)
 	{
 		LLViewerRegion *region = gAgent.getRegion();
 
-		std::string message = 
-			llformat("%s (%s)",
-					 info->mName.c_str(),
-					 LLViewerRegion::accessToString(info->mAccess).c_str());
+		std::string message = llformat("%s (%s)", info->getName().c_str(), info->getAccessString().c_str());
 
-		if (info->mAccess != SIM_ACCESS_DOWN)
+		if (!info->isDown())
 		{
-			S32 agent_count = LLWorldMap::getInstance()->mNumAgents[info->mHandle];			
-			if (region && region->getHandle() == info->mHandle)
+			S32 agent_count = info->getAgentCount();			
+			if (region && (region->getHandle() == handle))
 			{
 				++agent_count; // Bump by 1 if we're here
 			}
@@ -1208,6 +1045,8 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
 			// zoomed out, so don't display anything about the count. JC
 			if (agent_count > 0)
 			{
+				// Merov: i18n horror!!! Even using gettext(), concatenating strings is not localizable. 
+				// The singular/plural switch form here under might make no sense in some languages. Don't do that.
 				message += llformat("\n%d ", agent_count);
 
 				if (agent_count == 1)
@@ -1223,7 +1062,7 @@ BOOL LLWorldMapView::handleToolTip( S32 x, S32 y, MASK mask )
 		tooltip_msg.assign( message );
 
 		// Optionally show region flags
-		std::string region_flags = LLViewerRegion::regionFlagsToString(info->mRegionFlags);
+		std::string region_flags = info->getFlagsString();
 
 		if (!region_flags.empty())
 		{
@@ -1263,6 +1102,9 @@ static void drawDot(F32 x_pixels, F32 y_pixels,
 	}
 	else
 	{
+		// Draw V indicator for above or below
+		// *TODO: Replace this vector drawing with icons
+		
 		F32 left =		x_pixels - dot_radius;
 		F32 right =		x_pixels + dot_radius;
 		F32 center = (left + right) * 0.5f;
@@ -1271,13 +1113,14 @@ static void drawDot(F32 x_pixels, F32 y_pixels,
 
 		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		gGL.color4fv( color.mV );
-		LLUI::setLineWidth(1.5f);
-		F32 h_bar = relative_z > HEIGHT_THRESHOLD ? top : bottom; // horizontal bar Y
+		LLUI::setLineWidth(3.0f);
+		F32 point = relative_z > HEIGHT_THRESHOLD ? top : bottom; // Y pos of the point of the V
+		F32 back = relative_z > HEIGHT_THRESHOLD ? bottom : top; // Y pos of the ends of the V
 		gGL.begin( LLRender::LINES );
-			gGL.vertex2f(center, top);
-			gGL.vertex2f(left, h_bar);
-			gGL.vertex2f(right, h_bar);
-			gGL.vertex2f(right, bottom);
+			gGL.vertex2f(left, back);
+			gGL.vertex2f(center, point);
+			gGL.vertex2f(center, point);
+			gGL.vertex2f(right, back);
 		gGL.end();
 		LLUI::setLineWidth(1.0f);
 	}
@@ -1292,7 +1135,7 @@ void LLWorldMapView::drawAvatar(F32 x_pixels,
 								F32 dot_radius)
 {
 	const F32 HEIGHT_THRESHOLD = 7.f;
-	LLUIImagePtr dot_image = sAvatarSmallImage;
+	LLUIImagePtr dot_image = sAvatarLevelImage;
 	if(relative_z < -HEIGHT_THRESHOLD) 
 	{
 		dot_image = sAvatarBelowImage; 
@@ -1301,10 +1144,12 @@ void LLWorldMapView::drawAvatar(F32 x_pixels,
 	{ 
 		dot_image = sAvatarAboveImage;
 	}
-	dot_image->draw(
-		llround(x_pixels) - dot_image->getWidth()/2,
-		llround(y_pixels) - dot_image->getHeight()/2, 
-		color);
+	S32 dot_width = llround(dot_radius * 2.f);
+	dot_image->draw(llround(x_pixels - dot_radius),
+					llround(y_pixels - dot_radius),
+					dot_width,
+					dot_width,
+					color);
 }
 
 // Pass relative Z of 0 to draw at same level.
@@ -1565,7 +1410,7 @@ void LLWorldMapView::reshape( S32 width, S32 height, BOOL called_from_parent )
 
 bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bool track)
 {
-	LLVector3 pos_view = globalPosToView(item.mPosGlobal);
+	LLVector3 pos_view = globalPosToView(item.getGlobalPosition());
 	S32 item_x = llround(pos_view.mV[VX]);
 	S32 item_y = llround(pos_view.mV[VY]);
 
@@ -1574,12 +1419,12 @@ bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bo
 	if (y < item_y - BIG_DOT_RADIUS) return false;
 	if (y > item_y + BIG_DOT_RADIUS) return false;
 
-	LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromHandle(item.mRegionHandle);
+	LLSimInfo* sim_info = LLWorldMap::getInstance()->simInfoFromHandle(item.getRegionHandle());
 	if (sim_info)
 	{
 		if (track)
 		{
-			gFloaterWorldMap->trackLocation(item.mPosGlobal);
+			gFloaterWorldMap->trackLocation(item.getGlobalPosition());
 		}
 	}
 
@@ -1588,8 +1433,8 @@ bool LLWorldMapView::checkItemHit(S32 x, S32 y, LLItemInfo& item, LLUUID* id, bo
 		gFloaterWorldMap->trackGenericItem(item);
 	}
 
-	item.mSelected = TRUE;
-	*id = item.mID;
+//	item.setSelected(true);
+	*id = item.getUUID();
 
 	return true;
 }
@@ -1612,108 +1457,116 @@ void LLWorldMapView::handleClick(S32 x, S32 y, MASK mask,
 
 	*hit_type = 0; // hit nothing
 
-	LLWorldMap::getInstance()->mIsTrackingUnknownLocation = FALSE;
-	LLWorldMap::getInstance()->mIsTrackingDoubleClick = FALSE;
-	LLWorldMap::getInstance()->mIsTrackingCommit = FALSE;
-
-	LLWorldMap::item_info_list_t::iterator it;
-
-	// clear old selected stuff
-	for (it = LLWorldMap::getInstance()->mPGEvents.begin(); it != LLWorldMap::getInstance()->mPGEvents.end(); ++it)
-	{
-		(*it).mSelected = FALSE;
-	}
-	for (it = LLWorldMap::getInstance()->mMatureEvents.begin(); it != LLWorldMap::getInstance()->mMatureEvents.end(); ++it)
-	{
-		(*it).mSelected = FALSE;
-	}
-	for (it = LLWorldMap::getInstance()->mAdultEvents.begin(); it != LLWorldMap::getInstance()->mAdultEvents.end(); ++it)
-	{
-		(*it).mSelected = FALSE;
-	}
-	for (it = LLWorldMap::getInstance()->mLandForSale.begin(); it != LLWorldMap::getInstance()->mLandForSale.end(); ++it)
-	{
-		(*it).mSelected = FALSE;
-	}
-
-	// Select event you clicked on
-	if (gSavedSettings.getBOOL("MapShowEvents"))
-	{
-		for (it = LLWorldMap::getInstance()->mPGEvents.begin(); it != LLWorldMap::getInstance()->mPGEvents.end(); ++it)
-		{
-			LLItemInfo& event = *it;
-
-			if (checkItemHit(x, y, event, id, false))
-			{
-				*hit_type = MAP_ITEM_PG_EVENT;
-				mItemPicked = TRUE;
-				gFloaterWorldMap->trackEvent(event);
-				return;
-			}
-		}
-	}
-	if (gSavedSettings.getBOOL("ShowMatureEvents"))
-	{
-		for (it = LLWorldMap::getInstance()->mMatureEvents.begin(); it != LLWorldMap::getInstance()->mMatureEvents.end(); ++it)
-		{
-			LLItemInfo& event = *it;
-
-			if (checkItemHit(x, y, event, id, false))
-			{
-				*hit_type = MAP_ITEM_MATURE_EVENT;
-				mItemPicked = TRUE;
-				gFloaterWorldMap->trackEvent(event);
-				return;
-			}
-		}
-	}
-	if (gSavedSettings.getBOOL("ShowAdultEvents"))
-	{
-		for (it = LLWorldMap::getInstance()->mAdultEvents.begin(); it != LLWorldMap::getInstance()->mAdultEvents.end(); ++it)
-		{
-			LLItemInfo& event = *it;
-
-			if (checkItemHit(x, y, event, id, false))
-			{
-				*hit_type = MAP_ITEM_ADULT_EVENT;
-				mItemPicked = TRUE;
-				gFloaterWorldMap->trackEvent(event);
-				return;
-			}
-		}
-	}
+	LLWorldMap::getInstance()->cancelTracking();
 
-	if (gSavedSettings.getBOOL("MapShowLandForSale"))
+	S32 level = LLWorldMipmap::scaleToLevel(sMapScale);
+	// If the zoom level is not too far out already, test hits
+	if (level <= DRAW_SIMINFO_THRESHOLD)
 	{
-		for (it = LLWorldMap::getInstance()->mLandForSale.begin(); it != LLWorldMap::getInstance()->mLandForSale.end(); ++it)
-		{
-			LLItemInfo& land = *it;
+		bool show_mature = gAgent.canAccessMature() && gSavedSettings.getBOOL("ShowMatureEvents");
+		bool show_adult = gAgent.canAccessAdult() && gSavedSettings.getBOOL("ShowAdultEvents");
 
-			if (checkItemHit(x, y, land, id, true))
-			{
-				*hit_type = MAP_ITEM_LAND_FOR_SALE;
-				mItemPicked = TRUE;
-				return;
-			}
-		}
-		
-		for (it = LLWorldMap::getInstance()->mLandForSaleAdult.begin(); it != LLWorldMap::getInstance()->mLandForSaleAdult.end(); ++it)
+		// Test hits if trackable data are displayed, otherwise, we don't even bother
+		if (gSavedSettings.getBOOL("MapShowEvents") || show_mature || show_adult || gSavedSettings.getBOOL("MapShowLandForSale"))
 		{
-			LLItemInfo& land = *it;
-
-			if (checkItemHit(x, y, land, id, true))
+			// Iterate through the visible regions
+			for (handle_list_t::iterator iter = mVisibleRegions.begin(); iter != mVisibleRegions.end(); ++iter)
 			{
-				*hit_type = MAP_ITEM_LAND_FOR_SALE_ADULT;
-				mItemPicked = TRUE;
-				return;
+				U64 handle = *iter;
+				LLSimInfo* siminfo = LLWorldMap::getInstance()->simInfoFromHandle(handle);
+				if ((siminfo == NULL) || (siminfo->isDown()))
+				{
+					continue;
+				}
+				// If on screen check hits with the visible item lists
+				if (gSavedSettings.getBOOL("MapShowEvents"))
+				{
+					LLSimInfo::item_info_list_t::const_iterator it = siminfo->getPGEvent().begin();
+					while (it != siminfo->getPGEvent().end())
+					{
+						LLItemInfo event = *it;
+						if (checkItemHit(x, y, event, id, false))
+						{
+							*hit_type = MAP_ITEM_PG_EVENT;
+							mItemPicked = TRUE;
+							gFloaterWorldMap->trackEvent(event);
+							return;
+						}
+						++it;
+					}
+				}
+				if (show_mature)
+				{
+					LLSimInfo::item_info_list_t::const_iterator it = siminfo->getMatureEvent().begin();
+					while (it != siminfo->getMatureEvent().end())
+					{
+						LLItemInfo event = *it;
+						if (checkItemHit(x, y, event, id, false))
+						{
+							*hit_type = MAP_ITEM_MATURE_EVENT;
+							mItemPicked = TRUE;
+							gFloaterWorldMap->trackEvent(event);
+							return;
+						}
+						++it;
+					}
+				}
+				if (show_adult)
+				{
+					LLSimInfo::item_info_list_t::const_iterator it = siminfo->getAdultEvent().begin();
+					while (it != siminfo->getAdultEvent().end())
+					{
+						LLItemInfo event = *it;
+						if (checkItemHit(x, y, event, id, false))
+						{
+							*hit_type = MAP_ITEM_ADULT_EVENT;
+							mItemPicked = TRUE;
+							gFloaterWorldMap->trackEvent(event);
+							return;
+						}
+						++it;
+					}
+				}
+				if (gSavedSettings.getBOOL("MapShowLandForSale"))
+				{
+					LLSimInfo::item_info_list_t::const_iterator it = siminfo->getLandForSale().begin();
+					while (it != siminfo->getLandForSale().end())
+					{
+						LLItemInfo event = *it;
+						if (checkItemHit(x, y, event, id, true))
+						{
+							*hit_type = MAP_ITEM_LAND_FOR_SALE;
+							mItemPicked = TRUE;
+							return;
+						}
+						++it;
+					}
+					// for 1.23, we're showing normal land and adult land in the same UI; you don't
+					// get a choice about which ones you want. If you're currently asking for adult
+					// content and land you'll get the adult land.
+					if (gAgent.canAccessAdult())
+					{
+						LLSimInfo::item_info_list_t::const_iterator it = siminfo->getLandForSaleAdult().begin();
+						while (it != siminfo->getLandForSaleAdult().end())
+						{
+							LLItemInfo event = *it;
+							if (checkItemHit(x, y, event, id, true))
+							{
+								*hit_type = MAP_ITEM_LAND_FOR_SALE_ADULT;
+								mItemPicked = TRUE;
+								return;
+							}
+							++it;
+						}
+					}
+				}
 			}
 		}
 	}
-	// If we get here, we haven't clicked on an icon
 
+	// If we get here, we haven't clicked on anything
 	gFloaterWorldMap->trackLocation(pos_global);
 	mItemPicked = FALSE;
-
 	*id = LLUUID::null;
 	return;
 }
@@ -1774,59 +1627,36 @@ BOOL LLWorldMapView::handleMouseUp( S32 x, S32 y, MASK mask )
 	return FALSE;
 }
 
-U32 LLWorldMapView::updateBlock(S32 block_x, S32 block_y)
+void LLWorldMapView::updateVisibleBlocks()
 {
-	U32 blocks_requested = 0;
-	S32 offset = block_x | (block_y * MAP_BLOCK_RES);
-	if (!LLWorldMap::getInstance()->mMapBlockLoaded[LLWorldMap::getInstance()->mCurrentMap][offset])
+	if (LLWorldMipmap::scaleToLevel(sMapScale) > DRAW_SIMINFO_THRESHOLD)
 	{
-// 		llinfos << "Loading Block (" << block_x << "," << block_y << ")" << llendl;
-		LLWorldMap::getInstance()->sendMapBlockRequest(block_x << 3, block_y << 3, (block_x << 3) + 7, (block_y << 3) + 7);
-		LLWorldMap::getInstance()->mMapBlockLoaded[LLWorldMap::getInstance()->mCurrentMap][offset] = TRUE;
-		blocks_requested++;
+		// If we're zoomed out too much, we just don't load all those sim info: too much!
+		return;
 	}
-	return blocks_requested;
-}
 
-U32 LLWorldMapView::updateVisibleBlocks()
-{
-	if (gMapScale < SIM_MAP_SCALE)
-	{
-		// We don't care what is loaded if we're zoomed out
-		return 0;
-	}
+	// Load the blocks visible in the current World Map view
 
+	// Get the World Map view coordinates and boundaries
 	LLVector3d camera_global = gAgent.getCameraPositionGlobal();
-	
-	F32 pixels_per_region = gMapScale;
 	const S32 width = getRect().getWidth();
 	const S32 height = getRect().getHeight();
-	// Convert pan to sim coordinates
-	S32 world_center_x_lo = S32(((-sPanX - width/2) / pixels_per_region) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
-	S32 world_center_x_hi = S32(((-sPanX + width/2) / pixels_per_region) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
-	S32 world_center_y_lo = S32(((-sPanY - height/2) / pixels_per_region) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
-	S32 world_center_y_hi = S32(((-sPanY + height/2)/ pixels_per_region) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
-	
-	// Find the corresponding 8x8 block
-	S32 world_block_x_lo = world_center_x_lo >> 3;
-	S32 world_block_x_hi = world_center_x_hi >> 3;
-	S32 world_block_y_lo = world_center_y_lo >> 3;
-	S32 world_block_y_hi = world_center_y_hi >> 3;
-	
-	U32 blocks_requested = 0;
-	const U32 max_blocks_requested = 9;
+	const F32 half_width = F32(width) / 2.0f;
+	const F32 half_height = F32(height) / 2.0f;
 
-	for (S32 block_x = llmax(world_block_x_lo, 0); block_x <= llmin(world_block_x_hi, MAP_BLOCK_RES-1); ++block_x)
-	{
-		for (S32 block_y = llmax(world_block_y_lo, 0); block_y <= llmin(world_block_y_hi, MAP_BLOCK_RES-1); ++block_y)
-		{
-			blocks_requested += updateBlock(block_x, block_y);
-			if (blocks_requested >= max_blocks_requested)
-				return blocks_requested;
-		}
-	}
-	return blocks_requested;
-} 
+	// Compute center into sim grid coordinates
+	S32 world_center_x = S32((-sPanX / sMapScale) + (camera_global.mdV[0] / REGION_WIDTH_METERS));
+	S32 world_center_y = S32((-sPanY / sMapScale) + (camera_global.mdV[1] / REGION_WIDTH_METERS));
+
+	// Compute the boundaries into sim grid coordinates
+	S32 world_left   = world_center_x - S32(half_width  / sMapScale) - 1;
+	S32 world_right  = world_center_x + S32(half_width  / sMapScale) + 1;
+	S32 world_bottom = world_center_y - S32(half_height / sMapScale) - 1;
+	S32 world_top    = world_center_y + S32(half_height / sMapScale) + 1;
+
+	//LL_INFOS("World Map") << "LLWorldMapView::updateVisibleBlocks() : sMapScale = " << sMapScale << ", left = " << world_left << ", right = " << world_right << ", bottom  = " << world_bottom << ", top = " << world_top << LL_ENDL;
+	LLWorldMap::getInstance()->updateRegions(world_left, world_bottom, world_right, world_top);
+}
 
 BOOL LLWorldMapView::handleHover( S32 x, S32 y, MASK mask )
 {
@@ -1915,16 +1745,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 66793f01018cd9e1e52161dd9a6216593c8b8525..9eecacb2d83e284076a854459d7fbd532b78b193 100644
--- a/indra/newview/llworldmapview.h
+++ b/indra/newview/llworldmapview.h
@@ -30,27 +30,23 @@
  * $/LicenseInfo$
  */
 
-// Global map of the world.
+// View of the global map of the world
+
+// The data (model) for the global map (a singleton, unique to the application instance) is 
+// in LLWorldMap and is typically accessed using LLWorldMap::getInstance()
 
 #ifndef LL_LLWORLDMAPVIEW_H
 #define LL_LLWORLDMAPVIEW_H
 
 #include "llpanel.h"
-#include "v3math.h"
-#include "v3dmath.h"
-#include "v4color.h"
-#include "llviewertexture.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 LLViewerTexture;
+class LLUUID;
+class LLVector3d;
+class LLVector3;
 class LLTextBox;
 
 
@@ -77,22 +73,26 @@ class LLWorldMapView : public LLPanel
 	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();
 
@@ -108,7 +108,7 @@ class LLWorldMapView : public LLPanel
 									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, 
@@ -129,9 +129,7 @@ class LLWorldMapView : public LLPanel
 	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 );
@@ -140,11 +138,13 @@ class LLWorldMapView : public LLPanel
 public:
 	LLColor4		mBackgroundColor;
 
-	static LLUIImagePtr	sAvatarYouSmallImage;
 	static LLUIImagePtr	sAvatarSmallImage;
-	static LLUIImagePtr	sAvatarLargeImage;
+	static LLUIImagePtr	sAvatarYouImage;
+	static LLUIImagePtr	sAvatarYouLargeImage;
+	static LLUIImagePtr	sAvatarLevelImage;
 	static LLUIImagePtr	sAvatarAboveImage;
 	static LLUIImagePtr	sAvatarBelowImage;
+
 	static LLUIImagePtr	sTelehubImage;
 	static LLUIImagePtr	sInfohubImage;
 	static LLUIImagePtr	sHomeImage;
@@ -157,9 +157,7 @@ class LLWorldMapView : public LLPanel
 	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;
 
@@ -169,6 +167,7 @@ class LLWorldMapView : public LLPanel
 	static F32		sTargetPanY;		// in pixels
 	static S32		sTrackingArrowX;
 	static S32		sTrackingArrowY;
+	static bool		sVisibleTilesLoaded;
 
 	// Are we mid-pan from a user drag?
 	BOOL			mPanning;
@@ -191,10 +190,14 @@ class LLWorldMapView : public LLPanel
 	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<U64> handle_list_t;
 	handle_list_t mVisibleRegions; // set every frame
 
 	static std::map<std::string,std::string> 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 0000000000000000000000000000000000000000..8d3165b98c65eb47d8d91759aee9cef25571d7bc
--- /dev/null
+++ b/indra/newview/llworldmipmap.cpp
@@ -0,0 +1,275 @@
+/** 
+ * @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 "llviewertexturelist.h"
+#include "math.h"	// log()
+
+// 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<LLViewerFetchedTexture> img = iter->second;
+			S32 current_boost_level = img->getBoostLevel();
+			if (current_boost_level == LLViewerTexture::BOOST_MAP_VISIBLE)
+			{
+				// If level was BOOST_MAP_VISIBLE, the tile has been used in the last draw so keep it high
+				img->setBoostLevel(LLViewerTexture::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(LLViewerTexture::BOOST_NONE);
+			}
+#if DEBUG_TILES_STAT
+			// Increment some stats if compile option on
+			nb_tiles++;
+			if (current_boost_level == LLViewerTexture::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<LLViewerFetchedTexture> img = iter->second;
+			img->setBoostLevel(LLViewerTexture::BOOST_NONE);
+		}
+	}
+}
+
+LLPointer<LLViewerFetchedTexture> 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<LLViewerFetchedTexture> img = loadObjectsTile(grid_x, grid_y, level);
+			// 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<LLViewerFetchedTexture> 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(LLViewerTexture::BOOST_MAP_VISIBLE);
+		}
+		return img;
+	}
+}
+
+LLPointer<LLViewerFetchedTexture> LLWorldMipmap::loadObjectsTile(U32 grid_x, U32 grid_y, S32 level)
+{
+	// Get the grid coordinates
+//	std::string imageurl = llformat("http://map.secondlife.com.s3.amazonaws.com/%d/%05d/%05d/map-%d-%d-%d-objects.jpg",
+	std::string imageurl = llformat("http://map.secondlife.com.s3.amazonaws.com/map-%d-%d-%d-objects.jpg",
+									level, grid_x, grid_y, 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<LLViewerFetchedTexture> img = LLViewerTextureManager::getFetchedTextureFromUrl(imageurl, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+	img->setBoostLevel(LLViewerTexture::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<LLViewerFetchedTexture> 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 0000000000000000000000000000000000000000..ecf10034686870590c26325f5c9a49bfccc63b5d
--- /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 <map>
+
+#include "llmemory.h"			// LLPointer
+#include "indra_constants.h"	// REGION_WIDTH_UNITS
+#include "llregionhandle.h"		// to_region_handle()
+
+class LLViewerFetchedTexture;
+
+// 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<LLViewerFetchedTexture> 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<LLViewerFetchedTexture> 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<LLViewerFetchedTexture> 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<U64, LLPointer<LLViewerFetchedTexture> > 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/pipeline.cpp b/indra/newview/pipeline.cpp
index b01a4f5161d01794ddfe696be73111ac3931f650..17c04a81c27f8851ae177de5a3f912cb11882b26 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1464,6 +1464,7 @@ F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera
 	F32 dist = lookAt.length();
 
 	//ramp down distance for nearby objects
+	//shrink dist by dist/16.
 	if (dist < 16.f)
 	{
 		dist /= 16.f;
@@ -3001,15 +3002,6 @@ void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
 
 	LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO");
 	
-	//by bao
-	//fake vertex buffer updating
-	//to guaranttee at least updating one VBO buffer every frame
-	//to walk around the bug caused by ATI card --> DEV-3855
-	//
-	if(forceVBOUpdate)
-		gSky.mVOSkyp->updateDummyVertexBuffer() ;
-
-
 	// Initialize lots of GL state to "safe" values
 	glMatrixMode(GL_TEXTURE);
 	glLoadIdentity();
diff --git a/indra/newview/skins/default/textures/map_avatar_32.tga b/indra/newview/skins/default/textures/map_avatar_32.tga
new file mode 100644
index 0000000000000000000000000000000000000000..aebeab409366d632722c33328566919423f383fb
Binary files /dev/null and b/indra/newview/skins/default/textures/map_avatar_32.tga differ
diff --git a/indra/newview/skins/default/textures/map_avatar_above_32.tga b/indra/newview/skins/default/textures/map_avatar_above_32.tga
new file mode 100644
index 0000000000000000000000000000000000000000..65bd0561a784cf0402f9978b95e31b45f7127c5b
Binary files /dev/null and b/indra/newview/skins/default/textures/map_avatar_above_32.tga differ
diff --git a/indra/newview/skins/default/textures/map_avatar_below_32.tga b/indra/newview/skins/default/textures/map_avatar_below_32.tga
new file mode 100644
index 0000000000000000000000000000000000000000..496c44b369a473a38831885aab44c5b0d7e5a939
Binary files /dev/null and b/indra/newview/skins/default/textures/map_avatar_below_32.tga differ
diff --git a/indra/newview/skins/default/textures/map_avatar_you_32.tga b/indra/newview/skins/default/textures/map_avatar_you_32.tga
new file mode 100644
index 0000000000000000000000000000000000000000..782207efd6c28747686bcaf4355e2fe7388dbe94
Binary files /dev/null and b/indra/newview/skins/default/textures/map_avatar_you_32.tga differ
diff --git a/indra/newview/skins/default/xui/en/floater_world_map.xml b/indra/newview/skins/default/xui/en/floater_world_map.xml
index f37c0e90224c132f43d41ba9f9f06486c732426c..14fdbeaaa1ac08ef3a2200ffc68edcad84f187d6 100644
--- a/indra/newview/skins/default/xui/en/floater_world_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_world_map.xml
@@ -14,38 +14,15 @@
  single_instance="true"
  title="World Map"
  width="800">
-    <tab_container
+    <panel
+     filename="panel_world_map.xml"
      follows="left|top|right|bottom"
      height="565"
      layout="topleft"
      left="15"
-     name="maptab"
-     tab_position="top"
+     name="objects_mapview"
      top="25"
-     width="542">
-        <panel
-         filename="panel_world_map.xml"
-         follows="left|top|right|bottom"
-         height="550"
-         label="Objects"
-         layout="topleft"
-         left="1"
-         help_topic="worldmap_objects_tab"
-         name="objects_mapview"
-         top="19"
-         width="540" />
-        <panel
-         filename="panel_world_map.xml"
-         follows="left|top|right|bottom"
-         height="550"
-         label="Terrain"
-         layout="topleft"
-         left_delta="0"
-         help_topic="worldmap_terrain_tab"
-         name="terrain_mapview"
-         top_delta="3"
-         width="540" />
-    </tab_container>
+     width="542" />
     <icon
      follows="top|right"
      height="16"
@@ -209,7 +186,7 @@
      label="Telehub"
      layout="topleft"
      left_pad="4"
-     name="telehubchk"
+     name="telehub_chk"
      top_delta="0"
      width="110" />
     <icon
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 284594426c7439b9ac5a18f6e8a5fcc2f1d75430..6ebb5f8681f91c18d946b8ab4bef0f51dc275dc2 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1672,6 +1672,42 @@
                  function="Advanced.ToggleConsole"
                  parameter="debug" />
             </menu_item_check>
+            <menu_item_check
+             label="Notifications Console"
+             layout="topleft"
+             name="Notifications"
+             shortcut="control|shift|5">
+              <menu_item_check.on_check
+               function="Advanced.CheckConsole"
+               parameter="notifications" />
+              <menu_item_check.on_click
+               function="Floater.Show"
+               parameter="notifications_console" />
+            </menu_item_check>
+            <menu_item_check
+               label="Texture Size Console"
+               layout="topleft"
+               name="Texture Size"
+               shortcut="control|shift|6">
+              <menu_item_check.on_check
+               function="Advanced.CheckConsole"
+               parameter="texture size" />
+              <menu_item_check.on_click
+               function="Advanced.ToggleConsole"
+               parameter="texture size" />
+            </menu_item_check>
+            <menu_item_check
+               label="Texture Category Console"
+               layout="topleft"
+               name="Texture Category"
+               shortcut="control|shift|7">
+              <menu_item_check.on_check
+               function="Advanced.CheckConsole"
+               parameter="texture category" />
+              <menu_item_check.on_click
+               function="Advanced.ToggleConsole"
+               parameter="texture category" />
+            </menu_item_check>
             <menu_item_check
              label="Fast Timers"
              layout="topleft"
@@ -2229,19 +2265,43 @@
              label="Disable Textures"
              name="Disable Textures">
                 <menu_item_check.on_check
-                 function="Advanced.CheckDisableTextures"
-                 parameter="DisableTextures" />
+                 function="CheckControl"
+                 parameter="TextureDisable" />
+                <menu_item_check.on_click
+                 function="ToggleControl" 
+                 parameter="TextureDisable" />
+            </menu_item_check>
+            <menu_item_check
+              label="Full Res Textures"
+             layout="topleft"
+             name="Rull Res Textures">
+                <menu_item_check.on_check
+                 function="CheckControl"
+                 parameter="TextureLoadFullRes" />
                 <menu_item_check.on_click
-                 function="Advanced.ToggleDisableTextures" />
+                 function="ToggleControl"
+                 parameter="TextureLoadFullRes" />
+            </menu_item_check>
+            <menu_item_check
+               label="Audit Textures"
+               layout="topleft"
+               name="Audit Textures">
+              <menu_item_check.on_check
+               function="CheckControl"
+               parameter="AuditTexture" />
+              <menu_item_check.on_click
+               function="ToggleControl"
+               parameter="AuditTexture" />
             </menu_item_check>
             <menu_item_check
              label="Texture Atlas"
              name="Texture Atlas">
               <menu_item_check.on_check
-               function="Advanced.CheckTextureAtlas"
+               function="CheckControl"
                parameter="TextureAtlas" />
               <menu_item_check.on_click
-               function="Advanced.ToggleTextureAtlas" />
+               function="ToggleControl"
+               parameter="TextureAtlas" />
             </menu_item_check>
               <menu_item_check
              label="Render Attached Lights"
diff --git a/indra/newview/tests/lltextureinfo_test.cpp b/indra/newview/tests/lltextureinfo_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8dfba46262aa280caf78379364ba6978e21b0a15
--- /dev/null
+++ b/indra/newview/tests/lltextureinfo_test.cpp
@@ -0,0 +1,284 @@
+/** 
+ * @file llwtextureinfo_test.cpp
+ * @author Si & Gabriel
+ * @date 2009-03-30
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-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$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../lltextureinfo.h"
+// Dependencies
+#include "../lltextureinfodetails.cpp"
+
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes: 
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+	// Test wrapper declarations
+	struct textureinfo_test
+	{
+		// Constructor and destructor of the test wrapper
+		textureinfo_test()
+		{
+		}
+		~textureinfo_test()
+		{
+		}
+	};
+
+	// Tut templating thingamagic: test group, object and test instance
+	typedef test_group<textureinfo_test> textureinfo_t;
+	typedef textureinfo_t::object textureinfo_object_t;
+	tut::textureinfo_t tut_textureinfo("textureinfo");
+
+	
+	// ---------------------------------------------------------------------------------------
+	// Test functions
+	// Notes:
+	// * Test as many as you possibly can without requiring a full blown simulation of everything
+	// * The tests are executed in sequence so the test instance state may change between calls
+	// * Remember that you cannot test private methods with tut
+	// ---------------------------------------------------------------------------------------
+
+	// ---------------------------------------------------------------------------------------
+	// Test the LLTextureInfo
+	// ---------------------------------------------------------------------------------------
+
+
+	// Test instantiation
+	template<> template<>
+	void textureinfo_object_t::test<1>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+		ensure("have we crashed?", true);
+	}
+
+	// Check lltextureinfo does not contain UUIDs we haven't added
+	template<> template<>
+	void textureinfo_object_t::test<2>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1");
+		ensure(!tex_info.has(nonExistant));
+	}
+
+	// Check we can add a request time for a texture
+	template<> template<>
+	void textureinfo_object_t::test<3>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+		tex_info.setRequestStartTime(id, 200);
+
+		ensure_equals(tex_info.getRequestStartTime(id), 200);
+	}
+
+	// Check time for non-existant texture
+	template<> template<>
+	void textureinfo_object_t::test<4>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1");
+		ensure_equals(tex_info.getRequestStartTime(nonExistant), 0);
+	}
+
+	// Check download complete time for non existant texture
+	template<> template<>
+	void textureinfo_object_t::test<5>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		LLUUID nonExistant("3a0efa3b-84dc-4e17-9b8c-79ea028850c1");
+		ensure_equals(tex_info.getRequestCompleteTime(nonExistant), 0);
+	}
+
+	// requested size is passed in correctly
+	template<> template<>
+	void textureinfo_object_t::test<6>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+		tex_info.setRequestSize(id, 600);
+
+		ensure_equals(tex_info.getRequestSize(id), 600);
+	}
+
+	// transport type is recorded correctly (http)
+	template<> template<>
+	void textureinfo_object_t::test<7>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+		tex_info.setRequestType(id, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+
+		ensure_equals(tex_info.getRequestType(id), LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+	}
+
+	// transport type is recorded correctly (udp)
+	template<> template<>
+	void textureinfo_object_t::test<8>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+		tex_info.setRequestType(id, LLTextureInfoDetails::REQUEST_TYPE_UDP);
+
+		ensure_equals(tex_info.getRequestType(id), LLTextureInfoDetails::REQUEST_TYPE_UDP);
+	}
+
+	// request offset is recorded correctly
+	template<> template<>
+	void textureinfo_object_t::test<9>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		LLUUID id("10e65d70-46fd-429f-841a-bf698e9424d3");
+		tex_info.setRequestOffset(id, 1234);
+
+		ensure_equals(tex_info.getRequestOffset(id), 1234);
+	}
+
+	// ask for averages gives us correct figure
+	template<> template<>
+	void textureinfo_object_t::test<10>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		S32 requestStartTimeOne = 200;
+		S32 requestEndTimeOne = 400;
+		S32 requestSizeOne = 1024;
+		S32 requestSizeOneBits = requestSizeOne * 8;
+		LLUUID id1("10e65d70-46fd-429f-841a-bf698e9424d3");
+		tex_info.setRequestStartTime(id1, requestStartTimeOne);
+		tex_info.setRequestSize(id1, requestSizeOne);
+		tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+		tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne);
+
+		U32 requestStartTimeTwo = 100;
+		U32 requestEndTimeTwo = 500;
+		U32 requestSizeTwo = 2048;
+		S32 requestSizeTwoBits = requestSizeTwo * 8;
+		LLUUID id2("10e65d70-46fd-429f-841a-bf698e9424d4");
+		tex_info.setRequestStartTime(id2, requestStartTimeTwo);
+		tex_info.setRequestSize(id2, requestSizeTwo);
+		tex_info.setRequestType(id2, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+		tex_info.setRequestCompleteTimeAndLog(id2, requestEndTimeTwo);
+
+		S32 averageBitRate = ((requestSizeOneBits/(requestEndTimeOne - requestStartTimeOne)) +
+							(requestSizeTwoBits/(requestEndTimeTwo - requestStartTimeTwo))) / 2;
+
+		S32 totalBytes = requestSizeOne + requestSizeTwo;
+
+		LLSD results = tex_info.getAverages();
+		ensure_equals("is average bits per second correct", results["bits_per_second"].asInteger(), averageBitRate);
+		ensure_equals("is total bytes is correct", results["bytes_downloaded"].asInteger(), totalBytes);
+		ensure_equals("is transport correct", results["transport"].asString(), std::string("HTTP"));
+	}
+
+	// make sure averages cleared when reset is called
+	template<> template<>
+	void textureinfo_object_t::test<11>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		S32 requestStartTimeOne = 200;
+		S32 requestEndTimeOne = 400;
+		S32 requestSizeOne = 1024;
+		LLUUID id1("10e65d70-46fd-429f-841a-bf698e9424d3");
+		tex_info.setRequestStartTime(id1, requestStartTimeOne);
+		tex_info.setRequestSize(id1, requestSizeOne);
+		tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+		tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne);
+
+		tex_info.getAverages();
+		tex_info.reset();
+		LLSD results = tex_info.getAverages();
+		ensure_equals("is average bits per second correct", results["bits_per_second"].asInteger(), 0);
+		ensure_equals("is total bytes is correct", results["bytes_downloaded"].asInteger(), 0);
+		ensure_equals("is transport correct", results["transport"].asString(), std::string("NONE"));
+	}
+
+	// make sure map item removed when expired
+	template<> template<>
+	void textureinfo_object_t::test<12>()
+	{
+		LLTextureInfo tex_info;
+		tex_info.setUpLogging(true, true);
+
+		S32 requestStartTimeOne = 200;
+		S32 requestEndTimeOne = 400;
+		S32 requestSizeOne = 1024;
+		LLUUID id1("10e65d70-46fd-429f-841a-bf698e9424d3");
+		tex_info.setRequestStartTime(id1, requestStartTimeOne);
+		tex_info.setRequestSize(id1, requestSizeOne);
+		tex_info.setRequestType(id1, LLTextureInfoDetails::REQUEST_TYPE_HTTP);
+
+		ensure_equals("map item created", tex_info.getTextureInfoMapSize(), 1);
+
+		tex_info.setRequestCompleteTimeAndLog(id1, requestEndTimeOne);
+
+		ensure_equals("map item removed when consumed", tex_info.getTextureInfoMapSize(), 0);
+	}
+}
+
diff --git a/indra/newview/tests/lltextureinfodetails_test.cpp b/indra/newview/tests/lltextureinfodetails_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..aa2697fb8eb4b0aec7116103c630e4ebd96db4c7
--- /dev/null
+++ b/indra/newview/tests/lltextureinfodetails_test.cpp
@@ -0,0 +1,98 @@
+/** 
+ * @file llwtextureinfodetails_test.cpp
+ * @author Si & Gabriel
+ * @date 2009-03-30
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-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$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../lltextureinfodetails.h"
+// Dependencies
+
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes: 
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+	// Test wrapper declarations
+	struct textureinfodetails_test
+	{
+		// Constructor and destructor of the test wrapper
+		textureinfodetails_test()
+		{
+		}
+		~textureinfodetails_test()
+		{
+		}
+	};
+
+	// Tut templating thingamagic: test group, object and test instance
+	typedef test_group<textureinfodetails_test> textureinfodetails_t;
+	typedef textureinfodetails_t::object textureinfodetails_object_t;
+	tut::textureinfodetails_t tut_textureinfodetails("textureinfodetails");
+
+	
+	// ---------------------------------------------------------------------------------------
+	// Test functions
+	// Notes:
+	// * Test as many as you possibly can without requiring a full blown simulation of everything
+	// * The tests are executed in sequence so the test instance state may change between calls
+	// * Remember that you cannot test private methods with tut
+	// ---------------------------------------------------------------------------------------
+
+	// ---------------------------------------------------------------------------------------
+	// Test the LLTextureInfo
+	// ---------------------------------------------------------------------------------------
+
+
+	// Test instantiation
+	template<> template<>
+	void textureinfodetails_object_t::test<1>()
+	{
+		ensure("have we crashed?", true);
+	}
+}
diff --git a/indra/newview/tests/lltexturestatsuploader_test.cpp b/indra/newview/tests/lltexturestatsuploader_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..77a3e2c3d889c252a102b62f8e7debef160590ea
--- /dev/null
+++ b/indra/newview/tests/lltexturestatsuploader_test.cpp
@@ -0,0 +1,156 @@
+/** 
+ * @file lltexturestatsuploader_test.cpp
+ * @author Si
+ * @date 2009-05-27
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-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$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../lltexturestatsuploader.h"
+// Dependencies
+
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes: 
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+#include "boost/intrusive_ptr.hpp"
+void boost::intrusive_ptr_add_ref(LLCurl::Responder*){}
+void boost::intrusive_ptr_release(LLCurl::Responder* p){}
+const F32 HTTP_REQUEST_EXPIRY_SECS = 0.0f;
+
+static std::string most_recent_url;
+static LLSD most_recent_body;
+
+void LLHTTPClient::post(
+		const std::string& url,
+		const LLSD& body,
+		ResponderPtr,
+		const LLSD& headers,
+		const F32 timeout)
+{
+	// set some sensor code
+	most_recent_url = url;
+	most_recent_body = body;
+	return;
+}
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+namespace tut
+{
+	// Test wrapper declarations
+	struct texturestatsuploader_test
+	{
+		// Constructor and destructor of the test wrapper
+		texturestatsuploader_test()
+		{
+			most_recent_url = "some sort of default text that should never match anything the tests are expecting!";
+			LLSD blank_llsd;
+			most_recent_body = blank_llsd;
+		}
+		~texturestatsuploader_test()
+		{
+		}
+	};
+
+	// Tut templating thingamagic: test group, object and test instance
+	typedef test_group<texturestatsuploader_test> texturestatsuploader_t;
+	typedef texturestatsuploader_t::object texturestatsuploader_object_t;
+	tut::texturestatsuploader_t tut_texturestatsuploader("texturestatsuploader");
+
+	
+	// ---------------------------------------------------------------------------------------
+	// Test functions
+	// Notes:
+	// * Test as many as you possibly can without requiring a full blown simulation of everything
+	// * The tests are executed in sequence so the test instance state may change between calls
+	// * Remember that you cannot test private methods with tut
+	// ---------------------------------------------------------------------------------------
+
+	// ---------------------------------------------------------------------------------------
+	// Test the LLTextureInfo
+	// ---------------------------------------------------------------------------------------
+
+
+	// Test instantiation
+	template<> template<>
+	void texturestatsuploader_object_t::test<1>()
+	{
+		LLTextureStatsUploader tsu;
+		llinfos << &tsu << llendl;
+		ensure("have we crashed?", true);
+	}
+
+	// does it call out to the provided url if we ask it to?
+	template<> template<>
+	void texturestatsuploader_object_t::test<2>()
+	{	
+		LLTextureStatsUploader tsu;
+		std::string url = "http://blahblahblah";
+		LLSD texture_stats;
+		tsu.uploadStatsToSimulator(url, texture_stats);
+		ensure_equals("did the right url get called?", most_recent_url, url);
+		ensure_equals("did the right body get sent?", most_recent_body, texture_stats);
+	}
+
+	// does it not call out to the provided url if we send it an ungranted cap?
+	template<> template<>
+	void texturestatsuploader_object_t::test<3>()
+	{	
+		LLTextureStatsUploader tsu;
+
+		// this url left intentionally blank to mirror
+		// not getting a cap in the caller.
+		std::string url_for_ungranted_cap = ""; 
+							  
+		LLSD texture_stats;
+		std::string most_recent_url_before_test = most_recent_url;
+		tsu.uploadStatsToSimulator(url_for_ungranted_cap, texture_stats);
+
+		ensure_equals("hopefully no url got called!", most_recent_url, most_recent_url_before_test);
+	}
+
+	// does it call out if the data is empty?
+	// should it even do that?
+}
+
diff --git a/indra/newview/tests/llworldmap_test.cpp b/indra/newview/tests/llworldmap_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..56cf86f6df9e8178a4ad6f0afa57204ee1902d76
--- /dev/null
+++ b/indra/newview/tests/llworldmap_test.cpp
@@ -0,0 +1,523 @@
+/** 
+ * @file llworldmap_test.cpp
+ * @author Merov Linden
+ * @date 2009-03-09
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-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$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../llworldmap.h"
+// Dependencies
+#include "../llviewerimagelist.h"
+#include "../llworldmapmessage.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes: 
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+// Stub image calls
+LLViewerImageList::LLViewerImageList() { }
+LLViewerImageList::~LLViewerImageList() { }
+LLViewerImageList gImageList;
+LLViewerImage* LLViewerImageList::getImage(const LLUUID &image_id,
+												   BOOL usemipmaps,
+												   BOOL level_immediate,
+												   LLGLint internal_format,
+												   LLGLenum primary_format,
+												   LLHost request_from_host)
+{ return NULL; }
+void LLViewerImage::setBoostLevel(S32 level) { }
+void LLImageGL::setAddressMode(LLTexUnit::eTextureAddressMode mode) { }
+
+// Stub related map calls
+LLWorldMapMessage::LLWorldMapMessage() { }
+LLWorldMapMessage::~LLWorldMapMessage() { }
+void LLWorldMapMessage::sendItemRequest(U32 type, U64 handle) { }
+void LLWorldMapMessage::sendMapBlockRequest(U16 min_x, U16 min_y, U16 max_x, U16 max_y, bool return_nonexistent) { }
+LLWorldMipmap::LLWorldMipmap() { }
+LLWorldMipmap::~LLWorldMipmap() { }
+void LLWorldMipmap::reset() { }
+void LLWorldMipmap::dropBoostLevels() { }
+void LLWorldMipmap::equalizeBoostLevels() { }
+LLPointer<LLViewerImage> LLWorldMipmap::getObjectsTile(U32 grid_x, U32 grid_y, S32 level, bool load)
+{ return NULL; }
+
+// Stub other stuff
+BOOL gPacificDaylightTime;
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+
+const F32 X_WORLD_TEST = 1000.0f * REGION_WIDTH_METERS;
+const F32 Y_WORLD_TEST = 2000.0f * REGION_WIDTH_METERS;
+const F32 Z_WORLD_TEST = 240.0f;
+const std::string ITEM_NAME_TEST = "Item Foo";
+const std::string TOOLTIP_TEST = "Tooltip Foo";
+
+const std::string SIM_NAME_TEST = "Sim Foo";
+
+namespace tut
+{
+	// Test wrapper declarations
+	struct iteminfo_test
+	{
+		// Instance to be tested
+		LLItemInfo* mItem;
+
+		// Constructor and destructor of the test wrapper
+		iteminfo_test()
+		{
+			LLUUID id;
+			mItem = new LLItemInfo(X_WORLD_TEST, Y_WORLD_TEST, ITEM_NAME_TEST, id);
+		}
+		~iteminfo_test()
+		{
+			delete mItem;
+		}
+	};
+
+	struct siminfo_test
+	{
+		// Instance to be tested
+		LLSimInfo* mSim;
+
+		// Constructor and destructor of the test wrapper
+		siminfo_test()
+		{
+			U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST);
+			mSim = new LLSimInfo(handle);
+		}
+		~siminfo_test()
+		{
+			delete mSim;
+		}
+	};
+
+	struct worldmap_test
+	{
+		// Instance to be tested
+		LLWorldMap* mWorld;
+
+		// Constructor and destructor of the test wrapper
+		worldmap_test()
+		{
+			mWorld = LLWorldMap::getInstance();
+		}
+		~worldmap_test()
+		{
+			mWorld = NULL;
+		}
+	};
+
+	// Tut templating thingamagic: test group, object and test instance
+	typedef test_group<iteminfo_test> iteminfo_t;
+	typedef iteminfo_t::object iteminfo_object_t;
+	tut::iteminfo_t tut_iteminfo("iteminfo");
+
+	typedef test_group<siminfo_test> siminfo_t;
+	typedef siminfo_t::object siminfo_object_t;
+	tut::siminfo_t tut_siminfo("siminfo");
+
+	typedef test_group<worldmap_test> worldmap_t;
+	typedef worldmap_t::object worldmap_object_t;
+	tut::worldmap_t tut_worldmap("worldmap");
+
+	// ---------------------------------------------------------------------------------------
+	// Test functions
+	// Notes:
+	// * Test as many as you possibly can without requiring a full blown simulation of everything
+	// * The tests are executed in sequence so the test instance state may change between calls
+	// * Remember that you cannot test private methods with tut
+	// ---------------------------------------------------------------------------------------
+
+	// ---------------------------------------------------------------------------------------
+	// Test the LLItemInfo interface
+	// ---------------------------------------------------------------------------------------
+	template<> template<>
+	void iteminfo_object_t::test<1>()
+	{
+		// Test 1 : setCount() / getCount()
+		mItem->setCount(10);
+		ensure("LLItemInfo::setCount() test failed", mItem->getCount() == 10);
+		// Test 2 : setTooltip() / getToolTip()
+		std::string tooltip = TOOLTIP_TEST;
+		mItem->setTooltip(tooltip);
+		ensure("LLItemInfo::setTooltip() test failed", mItem->getToolTip() == TOOLTIP_TEST);
+		// Test 3 : setElevation() / getGlobalPosition()
+		mItem->setElevation(Z_WORLD_TEST);
+		LLVector3d pos = mItem->getGlobalPosition();
+		LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, Z_WORLD_TEST);
+		ensure("LLItemInfo::getGlobalPosition() test failed", pos == ref);
+		// Test 4 : getName()
+		std::string name = mItem->getName();
+		ensure("LLItemInfo::getName() test failed", name == ITEM_NAME_TEST);
+		// Test 5 : isName()
+		ensure("LLItemInfo::isName() test failed", mItem->isName(name));
+		// Test 6 : getUUID()
+		LLUUID id;
+		ensure("LLItemInfo::getUUID() test failed", mItem->getUUID() == id);
+		// Test 7 : getRegionHandle()
+		U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST);
+		ensure("LLItemInfo::getRegionHandle() test failed", mItem->getRegionHandle() == handle);
+	}
+	// ---------------------------------------------------------------------------------------
+	// Test the LLSimInfo interface
+	// ---------------------------------------------------------------------------------------
+	// Test Setters and Accessors methods
+	template<> template<>
+	void siminfo_object_t::test<1>()
+	{
+		// Test 1 : setName() / getName()
+		std::string name = SIM_NAME_TEST;
+		mSim->setName(name);
+		ensure("LLSimInfo::setName() test failed", mSim->getName() == SIM_NAME_TEST);
+		// Test 2 : isName()
+		ensure("LLSimInfo::isName() test failed", mSim->isName(name));
+		// Test 3 : getGlobalPos()
+		LLVector3 local;
+		LLVector3d ref(X_WORLD_TEST, Y_WORLD_TEST, 0.0f);
+		LLVector3d pos = mSim->getGlobalPos(local);
+		ensure("LLSimInfo::getGlobalPos() test failed", pos == ref);
+		// Test 4 : getGlobalOrigin()
+		pos = mSim->getGlobalOrigin();
+		ensure("LLSimInfo::getGlobalOrigin() test failed", pos == ref);
+		// Test 5 : clearImage()
+		try {
+			mSim->clearImage();
+		} catch (...) {
+			fail("LLSimInfo::clearImage() test failed");
+		}
+		// Test 6 : dropImagePriority()
+		try {
+			mSim->dropImagePriority();
+		} catch (...) {
+			fail("LLSimInfo::dropImagePriority() test failed");
+		}
+		// Test 7 : updateAgentCount()
+		try {
+			mSim->updateAgentCount(0.0f);
+		} catch (...) {
+			fail("LLSimInfo::updateAgentCount() test failed");
+		}
+		// Test 8 : getAgentCount()
+		S32 agents = mSim->getAgentCount();
+		ensure("LLSimInfo::getAgentCount() test failed", agents == 0);
+		// Test 9 : setLandForSaleImage() / getLandForSaleImage()
+		LLUUID id;
+		mSim->setLandForSaleImage(id);
+		LLPointer<LLViewerImage> image = mSim->getLandForSaleImage();
+		ensure("LLSimInfo::getLandForSaleImage() test failed", image.isNull());
+		// Test 10 : isPG()
+		mSim->setAccess(SIM_ACCESS_PG);
+		ensure("LLSimInfo::isPG() test failed", mSim->isPG());
+		// Test 11 : isDown()
+		mSim->setAccess(SIM_ACCESS_DOWN);
+		ensure("LLSimInfo::isDown() test failed", mSim->isDown());
+		// Test 12 : Access strings can't be accessed from unit test...
+		//ensure("LLSimInfo::getAccessString() test failed", mSim->getAccessString() == "Offline");
+		// Test 13 : Region strings can't be accessed from unit test...
+		//mSim->setRegionFlags(REGION_FLAGS_SANDBOX);
+		//ensure("LLSimInfo::setRegionFlags() test failed", mSim->getFlagsString() == "Sandbox");
+	}
+	// Test management of LLInfoItem lists
+	template<> template<>
+	void siminfo_object_t::test<2>()
+	{
+		// Test 14 : clearItems()
+		try {
+			mSim->clearItems();
+		} catch (...) {
+			fail("LLSimInfo::clearItems() at init test failed");
+		}
+
+		// Test 15 : Verify that all the lists are empty
+		LLSimInfo::item_info_list_t list;
+		list = mSim->getTeleHub();
+		ensure("LLSimInfo::getTeleHub() empty at init test failed", list.empty());
+		list = mSim->getInfoHub();
+		ensure("LLSimInfo::getInfoHub() empty at init test failed", list.empty());
+		list = mSim->getPGEvent();
+		ensure("LLSimInfo::getPGEvent() empty at init test failed", list.empty());
+		list = mSim->getMatureEvent();
+		ensure("LLSimInfo::getMatureEvent() empty at init test failed", list.empty());
+		list = mSim->getLandForSale();
+		ensure("LLSimInfo::getLandForSale() empty at init test failed", list.empty());
+		list = mSim->getAgentLocation();
+		ensure("LLSimInfo::getAgentLocation() empty at init test failed", list.empty());
+
+		// Create an item to be inserted
+		LLUUID id;
+		LLItemInfo item(X_WORLD_TEST, Y_WORLD_TEST, ITEM_NAME_TEST, id);
+
+		// Insert the item in each list
+		mSim->insertTeleHub(item);
+		mSim->insertInfoHub(item);
+		mSim->insertPGEvent(item);
+		mSim->insertMatureEvent(item);
+		mSim->insertLandForSale(item);
+		mSim->insertAgentLocation(item);
+
+		// Test 16 : Verify that the lists contain 1 item each
+		list = mSim->getTeleHub();
+		ensure("LLSimInfo::insertTeleHub() test failed", list.size() == 1);
+		list = mSim->getInfoHub();
+		ensure("LLSimInfo::insertInfoHub() test failed", list.size() == 1);
+		list = mSim->getPGEvent();
+		ensure("LLSimInfo::insertPGEvent() test failed", list.size() == 1);
+		list = mSim->getMatureEvent();
+		ensure("LLSimInfo::insertMatureEvent() test failed", list.size() == 1);
+		list = mSim->getLandForSale();
+		ensure("LLSimInfo::insertLandForSale() test failed", list.size() == 1);
+		list = mSim->getAgentLocation();
+		ensure("LLSimInfo::insertAgentLocation() test failed", list.size() == 1);
+
+		// Test 17 : clearItems()
+		try {
+			mSim->clearItems();
+		} catch (...) {
+			fail("LLSimInfo::clearItems() at end test failed");
+		}
+
+		// Test 18 : Verify that all the lists are empty again... *except* agent which is persisted!! (on purpose)
+		list = mSim->getTeleHub();
+		ensure("LLSimInfo::getTeleHub() empty after clear test failed", list.empty());
+		list = mSim->getInfoHub();
+		ensure("LLSimInfo::getInfoHub() empty after clear test failed", list.empty());
+		list = mSim->getPGEvent();
+		ensure("LLSimInfo::getPGEvent() empty after clear test failed", list.empty());
+		list = mSim->getMatureEvent();
+		ensure("LLSimInfo::getMatureEvent() empty after clear test failed", list.empty());
+		list = mSim->getLandForSale();
+		ensure("LLSimInfo::getLandForSale() empty after clear test failed", list.empty());
+		list = mSim->getAgentLocation();
+		ensure("LLSimInfo::getAgentLocation() empty after clear test failed", list.size() == 1);
+	}
+
+	// ---------------------------------------------------------------------------------------
+	// Test the LLWorldMap interface
+	// ---------------------------------------------------------------------------------------
+	// Test Setters and Accessors methods
+	template<> template<>
+	void worldmap_object_t::test<1>()
+	{
+		// Test 1 : reset()
+		try {
+			mWorld->reset();
+		} catch (...) {
+			fail("LLWorldMap::reset() at init test failed");
+		}
+		// Test 2 : clearImageRefs()
+		try {
+			mWorld->clearImageRefs();
+		} catch (...) {
+			fail("LLWorldMap::clearImageRefs() test failed");
+		}
+		// Test 3 : dropImagePriorities()
+		try {
+			mWorld->dropImagePriorities();
+		} catch (...) {
+			fail("LLWorldMap::dropImagePriorities() test failed");
+		}
+		// Test 4 : reloadItems()
+		try {
+			mWorld->reloadItems(true);
+		} catch (...) {
+			fail("LLWorldMap::reloadItems() test failed");
+		}
+		// Test 5 : updateRegions()
+		try {
+			mWorld->updateRegions(1000, 1000, 1004, 1004);
+		} catch (...) {
+			fail("LLWorldMap::updateRegions() test failed");
+		}
+		// Test 6 : equalizeBoostLevels()
+ 		try {
+ 			mWorld->equalizeBoostLevels();
+ 		} catch (...) {
+ 			fail("LLWorldMap::equalizeBoostLevels() test failed");
+ 		}
+		// Test 7 : getObjectsTile()
+		try {
+			LLPointer<LLViewerImage> image = mWorld->getObjectsTile((U32)(X_WORLD_TEST/REGION_WIDTH_METERS), (U32)(Y_WORLD_TEST/REGION_WIDTH_METERS), 1);
+			ensure("LLWorldMap::getObjectsTile() failed", image.isNull());
+		} catch (...) {
+			fail("LLWorldMap::getObjectsTile() test failed with exception");
+		}
+	}
+	// Test management of LLSimInfo lists
+	template<> template<>
+	void worldmap_object_t::test<2>()
+	{
+		// Test 8 : reset()
+		try {
+			mWorld->reset();
+		} catch (...) {
+			fail("LLWorldMap::reset() at init test failed");
+		}
+
+		// Test 9 : Verify that all the region list is empty
+		LLWorldMap::sim_info_map_t list;
+		list = mWorld->getRegionMap();
+		ensure("LLWorldMap::getRegionMap() empty at init test failed", list.empty());
+
+		// Test 10 : Insert a region
+		bool success;
+		LLUUID id;
+		std::string name_sim = SIM_NAME_TEST;
+		success = mWorld->insertRegion(	U32(X_WORLD_TEST), 
+						U32(Y_WORLD_TEST), 
+										name_sim,
+										id,
+										SIM_ACCESS_PG,
+										REGION_FLAGS_SANDBOX);
+		list = mWorld->getRegionMap();
+		ensure("LLWorldMap::insertRegion() failed", success && (list.size() == 1));
+
+		// Test 11 : Insert an item in the same region -> number of regions doesn't increase
+		std::string name_item = ITEM_NAME_TEST;
+		success = mWorld->insertItem(	U32(X_WORLD_TEST + REGION_WIDTH_METERS/2),
+						U32(Y_WORLD_TEST + REGION_WIDTH_METERS/2), 
+										name_item,
+										id,
+										MAP_ITEM_LAND_FOR_SALE,
+										0, 0);
+		list = mWorld->getRegionMap();
+		ensure("LLWorldMap::insertItem() in existing region failed", success && (list.size() == 1));
+
+		// Test 12 : Insert an item in another region -> number of regions increases
+		success = mWorld->insertItem(	U32(X_WORLD_TEST + REGION_WIDTH_METERS*2), 
+						U32(Y_WORLD_TEST + REGION_WIDTH_METERS*2), 
+										name_item,
+										id,
+										MAP_ITEM_LAND_FOR_SALE,
+										0, 0);
+		list = mWorld->getRegionMap();
+		ensure("LLWorldMap::insertItem() in unexisting region failed", success && (list.size() == 2));
+
+		// Test 13 : simInfoFromPosGlobal() in region
+		LLVector3d pos1(	X_WORLD_TEST + REGION_WIDTH_METERS*2 + REGION_WIDTH_METERS/2, 
+							Y_WORLD_TEST + REGION_WIDTH_METERS*2 + REGION_WIDTH_METERS/2, 
+							0.0f);
+		LLSimInfo* sim;
+		sim = mWorld->simInfoFromPosGlobal(pos1);
+		ensure("LLWorldMap::simInfoFromPosGlobal() test on existing region failed", sim != NULL);
+
+		// Test 14 : simInfoFromPosGlobal() outside region
+		LLVector3d pos2(	X_WORLD_TEST + REGION_WIDTH_METERS*4 + REGION_WIDTH_METERS/2, 
+							Y_WORLD_TEST + REGION_WIDTH_METERS*4 + REGION_WIDTH_METERS/2, 
+							0.0f);
+		sim = mWorld->simInfoFromPosGlobal(pos2);
+		ensure("LLWorldMap::simInfoFromPosGlobal() test outside region failed", sim == NULL);
+
+		// Test 15 : simInfoFromName()
+		sim = mWorld->simInfoFromName(name_sim);
+		ensure("LLWorldMap::simInfoFromName() test on existing region failed", sim != NULL);
+
+		// Test 16 : simInfoFromHandle()
+		U64 handle = to_region_handle_global(X_WORLD_TEST, Y_WORLD_TEST);
+		sim = mWorld->simInfoFromHandle(handle);
+		ensure("LLWorldMap::simInfoFromHandle() test on existing region failed", sim != NULL);
+
+		// Test 17 : simNameFromPosGlobal()
+		LLVector3d pos3(	X_WORLD_TEST + REGION_WIDTH_METERS/2, 
+							Y_WORLD_TEST + REGION_WIDTH_METERS/2, 
+							0.0f);
+		success = mWorld->simNameFromPosGlobal(pos3, name_sim);
+		ensure("LLWorldMap::simNameFromPosGlobal() test on existing region failed", success && (name_sim == SIM_NAME_TEST));
+		
+		// Test 18 : reset()
+		try {
+			mWorld->reset();
+		} catch (...) {
+			fail("LLWorldMap::reset() at end test failed");
+		}
+
+		// Test 19 : Verify that all the region list is empty
+		list = mWorld->getRegionMap();
+		ensure("LLWorldMap::getRegionMap() empty at end test failed", list.empty());
+	}
+	// Test tracking
+	template<> template<>
+	void worldmap_object_t::test<3>()
+	{
+		// Point to track
+		LLVector3d pos( X_WORLD_TEST + REGION_WIDTH_METERS/2, Y_WORLD_TEST + REGION_WIDTH_METERS/2, Z_WORLD_TEST);
+
+		// Test 20 : no tracking
+		mWorld->cancelTracking();
+		ensure("LLWorldMap::cancelTracking() at begin test failed", mWorld->isTracking() == false);
+
+		// Test 21 : set tracking
+		mWorld->setTracking(pos);
+		ensure("LLWorldMap::setTracking() failed", mWorld->isTracking() && !mWorld->isTrackingValidLocation());
+
+		// Test 22 : set click and commit flags
+		mWorld->setTrackingDoubleClick();
+		ensure("LLWorldMap::setTrackingDoubleClick() failed", mWorld->isTrackingDoubleClick());
+		mWorld->setTrackingCommit();
+		ensure("LLWorldMap::setTrackingCommit() failed", mWorld->isTrackingCommit());
+
+		// Test 23 : in rectangle test
+		bool inRect = mWorld->isTrackingInRectangle(	X_WORLD_TEST, Y_WORLD_TEST,  
+														X_WORLD_TEST + REGION_WIDTH_METERS, 
+														Y_WORLD_TEST + REGION_WIDTH_METERS);
+		ensure("LLWorldMap::isTrackingInRectangle() in rectangle failed", inRect);
+		inRect = mWorld->isTrackingInRectangle(			X_WORLD_TEST + REGION_WIDTH_METERS, 
+														Y_WORLD_TEST + REGION_WIDTH_METERS,  
+														X_WORLD_TEST + 2 * REGION_WIDTH_METERS, 
+														Y_WORLD_TEST + 2 * REGION_WIDTH_METERS);
+		ensure("LLWorldMap::isTrackingInRectangle() outside rectangle failed", !inRect);
+
+		// Test 24 : set tracking to valid and invalid
+		mWorld->setTrackingValid();
+		ensure("LLWorldMap::setTrackingValid() failed", mWorld->isTrackingValidLocation() && !mWorld->isTrackingInvalidLocation());
+		mWorld->setTrackingInvalid();
+		ensure("LLWorldMap::setTrackingInvalid() failed", !mWorld->isTrackingValidLocation() && mWorld->isTrackingInvalidLocation());
+
+		// Test 25 : getTrackedPositionGlobal()
+		LLVector3d res = mWorld->getTrackedPositionGlobal();
+		ensure("LLWorldMap::getTrackedPositionGlobal() failed", res == pos);
+
+		// Test 26 : reset tracking
+		mWorld->cancelTracking();
+		ensure("LLWorldMap::cancelTracking() at end test failed", mWorld->isTracking() == false);
+	}
+}
diff --git a/indra/newview/tests/llworldmipmap_test.cpp b/indra/newview/tests/llworldmipmap_test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9938175c558fa7027f156070f298aa99071cb268
--- /dev/null
+++ b/indra/newview/tests/llworldmipmap_test.cpp
@@ -0,0 +1,176 @@
+/** 
+ * @file llworldmipmap_test.cpp
+ * @author Merov Linden
+ * @date 2009-02-03
+ *
+ * $LicenseInfo:firstyear=2006&license=viewergpl$
+ * 
+ * Copyright (c) 2006-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$
+ */
+
+// Precompiled header: almost always required for newview cpp files
+#include "../llviewerprecompiledheaders.h"
+// Class to test
+#include "../llworldmipmap.h"
+// Dependencies
+#include "../llviewerimagelist.h"
+// Tut header
+#include "../test/lltut.h"
+
+// -------------------------------------------------------------------------------------------
+// Stubbing: Declarations required to link and run the class being tested
+// Notes: 
+// * Add here stubbed implementation of the few classes and methods used in the class to be tested
+// * Add as little as possible (let the link errors guide you)
+// * Do not make any assumption as to how those classes or methods work (i.e. don't copy/paste code)
+// * A simulator for a class can be implemented here. Please comment and document thoroughly.
+
+LLViewerImageList::LLViewerImageList() { }
+LLViewerImageList::~LLViewerImageList() { }
+
+LLViewerImageList gImageList;
+
+LLViewerImage* LLViewerImageList::getImageFromUrl(const std::string& url,
+												   BOOL usemipmaps,
+												   BOOL level_immediate,
+												   LLGLint internal_format,
+												   LLGLenum primary_format, 
+												   const LLUUID& force_id)
+{ return NULL; }
+void LLViewerImage::setBoostLevel(S32 level) { }
+
+// End Stubbing
+// -------------------------------------------------------------------------------------------
+
+// -------------------------------------------------------------------------------------------
+// TUT
+// -------------------------------------------------------------------------------------------
+namespace tut
+{
+	// Test wrapper declaration
+	struct worldmipmap_test
+	{
+		// Derived test class
+		class LLTestWorldMipmap : public LLWorldMipmap
+		{
+			// Put here stubbs of virtual methods we shouldn't call all the way down
+		};
+		// Instance to be tested
+		LLTestWorldMipmap* mMap;
+
+		// Constructor and destructor of the test wrapper
+		worldmipmap_test()
+		{
+			mMap = new LLTestWorldMipmap;
+		}
+		~worldmipmap_test()
+		{
+			delete mMap;
+		}
+	};
+
+	// Tut templating thingamagic: test group, object and test instance
+	typedef test_group<worldmipmap_test> worldmipmap_t;
+	typedef worldmipmap_t::object worldmipmap_object_t;
+	tut::worldmipmap_t tut_worldmipmap("worldmipmap");
+
+	// ---------------------------------------------------------------------------------------
+	// Test functions
+	// Notes:
+	// * Test as many as you possibly can without requiring a full blown simulation of everything
+	// * The tests are executed in sequence so the test instance state may change between calls
+	// * Remember that you cannot test private methods with tut
+	// ---------------------------------------------------------------------------------------
+	// Test static methods
+	// Test 1 : scaleToLevel()
+	template<> template<>
+	void worldmipmap_object_t::test<1>()
+	{
+		S32 level = mMap->scaleToLevel(0.0);
+		ensure("scaleToLevel() test 1 failed", level == LLWorldMipmap::MAP_LEVELS);
+		level = mMap->scaleToLevel(LLWorldMipmap::MAP_TILE_SIZE);
+		ensure("scaleToLevel() test 2 failed", level == 1);
+		level = mMap->scaleToLevel(10 * LLWorldMipmap::MAP_TILE_SIZE);
+		ensure("scaleToLevel() test 3 failed", level == 1);
+	}
+	// Test 2 : globalToMipmap()
+	template<> template<>
+	void worldmipmap_object_t::test<2>()
+	{
+		U32 grid_x, grid_y;
+		mMap->globalToMipmap(1000.f*REGION_WIDTH_METERS, 1000.f*REGION_WIDTH_METERS, 1, &grid_x, &grid_y);
+		ensure("globalToMipmap() test 1 failed", (grid_x == 1000) && (grid_y == 1000));
+		mMap->globalToMipmap(0.0, 0.0, LLWorldMipmap::MAP_LEVELS, &grid_x, &grid_y);
+		ensure("globalToMipmap() test 2 failed", (grid_x == 0) && (grid_y == 0));
+	}
+	// Test 3 : getObjectsTile()
+	template<> template<>
+	void worldmipmap_object_t::test<3>()
+	{
+		// Depends on some inline methods in LLViewerImage... Thinking about how to make this work
+		// LLPointer<LLViewerImage> img = mMap->getObjectsTile(0, 0, 1);
+		// ensure("getObjectsTile() test failed", img.isNull());
+	}
+	// Test 4 : equalizeBoostLevels()
+	template<> template<>
+	void worldmipmap_object_t::test<4>()
+	{
+		try
+		{
+			mMap->equalizeBoostLevels();
+		} 
+		catch (...)
+		{
+			fail("equalizeBoostLevels() test failed");
+		}
+	}
+	// Test 5 : dropBoostLevels()
+	template<> template<>
+	void worldmipmap_object_t::test<5>()
+	{
+		try
+		{
+			mMap->dropBoostLevels();
+		} 
+		catch (...)
+		{
+			fail("dropBoostLevels() test failed");
+		}
+	}
+	// Test 6 : reset()
+	template<> template<>
+	void worldmipmap_object_t::test<6>()
+	{
+		try
+		{
+			mMap->reset();
+		} 
+		catch (...)
+		{
+			fail("reset() test failed");
+		}
+	}
+}
diff --git a/install.xml b/install.xml
index 44224664cae498d630fe64c1ef1eb4f9021739ec..5349932d001f87005187c3666f06362e3d2bc46d 100644
--- a/install.xml
+++ b/install.xml
@@ -132,9 +132,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>6a53b02a07527de680f1336e20f74f08</string>
+            <string>70b51d0cc93c305026e4e2778cde6d19</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.4.0-windows-20080723.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/ares-1.6.0-windows-20090722.tar.bz2</uri>
           </map>
         </map>
       </map>
@@ -254,9 +254,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>8c9d135f0e7cd1fae5681d4595942ee3</string>
+            <string>f6cb20db3ace7f6f25053b7a97b797f4</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.16.4-windows-20090306.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/curl-7.19.6-windows-20090722.tar.bz2</uri>
           </map>
         </map>
       </map>