From dc75235e38e3f2d74476607e6196b26d36955619 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Mon, 13 Dec 2010 21:09:52 -0700
Subject: debug code for SH-639: http requests 3X more in viewer 2.4

---
 indra/newview/lltexturefetch.cpp | 13 ++++++++++++-
 indra/newview/lltexturefetch.h   |  4 ++++
 indra/newview/lltextureview.cpp  |  5 +++--
 3 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index d6d38de225..c1346b6768 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -862,7 +862,7 @@ bool LLTextureFetchWorker::doWork(S32 param)
 			//1, not openning too many file descriptors at the same time;
 			//2, control the traffic of http so udp gets bandwidth.
 			//
-			static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 32 ;
+			static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ;
 			if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE)
 			{
 				return false ; //wait.
@@ -1535,6 +1535,7 @@ LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* image
 	  mImageDecodeThread(imagedecodethread),
 	  mTextureBandwidth(0),
 	  mHTTPTextureBits(0),
+	   mTotalHTTPRequests(0),
 	  mCurlGetRequest(NULL)
 {
 	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
@@ -1678,6 +1679,7 @@ void LLTextureFetch::addToHTTPQueue(const LLUUID& id)
 {
 	LLMutexLock lock(&mNetworkQueueMutex);
 	mHTTPTextureQueue.insert(id);
+	mTotalHTTPRequests++;
 }
 
 void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size)
@@ -1740,6 +1742,15 @@ S32 LLTextureFetch::getNumHTTPRequests()
 	return size ;
 }
 
+U32 LLTextureFetch::getTotalNumHTTPRequests()
+{
+	mNetworkQueueMutex.lock() ;
+	U32 size = mTotalHTTPRequests ;
+	mNetworkQueueMutex.unlock() ;
+
+	return size ;
+}
+
 // call lockQueue() first!
 LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id)
 {
diff --git a/indra/newview/lltexturefetch.h b/indra/newview/lltexturefetch.h
index 796109df06..d25031666b 100644
--- a/indra/newview/lltexturefetch.h
+++ b/indra/newview/lltexturefetch.h
@@ -75,6 +75,7 @@ public:
 	void dump();
 	S32 getNumRequests() ;
 	S32 getNumHTTPRequests() ;
+	U32 getTotalNumHTTPRequests() ;
 	
 	// Public for access by callbacks
 	void lockQueue() { mQueueMutex.lock(); }
@@ -129,6 +130,9 @@ private:
 	LLTextureInfo mTextureInfo;
 
 	U32 mHTTPTextureBits;
+
+	//debug use
+	U32 mTotalHTTPRequests ;
 };
 
 #endif // LL_LLTEXTUREFETCH_H
diff --git a/indra/newview/lltextureview.cpp b/indra/newview/lltextureview.cpp
index b9a15fd1f4..0115115a23 100644
--- a/indra/newview/lltextureview.cpp
+++ b/indra/newview/lltextureview.cpp
@@ -516,6 +516,7 @@ void LLGLTexMemBar::draw()
 	S32 v_offset = (S32)((texture_bar_height + 2.2f) * mTextureView->mNumTextureBars + 2.0f);
 	F32 total_texture_downloaded = (F32)gTotalTextureBytes / (1024 * 1024);
 	F32 total_object_downloaded = (F32)gTotalObjectBytes / (1024 * 1024);
+	U32 total_http_requests = LLAppViewer::getTextureFetch()->getTotalNumHTTPRequests() ;
 	//----------------------------------------------------------------------------
 	LLGLSUIDefault gls_ui;
 	LLColor4 text_color(1.f, 1.f, 1.f, 0.75f);
@@ -526,13 +527,13 @@ void LLGLTexMemBar::draw()
 	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*6,
 											 text_color, LLFontGL::LEFT, LLFontGL::TOP);
 
-	text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB",
+	text = llformat("GL Tot: %d/%d MB Bound: %d/%d MB Raw Tot: %d MB Bias: %.2f Cache: %.1f/%.1f MB Net Tot Tex: %.1f MB Tot Obj: %.1f MB Tot Htp: %d",
 					total_mem,
 					max_total_mem,
 					bound_mem,
 					max_bound_mem,
 					LLImageRaw::sGlobalRawMemory >> 20,	discard_bias,
-					cache_usage, cache_max_usage, total_texture_downloaded, total_object_downloaded);
+					cache_usage, cache_max_usage, total_texture_downloaded, total_object_downloaded, total_http_requests);
 	//, cache_entries, cache_max_entries
 
 	LLFontGL::getFontMonospace()->renderUTF8(text, 0, 0, v_offset + line_height*3,
-- 
cgit v1.2.3


From da244c7cce6b3d84b011a87cbcabffb51abb3fc8 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 14 Dec 2010 12:16:39 -0700
Subject: a try fix for SH-212: crash at
 LLViewerObjectList::removeFromLocalIDTable(LLViewerObject const &)
 [secondlife-bin llviewerobjectlist.cpp] line 173

---
 indra/newview/llcapabilityprovider.h |  2 +-
 indra/newview/llviewerobjectlist.cpp | 22 ++++++++--------------
 indra/newview/llviewerobjectlist.h   |  2 +-
 indra/newview/llviewerregion.cpp     |  6 ++++++
 indra/newview/llviewerregion.h       |  2 +-
 5 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/indra/newview/llcapabilityprovider.h b/indra/newview/llcapabilityprovider.h
index a6e743f625..9d91245597 100644
--- a/indra/newview/llcapabilityprovider.h
+++ b/indra/newview/llcapabilityprovider.h
@@ -46,7 +46,7 @@ public:
     /**
      * Get host to which to send that capability request.
      */
-    virtual LLHost getHost() const = 0;
+    virtual const LLHost& getHost() const = 0;
     /**
      * Describe this LLCapabilityProvider for logging etc.
      */
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index f9bf0543c4..8d5015fd51 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -159,19 +159,13 @@ U64 LLViewerObjectList::getIndex(const U32 local_id,
 	return (((U64)index) << 32) | (U64)local_id;
 }
 
-BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object)
+BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject* objectp)
 {
-	if(object.getRegion())
+	if(objectp && objectp->getRegion())
 	{
-		U32 local_id = object.mLocalID;
-		LLHost region_host = object.getRegion()->getHost();
-		if(!region_host.isOk())
-		{
-			return FALSE ;
-		}
-
-		U32 ip = region_host.getAddress();
-		U32 port = region_host.getPort();
+		U32 local_id = objectp->mLocalID;		
+		U32 ip = objectp->getRegion()->getHost().getAddress();
+		U32 port = objectp->getRegion()->getHost().getPort();
 		U64 ipport = (((U64)ip) << 32) | (U64)port;
 		U32 index = sIPAndPortToIndex[ipport];
 		
@@ -186,7 +180,7 @@ BOOL LLViewerObjectList::removeFromLocalIDTable(const LLViewerObject &object)
 		}
 		
 		// Found existing entry
-		if (iter->second == object.getID())
+		if (iter->second == objectp->getID())
 		{   // Full UUIDs match, so remove the entry
 			sIndexAndLocalIDToUUID.erase(iter);
 			return TRUE;
@@ -460,7 +454,7 @@ void LLViewerObjectList::processObjectUpdate(LLMessageSystem *mesgsys,
 			//			<< ", regionp " << (U32) regionp << ", object region " << (U32) objectp->getRegion()
 			//			<< llendl;
 			//}
-			removeFromLocalIDTable(*objectp);
+			removeFromLocalIDTable(objectp);
 			setUUIDAndLocal(fullid,
 							local_id,
 							gMessageSystem->getSenderIP(),
@@ -849,7 +843,7 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 	//				<< objectp->getRegion()->getHost().getPort() << llendl;
 	//}	
 	
-	removeFromLocalIDTable(*objectp);
+	removeFromLocalIDTable(objectp);
 
 	if (objectp->onActiveList())
 	{
diff --git a/indra/newview/llviewerobjectlist.h b/indra/newview/llviewerobjectlist.h
index eba5584b57..14e5d78839 100644
--- a/indra/newview/llviewerobjectlist.h
+++ b/indra/newview/llviewerobjectlist.h
@@ -161,7 +161,7 @@ public:
 								const U32 ip,
 								const U32 port); // Requires knowledge of message system info!
 
-	static BOOL removeFromLocalIDTable(const LLViewerObject &object);
+	static BOOL removeFromLocalIDTable(const LLViewerObject* objectp);
 	// Used ONLY by the orphaned object code.
 	static U64 getIndex(const U32 local_id, const U32 ip, const U32 port);
 
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index b684206960..e4dcfa1126 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -321,6 +321,12 @@ LLViewerRegion::~LLViewerRegion()
 	std::for_each(mObjectPartition.begin(), mObjectPartition.end(), DeletePointer());
 }
 
+/*virtual*/ 
+const LLHost&	LLViewerRegion::getHost() const				
+{ 
+	return mHost; 
+}
+
 void LLViewerRegion::loadObjectCache()
 {
 	if (mCacheLoaded)
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 8b71998f60..49ee061b71 100644
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -244,7 +244,7 @@ public:
     LLEventPump& getCapAPI() { return mCapabilityListener.getCapAPI(); }
 
     /// implements LLCapabilityProvider
-	virtual LLHost	getHost() const				{ return mHost; }
+	/*virtual*/ const LLHost& getHost() const;
 	const U64 		&getHandle() const 			{ return mHandle; }
 
 	LLSurface		&getLand() const			{ return *mLandp; }
-- 
cgit v1.2.3


From 57065fe5a9521158b79b7a313d6476b8dcaa13a5 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 15 Dec 2010 17:20:58 -0700
Subject: fix for SH-367: mesh viewer lock up: Problem removing object.cache -
 errorcode: 13

---
 indra/llvfs/lldir.cpp        |  13 +-
 indra/newview/llvocache.cpp  | 274 +++++++++++++++++++++++--------------------
 indra/newview/llvocache.h    |   4 +-
 indra/newview/llvovolume.cpp |  10 +-
 4 files changed, 167 insertions(+), 134 deletions(-)

diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp
index 938fb008c9..1a1f52df50 100644
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -101,10 +101,18 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
 		{
 			if (0 != LLFile::remove(fullpath))
 			{
+				retry_count++;
 				result = errno;
 				llwarns << "Problem removing " << fullpath << " - errorcode: "
 						<< result << " attempt " << retry_count << llendl;
-				ms_sleep(1000);
+
+				if(retry_count >= 5)
+				{
+					llwarns << "Failed to remove " << fullpath << llendl ;
+					return count ;
+				}
+
+				ms_sleep(100);
 			}
 			else
 			{
@@ -113,8 +121,7 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
 					llwarns << "Successfully removed " << fullpath << llendl;
 				}
 				break;
-			}
-			retry_count++;
+			}			
 		}
 		count++;
 	}
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 1cb3962daa..bbe637d161 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -325,6 +325,8 @@ void LLVOCache::removeCache(ELLPath location)
 		return ;
 	}
 
+	llinfos << "about to remove the object cache due to settings." << llendl ;
+
 	std::string delem = gDirUtilp->getDirDelimiter();
 	std::string mask = delem + "*";
 	std::string cache_dir = gDirUtilp->getExpandedFilename(location, object_cache_dirname);
@@ -343,6 +345,8 @@ void LLVOCache::removeCache()
 		return ;
 	}
 
+	llinfos << "about to remove the object cache due to some error." << llendl ;
+
 	std::string delem = gDirUtilp->getDirDelimiter();
 	std::string mask = delem + "*";
 	gDirUtilp->deleteFilesInDir(mObjectCacheDirName, mask); 
@@ -351,6 +355,43 @@ void LLVOCache::removeCache()
 	writeCacheHeader();
 }
 
+void LLVOCache::removeEntry(HeaderEntryInfo* entry) 
+{
+	llassert_always(mInitialized) ;
+	if(mReadOnly)
+	{
+		return ;
+	}
+	if(!entry)
+	{
+		return ;
+	}
+
+	header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry) ;
+	if(iter != mHeaderEntryQueue.end())
+	{
+		removeFromCache(entry->mHandle) ;
+		mHandleEntryMap.erase(entry->mHandle) ;		
+		mHeaderEntryQueue.erase(iter) ;
+		delete entry ;
+
+		writeCacheHeader() ;
+		readCacheHeader() ;
+		mNumEntries = mHandleEntryMap.size() ;
+	}
+}
+
+void LLVOCache::removeEntry(U64 handle) 
+{
+	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
+	if(iter == mHandleEntryMap.end()) //no cache
+	{
+		return ;
+	}
+	HeaderEntryInfo* entry = iter->second ;
+	removeEntry(entry) ;
+}
+
 void LLVOCache::clearCacheInMemory()
 {
 	if(!mHeaderEntryQueue.empty()) 
@@ -388,30 +429,6 @@ void LLVOCache::removeFromCache(U64 handle)
 	LLAPRFile::remove(filename, mLocalAPRFilePoolp);	
 }
 
-BOOL LLVOCache::checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) 
-{
-	if(!check_read(apr_file, src, n_bytes))
-	{
-		delete apr_file ;
-		removeCache() ;
-		return FALSE ;
-	}
-
-	return TRUE ;
-}
-
-BOOL LLVOCache::checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) 
-{
-	if(!check_write(apr_file, src, n_bytes))
-	{
-		delete apr_file ;
-		removeCache() ;
-		return FALSE ;
-	}
-
-	return TRUE ;
-}
-
 void LLVOCache::readCacheHeader()
 {
 	if(!mEnabled)
@@ -422,43 +439,45 @@ void LLVOCache::readCacheHeader()
 	//clear stale info.
 	clearCacheInMemory();	
 
+	bool success = true ;
 	if (LLAPRFile::isExist(mHeaderFileName, mLocalAPRFilePoolp))
 	{
-		LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);		
+		LLAPRFile apr_file(mHeaderFileName, APR_READ|APR_BINARY, mLocalAPRFilePoolp);		
 		
 		//read the meta element
-		if(!checkRead(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
-		{
-			return ;
-		}
-
-		HeaderEntryInfo* entry ;
-		mNumEntries = 0 ;
-		while(mNumEntries < MAX_NUM_OBJECT_ENTRIES)
+		success = check_read(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
+		
+		if(success)
 		{
-			entry = new HeaderEntryInfo() ;
-			if(!checkRead(apr_file, entry, sizeof(HeaderEntryInfo)))
-			{
-				delete entry ;			
-				return ;
-			}
-			else if(!entry->mTime) //end of the cache.
+			HeaderEntryInfo* entry ;
+			mNumEntries = 0 ;
+			while(mNumEntries < MAX_NUM_OBJECT_ENTRIES)
 			{
-				delete entry ;
-				return ;
+				entry = new HeaderEntryInfo() ;
+				success = check_read(&apr_file, entry, sizeof(HeaderEntryInfo));
+				
+				if(!success || !entry->mTime) //failed or end of the cache
+				{
+					delete entry ; 
+					break ;
+				}				
+
+				entry->mIndex = mNumEntries++ ;
+				mHeaderEntryQueue.insert(entry) ;
+				mHandleEntryMap[entry->mHandle] = entry ;
 			}
-
-			entry->mIndex = mNumEntries++ ;
-			mHeaderEntryQueue.insert(entry) ;
-			mHandleEntryMap[entry->mHandle] = entry ;
 		}
-
-		delete apr_file ;
 	}
 	else
 	{
 		writeCacheHeader() ;
 	}
+
+	if(!success)
+	{
+		removeCache() ; //failed to read header, clear the cache
+	}
+	return ;
 }
 
 void LLVOCache::writeCacheHeader()
@@ -468,48 +487,47 @@ void LLVOCache::writeCacheHeader()
 		return ;
 	}	
 
-	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
-
-	//write the meta element
-	if(!checkWrite(apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)))
+	bool success = true ;
 	{
-		return ;
-	}
+		LLAPRFile apr_file(mHeaderFileName, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
 
-	mNumEntries = 0 ;
-	for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; iter != mHeaderEntryQueue.end(); ++iter)
-	{
-		(*iter)->mIndex = mNumEntries++ ;
-		if(!checkWrite(apr_file, (void*)*iter, sizeof(HeaderEntryInfo)))
+		//write the meta element
+		success = check_write(&apr_file, &mMetaInfo, sizeof(HeaderMetaInfo)) ;
+
+		mNumEntries = 0 ;	
+		for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter)
 		{
-			return ;
+			(*iter)->mIndex = mNumEntries++ ;
+			success = check_write(&apr_file, (void*)*iter, sizeof(HeaderEntryInfo));
 		}
-	}
-
-	mNumEntries = mHeaderEntryQueue.size() ;
-	if(mNumEntries < MAX_NUM_OBJECT_ENTRIES)
-	{
-		HeaderEntryInfo* entry = new HeaderEntryInfo() ;
-		for(S32 i = mNumEntries ; i < MAX_NUM_OBJECT_ENTRIES ; i++)
+	
+		mNumEntries = mHeaderEntryQueue.size() ;
+		if(success && mNumEntries < MAX_NUM_OBJECT_ENTRIES)
 		{
-			//fill the cache with the default entry.
-			if(!checkWrite(apr_file, entry, sizeof(HeaderEntryInfo)))
+			HeaderEntryInfo* entry = new HeaderEntryInfo() ;
+			for(S32 i = mNumEntries ; success && i < MAX_NUM_OBJECT_ENTRIES ; i++)
 			{
-				mReadOnly = TRUE ; //disable the cache.
-				return ;
+				//fill the cache with the default entry.
+				success = check_write(&apr_file, entry, sizeof(HeaderEntryInfo)) ;			
 			}
+			delete entry ;
 		}
-		delete entry ;
 	}
-	delete apr_file ;
+
+	if(!success)
+	{
+		clearCacheInMemory() ;
+		mReadOnly = TRUE ; //disable the cache.
+	}
+	return ;
 }
 
 BOOL LLVOCache::updateEntry(const HeaderEntryInfo* entry)
 {
-	LLAPRFile* apr_file = new LLAPRFile(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
-	apr_file->seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
+	LLAPRFile apr_file(mHeaderFileName, APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+	apr_file.seek(APR_SET, entry->mIndex * sizeof(HeaderEntryInfo) + sizeof(HeaderMetaInfo)) ;
 
-	return checkWrite(apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
+	return check_write(&apr_file, (void*)entry, sizeof(HeaderEntryInfo)) ;
 }
 
 void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) 
@@ -526,43 +544,51 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 		return ;
 	}
 
-	std::string filename;
-	getObjectCacheFilename(handle, filename);
-	LLAPRFile* apr_file = new LLAPRFile(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
-
-	LLUUID cache_id ;
-	if(!checkRead(apr_file, cache_id.mData, UUID_BYTES))
-	{
-		return ;
-	}
-	if(cache_id != id)
+	bool success = true ;
 	{
-		llinfos << "Cache ID doesn't match for this region, discarding"<< llendl;
-
-		delete apr_file ;
-		return ;
-	}
+		std::string filename;
+		getObjectCacheFilename(handle, filename);
+		LLAPRFile apr_file(filename, APR_READ|APR_BINARY, mLocalAPRFilePoolp);
+	
+		LLUUID cache_id ;
+		success = check_read(&apr_file, cache_id.mData, UUID_BYTES) ;
+	
+		if(success)
+		{		
+			if(cache_id != id)
+			{
+				llinfos << "Cache ID doesn't match for this region, discarding"<< llendl;
+				success = false ;
+			}
 
-	S32 num_entries;
-	if(!checkRead(apr_file, &num_entries, sizeof(S32)))
-	{
-		return ;
+			if(success)
+			{
+				S32 num_entries;
+				success = check_read(&apr_file, &num_entries, sizeof(S32)) ;
+	
+				for (S32 i = 0; success && i < num_entries; i++)
+				{
+					LLVOCacheEntry* entry = new LLVOCacheEntry(&apr_file);
+					if (!entry->getLocalID())
+					{
+						llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
+						delete entry ;
+						success = false ;
+					}
+					cache_entry_map[entry->getLocalID()] = entry;
+				}
+			}
+		}		
 	}
 	
-	for (S32 i = 0; i < num_entries; i++)
+	if(!success)
 	{
-		LLVOCacheEntry* entry = new LLVOCacheEntry(apr_file);
-		if (!entry->getLocalID())
+		if(cache_entry_map.empty())
 		{
-			llwarns << "Aborting cache file load for " << filename << ", cache file corruption!" << llendl;
-			delete entry ;
-			break;
+			removeEntry(iter->second) ;
 		}
-		cache_entry_map[entry->getLocalID()] = entry;
 	}
-	num_entries = cache_entry_map.size() ;
 
-	delete apr_file ;
 	return ;
 }
 	
@@ -636,33 +662,31 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
 	}
 
 	//write to cache file
-	std::string filename;
-	getObjectCacheFilename(handle, filename);
-	LLAPRFile* apr_file = new LLAPRFile(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
-	
-	if(!checkWrite(apr_file, (void*)id.mData, UUID_BYTES))
-	{
-		return ;
-	}
-
-	S32 num_entries = cache_entry_map.size() ;
-	if(!checkWrite(apr_file, &num_entries, sizeof(S32)))
+	bool success = true ;
 	{
-		return ;
+		std::string filename;
+		getObjectCacheFilename(handle, filename);
+		LLAPRFile apr_file(filename, APR_CREATE|APR_WRITE|APR_BINARY, mLocalAPRFilePoolp);
+	
+		success = check_write(&apr_file, (void*)id.mData, UUID_BYTES) ;
+	
+		if(success)
+		{
+			S32 num_entries = cache_entry_map.size() ;
+			success = check_write(&apr_file, &num_entries, sizeof(S32));
+	
+			for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); success && iter != cache_entry_map.end(); ++iter)
+			{
+				success = iter->second->writeToFile(&apr_file) ;
+			}
+		}
 	}
 
-	for (LLVOCacheEntry::vocache_entry_map_t::const_iterator iter = cache_entry_map.begin(); iter != cache_entry_map.end(); ++iter)
+	if(!success)
 	{
-		if(!iter->second->writeToFile(apr_file))
-		{
-			//failed
-			delete apr_file ;
-			removeCache() ;
-			return ;
-		}
+		removeEntry(entry) ;
 	}
 
-	delete apr_file ;
 	return ;
 }
 
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index ed2bc8bafe..6453886bc5 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -111,6 +111,7 @@ public:
 
 	void readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::vocache_entry_map_t& cache_entry_map) ;
 	void writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry::vocache_entry_map_t& cache_entry_map, BOOL dirty_cache) ;
+	void removeEntry(U64 handle) ;
 
 	void setReadOnly(BOOL read_only) {mReadOnly = read_only;} 
 
@@ -123,10 +124,9 @@ private:
 	void writeCacheHeader();
 	void clearCacheInMemory();
 	void removeCache() ;
+	void removeEntry(HeaderEntryInfo* entry) ;
 	void purgeEntries();
 	BOOL updateEntry(const HeaderEntryInfo* entry);
-	BOOL checkRead(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
-	BOOL checkWrite(LLAPRFile* apr_file, void* src, S32 n_bytes) ;
 	
 private:
 	BOOL                 mEnabled;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 761e12020b..858e0321e1 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -388,10 +388,12 @@ U32 LLVOVolume::processUpdateMessage(LLMessageSystem *mesgsys,
 				// There's something bogus in the data that we're unpacking.
 				dp->dumpBufferToLog();
 				llwarns << "Flushing cache files" << llendl;
-				std::string mask;
-				mask = gDirUtilp->getDirDelimiter() + "*.slc";
-				gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""), mask);
-// 				llerrs << "Bogus TE data in " << getID() << ", crashing!" << llendl;
+
+				if(LLVOCache::hasInstance() && getRegion())
+				{
+					LLVOCache::getInstance()->removeEntry(getRegion()->getHandle()) ;
+				}
+				
 				llwarns << "Bogus TE data in " << getID() << llendl;
 			}
 			else 
-- 
cgit v1.2.3


From ac71884a446170a32ec557d5e9f85d0a73e8fa23 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 15 Dec 2010 17:34:18 -0700
Subject: fix for SH-446: viewer crashed after clearing cache and relogging

---
 indra/newview/llvocache.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index bbe637d161..cb48d1db73 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -291,6 +291,7 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
 	{
 		return ;
 	}
+	mInitialized = TRUE ;
 
 	setDirNames(location);
 	if (!mReadOnly)
@@ -301,8 +302,7 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
 			     MAX_NUM_OBJECT_ENTRIES, NUM_ENTRIES_TO_PURGE);
 
 	mMetaInfo.mVersion = cache_version;
-	readCacheHeader();
-	mInitialized = TRUE ;
+	readCacheHeader();	
 
 	if(mMetaInfo.mVersion != cache_version) 
 	{
-- 
cgit v1.2.3


From f137dc0c2f928b81a90e59c58adefeb56f21393e Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Thu, 16 Dec 2010 17:13:07 -0700
Subject: fix for SH-445: debug settings -> "CacheNumberOfRegionsForObjects"
 does not limit the number of object cache files

---
 indra/newview/llvocache.cpp | 86 +++++++++++++++++++++++++++++----------------
 indra/newview/llvocache.h   |  9 +++--
 2 files changed, 62 insertions(+), 33 deletions(-)

diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index cb48d1db73..b53f5c7a20 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -225,7 +225,8 @@ BOOL LLVOCacheEntry::writeToFile(LLAPRFile* apr_file) const
 static const char OBJECT_CACHE_FILENAME[] = "objects_%d_%d.slc";
 
 const U32 MAX_NUM_OBJECT_ENTRIES = 128 ;
-const U32 NUM_ENTRIES_TO_PURGE = 16 ;
+const U32 MIN_ENTRIES_TO_PURGE = 16 ;
+const U32 INVALID_TIME = 0 ;
 const char* object_cache_dirname = "objectcache";
 const char* header_filename = "object.cache";
 
@@ -298,8 +299,7 @@ void LLVOCache::initCache(ELLPath location, U32 size, U32 cache_version)
 	{
 		LLFile::mkdir(mObjectCacheDirName);
 	}	
-	mCacheSize = llclamp(size,
-			     MAX_NUM_OBJECT_ENTRIES, NUM_ENTRIES_TO_PURGE);
+	mCacheSize = llclamp(size, MIN_ENTRIES_TO_PURGE, MAX_NUM_OBJECT_ENTRIES);
 
 	mMetaInfo.mVersion = cache_version;
 	readCacheHeader();	
@@ -369,14 +369,12 @@ void LLVOCache::removeEntry(HeaderEntryInfo* entry)
 
 	header_entry_queue_t::iterator iter = mHeaderEntryQueue.find(entry) ;
 	if(iter != mHeaderEntryQueue.end())
-	{
-		removeFromCache(entry->mHandle) ;
+	{		
 		mHandleEntryMap.erase(entry->mHandle) ;		
 		mHeaderEntryQueue.erase(iter) ;
+		removeFromCache(entry) ;
 		delete entry ;
 
-		writeCacheHeader() ;
-		readCacheHeader() ;
 		mNumEntries = mHandleEntryMap.size() ;
 	}
 }
@@ -417,7 +415,7 @@ void LLVOCache::getObjectCacheFilename(U64 handle, std::string& filename)
 	return ;
 }
 
-void LLVOCache::removeFromCache(U64 handle)
+void LLVOCache::removeFromCache(HeaderEntryInfo* entry)
 {
 	if(mReadOnly)
 	{
@@ -425,8 +423,11 @@ void LLVOCache::removeFromCache(U64 handle)
 	}
 
 	std::string filename;
-	getObjectCacheFilename(handle, filename);
-	LLAPRFile::remove(filename, mLocalAPRFilePoolp);	
+	getObjectCacheFilename(entry->mHandle, filename);
+	LLAPRFile::remove(filename, mLocalAPRFilePoolp);
+
+	entry->mTime = INVALID_TIME ;
+	updateEntry(entry) ; //update the head file.
 }
 
 void LLVOCache::readCacheHeader()
@@ -449,24 +450,49 @@ void LLVOCache::readCacheHeader()
 		
 		if(success)
 		{
-			HeaderEntryInfo* entry ;
+			HeaderEntryInfo* entry = NULL ;
 			mNumEntries = 0 ;
-			while(mNumEntries < MAX_NUM_OBJECT_ENTRIES)
+			U32 num_read = 0 ;
+			while(num_read++ < MAX_NUM_OBJECT_ENTRIES)
 			{
-				entry = new HeaderEntryInfo() ;
+				if(!entry)
+				{
+					entry = new HeaderEntryInfo() ;
+				}
 				success = check_read(&apr_file, entry, sizeof(HeaderEntryInfo));
-				
-				if(!success || !entry->mTime) //failed or end of the cache
+								
+				if(!success) //failed
 				{
-					delete entry ; 
+					delete entry ;
+					entry = NULL ;
 					break ;
-				}				
+				}
+				else if(entry->mTime == INVALID_TIME)
+				{
+					continue ; //an empty entry
+				}
 
 				entry->mIndex = mNumEntries++ ;
 				mHeaderEntryQueue.insert(entry) ;
 				mHandleEntryMap[entry->mHandle] = entry ;
+				entry = NULL ;
+			}
+			if(entry)
+			{
+				delete entry ;
 			}
 		}
+
+		//---------
+		//debug code
+		//----------
+		//std::string name ;
+		//for(header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ; success && iter != mHeaderEntryQueue.end(); ++iter)
+		//{
+		//	getObjectCacheFilename((*iter)->mHandle, name) ;
+		//	llinfos << name << llendl ;
+		//}
+		//-----------
 	}
 	else
 	{
@@ -505,6 +531,7 @@ void LLVOCache::writeCacheHeader()
 		if(success && mNumEntries < MAX_NUM_OBJECT_ENTRIES)
 		{
 			HeaderEntryInfo* entry = new HeaderEntryInfo() ;
+			entry->mTime = INVALID_TIME ;
 			for(S32 i = mNumEntries ; success && i < MAX_NUM_OBJECT_ENTRIES ; i++)
 			{
 				//fill the cache with the default entry.
@@ -594,20 +621,17 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 	
 void LLVOCache::purgeEntries()
 {
-	U32 limit = mCacheSize - NUM_ENTRIES_TO_PURGE ;
-	while(mHeaderEntryQueue.size() > limit)
+	while(mHeaderEntryQueue.size() >= mCacheSize)
 	{
 		header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ;
 		HeaderEntryInfo* entry = *iter ;
-		
-		removeFromCache(entry->mHandle) ;
+				
 		mHandleEntryMap.erase(entry->mHandle) ;		
 		mHeaderEntryQueue.erase(iter) ;
+		removeFromCache(entry) ;
 		delete entry ;
 	}
 
-	writeCacheHeader() ;
-	readCacheHeader() ;
 	mNumEntries = mHandleEntryMap.size() ;
 }
 
@@ -623,16 +647,15 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
 	{
 		return ;
 	}
+	if(mNumEntries >= mCacheSize)
+	{
+		purgeEntries() ;
+	}
 
 	HeaderEntryInfo* entry;
 	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
 	if(iter == mHandleEntryMap.end()) //new entry
-	{		
-		if(mNumEntries >= mCacheSize)
-		{
-			purgeEntries() ;
-		}
-		
+	{				
 		entry = new HeaderEntryInfo();
 		entry->mHandle = handle ;
 		entry->mTime = time(NULL) ;
@@ -642,11 +665,12 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
 	}
 	else
 	{
-		entry = iter->second ;
-		entry->mTime = time(NULL) ;
+		entry = iter->second ;		
 
 		//resort
 		mHeaderEntryQueue.erase(entry) ;
+		
+		entry->mTime = time(NULL) ;
 		mHeaderEntryQueue.insert(entry) ;
 	}
 
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 6453886bc5..1070fcaae9 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -95,7 +95,12 @@ private:
 	{
 		bool operator()(const HeaderEntryInfo* lhs, const HeaderEntryInfo* rhs) const
 		{
-			return lhs->mTime < rhs->mTime; // older entry in front of queue (set)
+			if(lhs->mTime == rhs->mTime) 
+			{
+				return lhs < rhs ;
+			}
+			
+			return lhs->mTime < rhs->mTime ; // older entry in front of queue (set)
 		}
 	};
 	typedef std::set<HeaderEntryInfo*, header_entry_less> header_entry_queue_t;
@@ -119,7 +124,7 @@ private:
 	void setDirNames(ELLPath location);	
 	// determine the cache filename for the region from the region handle	
 	void getObjectCacheFilename(U64 handle, std::string& filename);
-	void removeFromCache(U64 handle);
+	void removeFromCache(HeaderEntryInfo* entry);
 	void readCacheHeader();
 	void writeCacheHeader();
 	void clearCacheInMemory();
-- 
cgit v1.2.3


From 8dad2e56f3d87769a47e9b89455274a130267cc9 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Thu, 23 Dec 2010 11:42:17 -0700
Subject: fix for SH-416: crash at LLFace::getGeometryVolume line 1003

---
 indra/llprimitive/lltextureentry.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index 3c1d031ff5..861bde5c89 100644
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -403,7 +403,7 @@ S32 LLTextureEntry::setOffsetT(F32 t)
 
 S32 LLTextureEntry::setRotation(F32 theta)
 {
-	if (mRotation != theta)
+	if (mRotation != theta && llfinite(theta))
 	{
 		mRotation = theta;
 		return TEM_CHANGE_TEXTURE;
-- 
cgit v1.2.3


From 6150e4ed7cf86a2afc0061ba89b0cb049d6f036e Mon Sep 17 00:00:00 2001
From: Jonathan Yap <none@none>
Date: Wed, 29 Dec 2010 18:25:40 -0500
Subject: VWR-24347 Fix reversion--allow VS2005 Express user to specify
 location of msvc* files

---
 indra/cmake/Copy3rdPartyLibs.cmake | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 176ae9787e..1b08c3fd2e 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -66,6 +66,7 @@ if(WINDOWS)
 if (MSVC80)
     FIND_PATH(debug_msvc8_redist_path msvcr80d.dll
         PATHS
+		${MSVC_DEBUG_REDIST_PATH}
          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/Debug_NonRedist/x86/Microsoft.VC80.DebugCRT
         NO_DEFAULT_PATH
         NO_DEFAULT_PATH
@@ -90,6 +91,7 @@ if (MSVC80)
 
     FIND_PATH(release_msvc8_redist_path msvcr80.dll
         PATHS
+		${MSVC_REDIST_PATH}
          [HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0\\Setup\\VC;ProductDir]/redist/x86/Microsoft.VC80.CRT
         NO_DEFAULT_PATH
         NO_DEFAULT_PATH
-- 
cgit v1.2.3


From d0b5e6b0b4acebd1b11685dea290b830957ba9dc Mon Sep 17 00:00:00 2001
From: Jonathan Yap <none@none>
Date: Thu, 6 Jan 2011 06:07:11 -0500
Subject: STORM-829 Viewer 2 does not parse /me in object Instant Messages

---
 doc/contributions.txt             | 3 ++-
 indra/newview/llviewermessage.cpp | 8 ++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 0954704c26..4e6c662e4f 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -370,8 +370,9 @@ Jonathan Yap
 	STORM-679
 	STORM-737
 	STORM-726
-	VWR-17801
 	STORM-785
+	STORM-829
+	VWR-17801
 Kage Pixel
 	VWR-11
 Ken March
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 7dc5d96689..7f7855c08c 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -2746,6 +2746,14 @@ void process_improved_im(LLMessageSystem *msg, void **user_data)
 				LLSD args;
 				args["slurl"] = location;
 				args["type"] = LLNotificationsUI::NT_NEARBYCHAT;
+
+				// Look for IRC-style emotes here so object name formatting is correct
+				std::string prefix = message.substr(0, 4);
+				if (prefix == "/me " || prefix == "/me'")
+				{
+					chat.mChatStyle = CHAT_STYLE_IRC;
+				}
+
 				LLNotificationsUI::LLNotificationManager::instance().onChat(chat, args);
 			}
 
-- 
cgit v1.2.3


From ba1266043f36fd0a576fe888120bbb3f7b7dc2f3 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Fri, 7 Jan 2011 15:04:36 -0700
Subject: trivial: for VWR-22353: remove debug code for EXT-6791.

---
 indra/llrender/llimagegl.cpp       | 10 ----------
 indra/newview/lldynamictexture.cpp | 10 ----------
 2 files changed, 20 deletions(-)

diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 65940cb067..e8e98211f1 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1063,16 +1063,6 @@ BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_
 {
 	if (gGL.getTexUnit(0)->bind(this, false, true))
 	{
-		if(gGLManager.mDebugGPU)
-		{
-			llinfos << "Calling glCopyTexSubImage2D(...)" << llendl ;
-			checkTexSize(true) ;
-			llcallstacks << fb_x << " : " << fb_y << " : " << x_pos << " : " << y_pos << " : " << width << " : " << height <<
-				" : " << (S32)mComponents << llcallstacksendl ;
-
-			log_glerror() ;
-		}
-
 		glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
 		mGLTextureCreated = true;
 		stop_glerror();
diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp
index a3d2941114..f781d5f3ff 100644
--- a/indra/newview/lldynamictexture.cpp
+++ b/indra/newview/lldynamictexture.cpp
@@ -177,10 +177,6 @@ void LLViewerDynamicTexture::postRender(BOOL success)
 				generateGLTexture() ;
 			}
 
-			if(gGLManager.mDebugGPU)
-			{
-				LLGLState::dumpStates() ;
-			}
 			success = mGLTexturep->setSubImageFromFrameBuffer(0, 0, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight);
 		}
 	}
@@ -220,12 +216,6 @@ BOOL LLViewerDynamicTexture::updateAllInstances()
 			LLViewerDynamicTexture *dynamicTexture = *iter;
 			if (dynamicTexture->needsRender())
 			{				
-				if(gGLManager.mDebugGPU)
-				{				
-					llinfos << "class type: " << (S32)dynamicTexture->getType() << llendl;
-					LLGLState::dumpStates() ;
-				}
-
 				glClear(GL_DEPTH_BUFFER_BIT);
 				gDepthDirty = TRUE;
 								
-- 
cgit v1.2.3


From 3703f0bb0d7cd20c801d88cb77632c239010d26b Mon Sep 17 00:00:00 2001
From: Jonathan Yap <none@none>
Date: Wed, 12 Jan 2011 08:24:38 -0500
Subject: STORM-844 "More" should be "Less" when Media Control is open

---
 doc/contributions.txt                                     | 7 ++++---
 indra/newview/skins/default/xui/en/panel_nearby_media.xml | 6 +++---
 2 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 9266ae3c5b..0d7bed2f78 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -366,15 +366,16 @@ JB Kraft
 Joghert LeSabre
 	VWR-64
 Jonathan Yap
-	STORM-596
 	STORM-523
+	STORM-596
 	STORM-616
 	STORM-679
-	STORM-737
 	STORM-726
+	STORM-737
+	STORM-785
 	STORM-812
+	STORM-844
 	VWR-17801
-	STORM-785
 Kage Pixel
 	VWR-11
 Ken March
diff --git a/indra/newview/skins/default/xui/en/panel_nearby_media.xml b/indra/newview/skins/default/xui/en/panel_nearby_media.xml
index 8c13ced8f3..aac3608e13 100644
--- a/indra/newview/skins/default/xui/en/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/en/panel_nearby_media.xml
@@ -69,7 +69,7 @@
 		width="66"
 		height="22"
 		label="More &gt;&gt;"
-		label_selected="Less &lt;&lt;">
+		label_selected="More &gt;&gt;">
 	  <button.commit_callback
 		  function="MediaListCtrl.MoreLess" />
 	</button>
@@ -81,8 +81,8 @@
 		right="-8"
 		width="66"
 		height="22"
-		label="More &gt;&gt;"
-		label_selected="Less &lt;&lt;">
+		label="&lt;&lt; Less"
+		label_selected="&lt;&lt; Less">
       <button.commit_callback
         function="MediaListCtrl.MoreLess" />
   </button>
-- 
cgit v1.2.3


From e27ae655c6859f947d92c789f189b52940dae877 Mon Sep 17 00:00:00 2001
From: Jonathan Yap <none@none>
Date: Wed, 12 Jan 2011 10:37:15 -0500
Subject: STORM-844 Minor adjustment to contributions.txt

---
 doc/contributions.txt | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 0d7bed2f78..f4831a1947 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -366,16 +366,16 @@ JB Kraft
 Joghert LeSabre
 	VWR-64
 Jonathan Yap
-	STORM-523
 	STORM-596
+	STORM-523
 	STORM-616
 	STORM-679
-	STORM-726
 	STORM-737
-	STORM-785
+	STORM-726
 	STORM-812
-	STORM-844
 	VWR-17801
+	STORM-785
+	STORM-844
 Kage Pixel
 	VWR-11
 Ken March
-- 
cgit v1.2.3


From 6a3d06deca73683514d4668f78adf684d760708c Mon Sep 17 00:00:00 2001
From: Jonathan Yap <none@none>
Date: Sun, 16 Jan 2011 12:10:44 -0500
Subject: STORM-844 Better way of doing "More" should be "Less" when Media
 Control is open thanks to Twisted Laws

---
 doc/contributions.txt                                    |  1 +
 indra/newview/llpanelnearbymedia.cpp                     |  5 ++---
 .../newview/skins/default/xui/en/panel_nearby_media.xml  | 16 ++--------------
 3 files changed, 5 insertions(+), 17 deletions(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index f4831a1947..42e030ac66 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -755,6 +755,7 @@ Twisted Laws
 	SNOW-352
 	STORM-466
 	STORM-467
+	STORM-844
 Vadim Bigbear
 	VWR-2681
 Vector Hastings
diff --git a/indra/newview/llpanelnearbymedia.cpp b/indra/newview/llpanelnearbymedia.cpp
index fcc67d6840..14e39f2c48 100644
--- a/indra/newview/llpanelnearbymedia.cpp
+++ b/indra/newview/llpanelnearbymedia.cpp
@@ -958,7 +958,7 @@ void LLPanelNearByMedia::onAdvancedButtonClick()
 
 void LLPanelNearByMedia::onMoreLess()
 {
-	bool is_more = getChild<LLUICtrl>("more_btn")->getVisible();
+	bool is_more = getChild<LLButton>("more_btn")->getToggleState();
 	mNearbyMediaPanel->setVisible(is_more);
 
 	// enable resizing when expanded
@@ -969,8 +969,7 @@ void LLPanelNearByMedia::onMoreLess()
 
 	setShape(new_rect);
 
-	getChild<LLUICtrl>("more_btn")->setVisible(!is_more);
-	getChild<LLUICtrl>("less_btn")->setVisible(is_more);
+	getChild<LLUICtrl>("more_btn")->setVisible(true);
 }
 
 void LLPanelNearByMedia::updateControls()
diff --git a/indra/newview/skins/default/xui/en/panel_nearby_media.xml b/indra/newview/skins/default/xui/en/panel_nearby_media.xml
index aac3608e13..9bd60b935f 100644
--- a/indra/newview/skins/default/xui/en/panel_nearby_media.xml
+++ b/indra/newview/skins/default/xui/en/panel_nearby_media.xml
@@ -68,24 +68,12 @@
 		right="-8"
 		width="66"
 		height="22"
+		is_toggle="true"
 		label="More &gt;&gt;"
-		label_selected="More &gt;&gt;">
+		label_selected="&lt;&lt; Less">
 	  <button.commit_callback
 		  function="MediaListCtrl.MoreLess" />
 	</button>
-  <button
-		name="less_btn"
-		follows="right"
-		tool_tip="Advanced Controls"
-		top_delta="0"
-		right="-8"
-		width="66"
-		height="22"
-		label="&lt;&lt; Less"
-		label_selected="&lt;&lt; Less">
-      <button.commit_callback
-        function="MediaListCtrl.MoreLess" />
-  </button>
   </panel>
   <panel
 	  name="nearby_media_panel"
-- 
cgit v1.2.3


From feb5fbc66e0a4941489a7c0d92cb51341a1c4f39 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 18 Jan 2011 10:41:37 -0700
Subject: debug tool to show texture info for SH-659: small textures not
 loaded.

---
 indra/newview/app_settings/settings.xml            | 13 +++++-
 indra/newview/llviewerwindow.cpp                   | 54 ++++++++++++++++++++--
 indra/newview/skins/default/xui/en/menu_viewer.xml | 10 ++++
 3 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7b3f50e4e2..c7302ea607 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1851,10 +1851,21 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
+  <key>DebugShowTextureInfo</key>
+    <map>
+      <key>Comment</key>
+      <string>Show inertested texture info</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
   <key>DebugShowTime</key>
     <map>
       <key>Comment</key>
-      <string>Show depth buffer contents</string>
+      <string>Show time info</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index fda6f316e6..ed0789bc50 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -296,13 +296,15 @@ private:
 	line_list_t mLineList;
 	LLColor4 mTextColor;
 	
-public:
-	LLDebugText(LLViewerWindow* window) : mWindow(window) {}
-	
 	void addText(S32 x, S32 y, const std::string &text) 
 	{
 		mLineList.push_back(Line(text, x, y));
 	}
+	
+	void clearText() { mLineList.clear(); }
+	
+public:
+	LLDebugText(LLViewerWindow* window) : mWindow(window) {}
 
 	void update()
 	{
@@ -323,6 +325,8 @@ public:
 		U32 ypos = 64;
 		const U32 y_inc = 20;
 
+		clearText();
+		
 		if (gSavedSettings.getBOOL("DebugShowTime"))
 		{
 			const U32 y_inc2 = 15;
@@ -601,6 +605,50 @@ public:
 				ypos += y_inc;
 			}
 		}
+		
+		if (gSavedSettings.getBOOL("DebugShowTextureInfo"))
+		{
+			LLViewerObject* objectp = NULL ;
+			//objectp = = gAgentCamera.getFocusObject();
+			
+			LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
+			if (nodep)
+			{
+				objectp = nodep->getObject();			
+			}
+			if (objectp && !objectp->isDead())
+			{
+				S32 num_faces = objectp->mDrawable->getNumFaces() ;
+				
+				for(S32 i = 0 ; i < num_faces; i++)
+				{
+					LLFace* facep = objectp->mDrawable->getFace(i) ;
+					if(facep)
+					{
+						//addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0],
+						//		facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1]));
+						//ypos += y_inc;
+						
+						addText(xpos, ypos, llformat("v_size: %.3f:  p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea()));
+						ypos += y_inc;
+						
+						//const LLTextureEntry *tep = facep->getTextureEntry();
+						//if(tep)
+						//{
+						//	addText(xpos, ypos, llformat("scale_s: %.3f:  scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ;
+						//	ypos += y_inc;
+						//}
+						
+						LLViewerTexture* tex = facep->getTexture() ;
+						if(tex)
+						{
+							addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize()));
+							ypos += y_inc;
+						}
+					}
+				}
+			}
+		}
 	}
 
 	void draw()
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index b36cf13f1b..e2a3067796 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1916,6 +1916,16 @@
                 <menu_item_check.on_click
                  function="ToggleControl"
                  parameter="DebugShowRenderInfo" />
+            </menu_item_check>
+			<menu_item_check
+             label="Show Texture Info"
+             name="Show Texture Info">
+                <menu_item_check.on_check
+                 function="CheckControl"
+                 parameter="DebugShowTextureInfo" />
+                <menu_item_check.on_click
+                 function="ToggleControl"
+                 parameter="DebugShowTextureInfo" />
             </menu_item_check>
             <menu_item_check
              label="Show Matrices"
-- 
cgit v1.2.3


From c602fed9b7f262d6cba713f6a282aacde6304fde Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 18 Jan 2011 14:08:21 -0700
Subject: fix for SH-659: small textures not loaded

---
 indra/llmath/llvolume.cpp | 41 ++++++++++++++++++++++++++++++++++++++---
 indra/llmath/llvolume.h   |  1 +
 indra/newview/llface.cpp  | 11 +++++++++--
 3 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 14e1ca8d43..71b92962fb 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -4406,19 +4406,54 @@ std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
 
 BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 {
+	BOOL ret = FALSE ;
 	if (mTypeMask & CAP_MASK)
 	{
-		return createCap(volume, partial_build);
+		ret = createCap(volume, partial_build);
 	}
 	else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
 	{
-		return createSide(volume, partial_build);
+		ret = createSide(volume, partial_build);
 	}
 	else
 	{
 		llerrs << "Unknown/uninitialized face type!" << llendl;
-		return FALSE;
 	}
+
+	//update the range of the texture coordinates
+	if(ret)
+	{
+		mTexCoordExtents[0].setVec(1.f, 1.f) ;
+		mTexCoordExtents[1].setVec(0.f, 0.f) ;
+
+		U32 end = mVertices.size() ;
+		for(U32 i = 0 ; i < end ; i++)
+		{
+			if(mTexCoordExtents[0].mV[0] > mVertices[i].mTexCoord.mV[0])
+			{
+				mTexCoordExtents[0].mV[0] = mVertices[i].mTexCoord.mV[0] ;
+			}
+			if(mTexCoordExtents[1].mV[0] < mVertices[i].mTexCoord.mV[0])
+			{
+				mTexCoordExtents[1].mV[0] = mVertices[i].mTexCoord.mV[0] ;
+			}
+
+			if(mTexCoordExtents[0].mV[1] > mVertices[i].mTexCoord.mV[1])
+			{
+				mTexCoordExtents[0].mV[1] = mVertices[i].mTexCoord.mV[1] ;
+			}
+			if(mTexCoordExtents[1].mV[1] < mVertices[i].mTexCoord.mV[1])
+			{
+				mTexCoordExtents[1].mV[1] = mVertices[i].mTexCoord.mV[1] ;
+			}			
+		}
+		mTexCoordExtents[0].mV[0] = llmax(0.f, mTexCoordExtents[0].mV[0]) ;
+		mTexCoordExtents[0].mV[1] = llmax(0.f, mTexCoordExtents[0].mV[1]) ;
+		mTexCoordExtents[1].mV[0] = llmin(1.f, mTexCoordExtents[1].mV[0]) ;
+		mTexCoordExtents[1].mV[1] = llmin(1.f, mTexCoordExtents[1].mV[1]) ;
+	}
+
+	return ret ;
 }
 
 void	LerpPlanarVertex(LLVolumeFace::VertexData& v0,
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index d48a79ee46..28b9895ff3 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -831,6 +831,7 @@ public:
 	S32 mNumT;
 
 	LLVector3 mExtents[2]; //minimum and maximum point of face
+	LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
 
 	std::vector<VertexData> mVertices;
 	std::vector<U16>	mIndices;
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index d22950cad3..6ba957870c 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1233,7 +1233,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		if (rebuild_tcoord)
 		{
 			LLVector2 tc = vf.mVertices[i].mTexCoord;
-		
+		   
 			if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
 			{
 				LLVector3 vec = vf.mVertices[i].mPosition; 
@@ -1409,7 +1409,14 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		mTexExtents[0].setVec(0,0);
 		mTexExtents[1].setVec(1,1);
 		xform(mTexExtents[0], cos_ang, sin_ang, os, ot, ms, mt);
-		xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt);		
+		xform(mTexExtents[1], cos_ang, sin_ang, os, ot, ms, mt);
+		
+		F32 es = vf.mTexCoordExtents[1].mV[0] - vf.mTexCoordExtents[0].mV[0] ;
+		F32 et = vf.mTexCoordExtents[1].mV[1] - vf.mTexCoordExtents[0].mV[1] ;
+		mTexExtents[0][0] *= es ;
+		mTexExtents[1][0] *= es ;
+		mTexExtents[0][1] *= et ;
+		mTexExtents[1][1] *= et ;
 	}
 
 	mLastVertexBuffer = mVertexBuffer;
-- 
cgit v1.2.3


From c46cbafb15ff48515fdff8f1fd78b99391ddd4d7 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Tue, 18 Jan 2011 16:46:33 -0700
Subject: fix for SH-761: Texture Saving Does Not Work

---
 indra/newview/llpreviewtexture.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/indra/newview/llpreviewtexture.cpp b/indra/newview/llpreviewtexture.cpp
index fd6b326ef1..ced699b6b2 100644
--- a/indra/newview/llpreviewtexture.cpp
+++ b/indra/newview/llpreviewtexture.cpp
@@ -273,6 +273,8 @@ void LLPreviewTexture::saveAs()
 	mSaveFileName = file_picker.getFirstFile();
 	mLoadingFullImage = TRUE;
 	getWindow()->incBusyCount();
+
+	mImage->forceToSaveRawImage(0) ;//re-fetch the raw image if the old one is removed.
 	mImage->setLoadedCallback( LLPreviewTexture::onFileLoadedForSave, 
 								0, TRUE, FALSE, new LLUUID( mItemUUID ), &mCallbackTextureList );
 }
-- 
cgit v1.2.3


From 3571e83b6413e0c1050540a6cddeeaa7c6ca91c1 Mon Sep 17 00:00:00 2001
From: Jonathan Yap <none@none>
Date: Wed, 19 Jan 2011 06:02:08 -0500
Subject: STORM-869 Minor irregulaties in settings.xml -- remove duplicate
 entries, formatting cleanup

---
 doc/contributions.txt                   |  1 +
 indra/newview/app_settings/settings.xml | 81 +--------------------------------
 2 files changed, 2 insertions(+), 80 deletions(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 4c33834a46..c82d2c2a9d 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -359,6 +359,7 @@ Jonathan Yap
 	STORM-679
 	STORM-596
 	STORM-726
+	STORM-869
 Kage Pixel
 	VWR-11
 Ken March
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 06992d2b52..ec094eaeb8 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -917,39 +917,6 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-    <key>BulkChangeIncludeAnimations</key>
-    <map>
-      <key>Comment</key>
-      <string>Bulk permission changes affect animations</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
-    <key>BulkChangeIncludeAnimations</key>
-    <map>
-      <key>Comment</key>
-      <string>Bulk permission changes affect animations</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
-    <key>BulkChangeIncludeAnimations</key>
-    <map>
-      <key>Comment</key>
-      <string>Bulk permission changes affect animations</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
     <key>BulkChangeIncludeBodyParts</key>
     <map>
       <key>Comment</key>
@@ -1162,18 +1129,7 @@
     <key>CacheLocationTopFolder</key>
     <map>
       <key>Comment</key>
-      <string>Controls the top folder location of the local disk cache</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string />
-    </map>	
-    <key>CacheLocationTopFolder</key>
-    <map>
-      <key>Comment</key>
-      <string>Controls the location of the local disk cache</string>
+      <string>Controls the top folder location of the the local disk cache</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -3085,17 +3041,6 @@
         <key>Value</key>
         <string>http://viewer-settings.secondlife.com</string>
     </map>
-    <key>FPSLogFrequency</key>
-    <map>
-      <key>Comment</key>
-      <string>Seconds between display of FPS in log (0 for never)</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>F32</string>
-      <key>Value</key>
-      <real>60.0</real>
-    </map>
     <key>FPSLogFrequency</key>
         <map>
         <key>Comment</key>
@@ -6027,17 +5972,6 @@
       <integer>0</integer>
     </map>
     <key>OutBandwidth</key>
-    <map>
-      <key>Comment</key>
-      <string>Expand render stats display</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
-    <key>OutBandwidth</key>
     <map>
       <key>Comment</key>
       <string>Outgoing bandwidth throttle (bps)</string>
@@ -11375,8 +11309,6 @@
       <key>Type</key>
       <string>LLSD</string>
       <key>Value</key>
-      <map>
-      </map>
     </map>
     <key>VFSOldSize</key>
     <map>
@@ -11532,17 +11464,6 @@
       <key>Value</key>
       <string></string>
     </map>
-    <key>VivoxDebugSIPURIHostName</key>
-    <map>
-      <key>Comment</key>
-      <string>Hostname portion of vivox SIP URIs (empty string for the default).</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string></string>
-    </map>
     <key>VivoxDebugVoiceAccountServerURI</key>
     <map>
       <key>Comment</key>
-- 
cgit v1.2.3


From 4f801f729dbaf65edba93a7152c6f21ba2269ee0 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Wed, 19 Jan 2011 13:30:05 +0200
Subject: STORM-373 FIXED "Rename" context menu option was disabled for
 incomplete inventory items.

Refresh the inventory context menu (which enables the "Rename" option) after the selected item(s) gets fetched.
---
 indra/newview/llfolderview.cpp     | 63 ++++++++++++++++++++------------
 indra/newview/llfolderview.h       |  3 ++
 indra/newview/llinventorypanel.cpp | 73 ++++++++++++++++++++++++++++++++++++++
 indra/newview/llinventorypanel.h   |  3 ++
 4 files changed, 119 insertions(+), 23 deletions(-)

diff --git a/indra/newview/llfolderview.cpp b/indra/newview/llfolderview.cpp
index 62ba746a02..b3b1ce5743 100644
--- a/indra/newview/llfolderview.cpp
+++ b/indra/newview/llfolderview.cpp
@@ -1854,31 +1854,9 @@ BOOL LLFolderView::handleRightMouseDown( S32 x, S32 y, MASK mask )
 	{
 		if (mCallbackRegistrar)
 			mCallbackRegistrar->pushScope();
-		//menu->empty();
-		const LLView::child_list_t *list = menu->getChildList();
 
-		LLView::child_list_t::const_iterator menu_itor;
-		for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor)
-		{
-			(*menu_itor)->setVisible(FALSE);
-			(*menu_itor)->pushVisible(TRUE);
-			(*menu_itor)->setEnabled(TRUE);
-		}
-		
-		// Successively filter out invalid options
-
-		U32 flags = FIRST_SELECTED_ITEM;
-		for (selected_items_t::iterator item_itor = mSelectedItems.begin(); 
-			 item_itor != mSelectedItems.end(); 
-			 ++item_itor)
-		{
-			LLFolderViewItem* selected_item = (*item_itor);
-			selected_item->buildContextMenu(*menu, flags);
-			flags = 0x0;
-		}
+		updateMenuOptions(menu);
 	   
-		addNoOptions(menu);
-
 		menu->updateParent(LLMenuGL::sMenuContainer);
 		LLMenuGL::showPopup(this, menu, x, y);
 		if (mCallbackRegistrar)
@@ -2365,6 +2343,45 @@ void LLFolderView::updateRenamerPosition()
 	}
 }
 
+// Update visibility and availability (i.e. enabled/disabled) of context menu items.
+void LLFolderView::updateMenuOptions(LLMenuGL* menu)
+{
+	const LLView::child_list_t *list = menu->getChildList();
+
+	LLView::child_list_t::const_iterator menu_itor;
+	for (menu_itor = list->begin(); menu_itor != list->end(); ++menu_itor)
+	{
+		(*menu_itor)->setVisible(FALSE);
+		(*menu_itor)->pushVisible(TRUE);
+		(*menu_itor)->setEnabled(TRUE);
+	}
+
+	// Successively filter out invalid options
+
+	U32 flags = FIRST_SELECTED_ITEM;
+	for (selected_items_t::iterator item_itor = mSelectedItems.begin();
+			item_itor != mSelectedItems.end();
+			++item_itor)
+	{
+		LLFolderViewItem* selected_item = (*item_itor);
+		selected_item->buildContextMenu(*menu, flags);
+		flags = 0x0;
+	}
+
+	addNoOptions(menu);
+}
+
+// Refresh the context menu (that is already shown).
+void LLFolderView::updateMenu()
+{
+	LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get();
+	if (menu && menu->getVisible())
+	{
+		updateMenuOptions(menu);
+		menu->needsArrange(); // update menu height if needed
+	}
+}
+
 bool LLFolderView::selectFirstItem()
 {
 	for (folders_t::iterator iter = mFolders.begin();
diff --git a/indra/newview/llfolderview.h b/indra/newview/llfolderview.h
index afaac86b04..210ba9eb3c 100644
--- a/indra/newview/llfolderview.h
+++ b/indra/newview/llfolderview.h
@@ -269,7 +269,10 @@ public:
 	virtual S32	notify(const LLSD& info) ;
 	
 	bool useLabelSuffix() { return mUseLabelSuffix; }
+	void updateMenu();
+
 private:
+	void updateMenuOptions(LLMenuGL* menu);
 	void updateRenamerPosition();
 
 protected:
diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp
index 5a9d1524f3..1dcb91ad4d 100644
--- a/indra/newview/llinventorypanel.cpp
+++ b/indra/newview/llinventorypanel.cpp
@@ -60,6 +60,7 @@ static const LLInventoryFVBridgeBuilder INVENTORY_BRIDGE_BUILDER;
 //
 // Bridge to support knowing when the inventory has changed.
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
 class LLInventoryPanelObserver : public LLInventoryObserver
 {
 public:
@@ -73,9 +74,57 @@ protected:
 	LLInventoryPanel* mIP;
 };
 
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInvPanelComplObserver
+//
+// Calls specified callback when all specified items become complete.
+//
+// Usage:
+// observer = new LLInvPanelComplObserver(boost::bind(onComplete));
+// inventory->addObserver(observer);
+// observer->reset(); // (optional)
+// observer->watchItem(incomplete_item1_id);
+// observer->watchItem(incomplete_item2_id);
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class LLInvPanelComplObserver : public LLInventoryCompletionObserver
+{
+public:
+	typedef boost::function<void()> callback_t;
+
+	LLInvPanelComplObserver(callback_t cb)
+	:	mCallback(cb)
+	{
+	}
+
+	void reset();
+
+private:
+	/*virtual*/ void done();
+
+	/// Called when all the items are complete.
+	callback_t	mCallback;
+};
+
+void LLInvPanelComplObserver::reset()
+{
+	mIncomplete.clear();
+	mComplete.clear();
+}
+
+void LLInvPanelComplObserver::done()
+{
+	mCallback();
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+// Class LLInventoryPanel
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
 LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :	
 	LLPanel(p),
 	mInventoryObserver(NULL),
+	mCompletionObserver(NULL),
 	mFolderRoot(NULL),
 	mScroller(NULL),
 	mSortOrderSetting(p.sort_order_setting),
@@ -152,6 +201,9 @@ void LLInventoryPanel::initFromParams(const LLInventoryPanel::Params& params)
 	mInventoryObserver = new LLInventoryPanelObserver(this);
 	mInventory->addObserver(mInventoryObserver);
 
+	mCompletionObserver = new LLInvPanelComplObserver(boost::bind(&LLInventoryPanel::onItemsCompletion, this));
+	mInventory->addObserver(mCompletionObserver);
+
 	// Build view of inventory if we need default full hierarchy and inventory ready,
 	// otherwise wait for idle callback.
 	if (mBuildDefaultHierarchy && mInventory->isInventoryUsable() && !mViewsInitialized)
@@ -189,7 +241,10 @@ LLInventoryPanel::~LLInventoryPanel()
 
 	// LLView destructor will take care of the sub-views.
 	mInventory->removeObserver(mInventoryObserver);
+	mInventory->removeObserver(mCompletionObserver);
 	delete mInventoryObserver;
+	delete mCompletionObserver;
+
 	mScroller = NULL;
 }
 
@@ -654,6 +709,11 @@ void LLInventoryPanel::openStartFolderOrMyInventory()
 	}
 }
 
+void LLInventoryPanel::onItemsCompletion()
+{
+	if (mFolderRoot) mFolderRoot->updateMenu();
+}
+
 void LLInventoryPanel::openSelected()
 {
 	LLFolderViewItem* folder_item = mFolderRoot->getCurSelectedItem();
@@ -757,6 +817,19 @@ void LLInventoryPanel::clearSelection()
 
 void LLInventoryPanel::onSelectionChange(const std::deque<LLFolderViewItem*>& items, BOOL user_action)
 {
+	// Schedule updating the folder view context menu when all selected items become complete (STORM-373).
+	mCompletionObserver->reset();
+	for (std::deque<LLFolderViewItem*>::const_iterator it = items.begin(); it != items.end(); ++it)
+	{
+		LLUUID id = (*it)->getListener()->getUUID();
+		LLViewerInventoryItem* inv_item = mInventory->getItem(id);
+
+		if (inv_item && !inv_item->isFinished())
+		{
+			mCompletionObserver->watchItem(id);
+		}
+	}
+
 	LLFolderView* fv = getRootFolder();
 	if (fv->needsAutoRename()) // auto-selecting a new user-created asset and preparing to rename
 	{
diff --git a/indra/newview/llinventorypanel.h b/indra/newview/llinventorypanel.h
index 6545fc0d5e..9da9f7d8ba 100644
--- a/indra/newview/llinventorypanel.h
+++ b/indra/newview/llinventorypanel.h
@@ -52,6 +52,7 @@ class LLIconCtrl;
 class LLSaveFolderState;
 class LLFilterEditor;
 class LLTabContainer;
+class LLInvPanelComplObserver;
 
 class LLInventoryPanel : public LLPanel
 {
@@ -167,9 +168,11 @@ public:
 
 protected:
 	void openStartFolderOrMyInventory(); // open the first level of inventory
+	void onItemsCompletion();			// called when selected items are complete
 
 	LLInventoryModel*			mInventory;
 	LLInventoryObserver*		mInventoryObserver;
+	LLInvPanelComplObserver*	mCompletionObserver;
 	BOOL 						mAllowMultiSelect;
 	BOOL 						mShowItemLinkOverlays; // Shows link graphic over inventory item icons
 
-- 
cgit v1.2.3


From ff0e3e6177812cdb6b3e044500d50f5d8d10434a Mon Sep 17 00:00:00 2001
From: Paul Guslisty <pguslisty@productengine.com>
Date: Wed, 19 Jan 2011 13:55:39 +0200
Subject: STORM-547 FIXED Name of blocked person is not presented in list if
 person was blocked from Inspector

- Replaced method call which returns empty string with member containing display name
---
 indra/newview/llinspectavatar.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 91ede6d221..2bb6dbf277 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -704,7 +704,7 @@ void LLInspectAvatar::onClickShare()
 
 void LLInspectAvatar::onToggleMute()
 {
-	LLMute mute(mAvatarID, mAvatarName.getLegacyName(), LLMute::AGENT);
+	LLMute mute(mAvatarID, mAvatarName.mDisplayName, LLMute::AGENT);
 
 	if (LLMuteList::getInstance()->isMuted(mute.mID, mute.mName))
 	{
-- 
cgit v1.2.3


From ec0eafbaa0e4c4fbf25bab31ed38d90e998e9dbd Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Wed, 19 Jan 2011 21:41:53 +0200
Subject: STORM-348 FIXED "Edit" and "Lock" buttons appearing on body part
 items in outfit editor before they are hovered with mouse.

Added buttons reshaping code that exists in postBuild() methods of the other LLPanelWearableListItem descendants.
---
 indra/newview/llwearableitemslist.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp
index a49dc1b59d..66a6ab5e94 100644
--- a/indra/newview/llwearableitemslist.cpp
+++ b/indra/newview/llwearableitemslist.cpp
@@ -287,6 +287,9 @@ BOOL LLPanelBodyPartsListItem::postBuild()
 	addWidgetToRightSide("btn_lock");
 	addWidgetToRightSide("btn_edit_panel");
 
+	setWidgetsVisible(false);
+	reshapeWidgets();
+
 	return TRUE;
 }
 
-- 
cgit v1.2.3


From 0409d98dfb181284bb8815cda54f66f3d4b1c790 Mon Sep 17 00:00:00 2001
From: Eli Linden <eli@lindenlab.com>
Date: Wed, 19 Jan 2011 12:16:23 -0800
Subject: sync up with Viewer 2.5 from viewer-beta

---
 .../newview/skins/default/xui/da/panel_places.xml  |   2 +-
 .../newview/skins/default/xui/da/panel_profile.xml |   2 +-
 .../newview/skins/default/xui/de/panel_places.xml  |   2 +-
 .../newview/skins/default/xui/de/panel_profile.xml |   2 +-
 .../skins/default/xui/en/floater_env_settings.xml  |   1 +
 .../skins/default/xui/en/floater_help_browser.xml  |   3 +-
 .../skins/default/xui/en/floater_media_browser.xml |   2 +-
 .../default/xui/en/floater_windlight_options.xml   |   1 +
 .../skins/default/xui/en/inspect_object.xml        |  27 +-
 indra/newview/skins/default/xui/en/main_view.xml   |   8 +-
 indra/newview/skins/default/xui/en/menu_login.xml  |  10 +-
 .../newview/skins/default/xui/en/menu_mini_map.xml |  11 +-
 indra/newview/skins/default/xui/en/menu_place.xml  |  22 --
 indra/newview/skins/default/xui/en/menu_viewer.xml |  51 +++-
 .../newview/skins/default/xui/en/notifications.xml | 257 ++++++++++++++----
 .../default/xui/en/panel_avatar_list_item.xml      |   4 +-
 .../skins/default/xui/en/panel_bottomtray.xml      |   1 +
 .../skins/default/xui/en/panel_bottomtray_lite.xml |   1 +
 .../skins/default/xui/en/panel_edit_alpha.xml      |  24 +-
 .../skins/default/xui/en/panel_edit_profile.xml    |  11 -
 .../skins/default/xui/en/panel_edit_tattoo.xml     |   2 +-
 .../skins/default/xui/en/panel_group_invite.xml    |   2 +-
 .../default/xui/en/panel_group_land_money.xml      |   2 +-
 .../skins/default/xui/en/panel_group_list_item.xml |   3 +-
 .../skins/default/xui/en/panel_landmarks.xml       |   4 +
 indra/newview/skins/default/xui/en/panel_login.xml |  27 +-
 .../skins/default/xui/en/panel_main_inventory.xml  |   4 +
 .../skins/default/xui/en/panel_my_profile.xml      | 302 ++++-----------------
 .../skins/default/xui/en/panel_navigation_bar.xml  |   1 +
 .../skins/default/xui/en/panel_notify_textbox.xml  |  66 +++--
 .../newview/skins/default/xui/en/panel_places.xml  |   2 +-
 .../default/xui/en/panel_preferences_advanced.xml  |   2 +-
 .../default/xui/en/panel_preferences_colors.xml    |   7 +-
 .../default/xui/en/panel_preferences_privacy.xml   |  23 +-
 .../default/xui/en/panel_preferences_setup.xml     |  55 ++--
 .../default/xui/en/panel_preferences_sound.xml     |   1 +
 .../newview/skins/default/xui/en/panel_profile.xml |   4 +-
 .../skins/default/xui/en/panel_script_ed.xml       |   1 +
 .../skins/default/xui/en/panel_status_bar.xml      |   2 +-
 .../skins/default/xui/en/sidepanel_task_info.xml   |  11 +-
 indra/newview/skins/default/xui/en/strings.xml     |   4 +-
 .../skins/default/xui/en/widgets/button.xml        |   2 +-
 .../skins/default/xui/en/widgets/check_box.xml     |   8 +
 .../skins/default/xui/en/widgets/group_icon.xml    |   3 +-
 .../newview/skins/default/xui/es/panel_places.xml  |   2 +-
 .../newview/skins/default/xui/es/panel_profile.xml |   2 +-
 .../newview/skins/default/xui/fr/panel_places.xml  |   2 +-
 .../newview/skins/default/xui/fr/panel_profile.xml |   2 +-
 .../newview/skins/default/xui/it/panel_places.xml  |   2 +-
 .../newview/skins/default/xui/it/panel_profile.xml |   2 +-
 .../newview/skins/default/xui/ja/panel_places.xml  |   2 +-
 .../newview/skins/default/xui/ja/panel_profile.xml |   2 +-
 .../newview/skins/default/xui/pl/panel_places.xml  |   2 +-
 .../newview/skins/default/xui/pl/panel_profile.xml |   2 +-
 .../newview/skins/default/xui/pt/panel_places.xml  |   2 +-
 .../newview/skins/default/xui/pt/panel_profile.xml |   2 +-
 56 files changed, 538 insertions(+), 466 deletions(-)

diff --git a/indra/newview/skins/default/xui/da/panel_places.xml b/indra/newview/skins/default/xui/da/panel_places.xml
index ca3d7c71bb..fe8ca69f34 100644
--- a/indra/newview/skins/default/xui/da/panel_places.xml
+++ b/indra/newview/skins/default/xui/da/panel_places.xml
@@ -21,7 +21,7 @@
 						<button label="Redigér" name="edit_btn" tool_tip="Redigér landemærke information"/>
 					</layout_panel>
 					<layout_panel name="overflow_btn_lp">
-						<button label="▼" name="overflow_btn" tool_tip="Vis flere valg"/>
+						<menu_button label="▼" name="overflow_btn" tool_tip="Vis flere valg"/>
 					</layout_panel>
 				</layout_stack>
 				<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/da/panel_profile.xml b/indra/newview/skins/default/xui/da/panel_profile.xml
index b2d1e9791a..b8b99a9c21 100644
--- a/indra/newview/skins/default/xui/da/panel_profile.xml
+++ b/indra/newview/skins/default/xui/da/panel_profile.xml
@@ -42,7 +42,7 @@
 					<button label="Teleportér" name="teleport" tool_tip="Tilbyd teleport"/>
 				</layout_panel>
 				<layout_panel name="overflow_btn_lp">
-					<button label="▼" name="overflow_btn" tool_tip="Betal eller del beholdning med denne beboer"/>
+					<menu_button label="▼" name="overflow_btn" tool_tip="Betal eller del beholdning med denne beboer"/>
 				</layout_panel>
 			</layout_stack>
 		</layout_panel>
diff --git a/indra/newview/skins/default/xui/de/panel_places.xml b/indra/newview/skins/default/xui/de/panel_places.xml
index 0e85829a0b..36c77d4fe1 100644
--- a/indra/newview/skins/default/xui/de/panel_places.xml
+++ b/indra/newview/skins/default/xui/de/panel_places.xml
@@ -21,7 +21,7 @@
 						<button label="Bearbeiten" name="edit_btn" tool_tip="Landmarken-Info bearbeiten"/>
 					</layout_panel>
 					<layout_panel name="overflow_btn_lp">
-						<button label="▼" name="overflow_btn" tool_tip="Zusätzliche Optionen anzeigen"/>
+						<menu_button label="▼" name="overflow_btn" tool_tip="Zusätzliche Optionen anzeigen"/>
 					</layout_panel>
 				</layout_stack>
 				<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/de/panel_profile.xml b/indra/newview/skins/default/xui/de/panel_profile.xml
index 40fa2f922a..938631f65d 100644
--- a/indra/newview/skins/default/xui/de/panel_profile.xml
+++ b/indra/newview/skins/default/xui/de/panel_profile.xml
@@ -57,7 +57,7 @@
 					<button label="Teleportieren" name="teleport" tool_tip="Teleport anbieten"/>
 				</layout_panel>
 				<layout_panel name="overflow_btn_lp">
-					<button label="▼" name="overflow_btn" tool_tip="Dem Einwohner Geld geben oder Inventar an den Einwohner schicken"/>
+					<menu_button label="▼" name="overflow_btn" tool_tip="Dem Einwohner Geld geben oder Inventar an den Einwohner schicken"/>
 				</layout_panel>
 			</layout_stack>
 		</layout_panel>
diff --git a/indra/newview/skins/default/xui/en/floater_env_settings.xml b/indra/newview/skins/default/xui/en/floater_env_settings.xml
index 14f9e2db95..8df5e232d9 100644
--- a/indra/newview/skins/default/xui/en/floater_env_settings.xml
+++ b/indra/newview/skins/default/xui/en/floater_env_settings.xml
@@ -44,6 +44,7 @@
      left="85"
      name="EnvDayCycle"
      top="30"
+     use_draw_context_alpha="false"
      width="200" />
     <slider
      control_name="EnvTimeSlider"
diff --git a/indra/newview/skins/default/xui/en/floater_help_browser.xml b/indra/newview/skins/default/xui/en/floater_help_browser.xml
index 837923bcf6..02e50ee584 100644
--- a/indra/newview/skins/default/xui/en/floater_help_browser.xml
+++ b/indra/newview/skins/default/xui/en/floater_help_browser.xml
@@ -36,7 +36,8 @@
          user_resize="false"
          width="620">
             <web_browser
-              trusted_content="true" 
+             trusted_content="true" 
+             initial_mime_type="text/html" 
              bottom="-25"
              follows="left|right|top|bottom"
              layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/floater_media_browser.xml b/indra/newview/skins/default/xui/en/floater_media_browser.xml
index 49e835cce4..43729d7c9f 100644
--- a/indra/newview/skins/default/xui/en/floater_media_browser.xml
+++ b/indra/newview/skins/default/xui/en/floater_media_browser.xml
@@ -101,7 +101,7 @@
              left_pad="5"
              name="go"
              top_delta="0"
-             width="55">
+             width="50">
 				<button.commit_callback
 				function="MediaBrowser.Go" />
 			</button>
diff --git a/indra/newview/skins/default/xui/en/floater_windlight_options.xml b/indra/newview/skins/default/xui/en/floater_windlight_options.xml
index 85a5be369c..249ad95c41 100644
--- a/indra/newview/skins/default/xui/en/floater_windlight_options.xml
+++ b/indra/newview/skins/default/xui/en/floater_windlight_options.xml
@@ -594,6 +594,7 @@
              left_delta="14"
              top_pad="10"
              name="SkyDayCycle"
+             use_draw_context_alpha="false"
              width="148" />
             <slider
              control_name="WLSunAngle"
diff --git a/indra/newview/skins/default/xui/en/inspect_object.xml b/indra/newview/skins/default/xui/en/inspect_object.xml
index eb2e7ea788..8d14c974b4 100644
--- a/indra/newview/skins/default/xui/en/inspect_object.xml
+++ b/indra/newview/skins/default/xui/en/inspect_object.xml
@@ -76,13 +76,24 @@ L$30,000
   </text>
   <!-- Overlapping buttons for all default actions.  Show "Buy" if
   for sale, "Sit" if can sit, etc. -->
+  <icon
+   name="secure_browsing"
+   image_name="Lock"
+   left="0"
+   visible="false"
+   width="18"
+   height="18"
+   top="103"
+   tool_tip="Secure Browsing"
+   follows="left|top" />
    <text
    follows="all"
    font="SansSerifSmall"
    height="13"
    name="object_media_url"
-   width="220"
-   top_pad="0"
+   width="207"
+   left_pad="2"
+   top_delta="0"
    max_length = "50"
    use_ellipses="true">
    http://www.superdupertest.com
@@ -135,16 +146,6 @@ L$30,000
    name="open_btn"
    top_delta="0"
    width="80" />
-  <icon
-   name="secure_browsing"
-   image_name="Lock"
-   left_delta="80"
-   visible="false"
-   width="18"
-   height="18"
-   top_delta="0"
-   tool_tip="Secure Browsing"
-   follows="left|top" />
 
  <!--  non-overlapping buttons here -->
      <button
@@ -153,7 +154,7 @@ L$30,000
      label="More"
      layout="topleft"
      name="more_info_btn"
-     left_delta="10"
+     left_pad="10"
      top_delta="0"
      tab_stop="false"
      width="80" />
diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml
index 520a604bde..d9991fcae9 100644
--- a/indra/newview/skins/default/xui/en/main_view.xml
+++ b/indra/newview/skins/default/xui/en/main_view.xml
@@ -8,6 +8,12 @@
  tab_stop="false" 
  name="main_view"
  width="1024">
+  <panel top="0"
+     follows="all"
+     height="768"
+     mouse_opaque="false"
+     name="login_panel_holder"
+     width="1024"/>
   <layout_stack border_size="0"
                 follows="all"
                 mouse_opaque="false"
@@ -120,7 +126,7 @@
                       user_resize="false"
                       visible="false"
                       width="333"/>
-      </layout_stack>
+      </layout_stack>      
       <panel follows="all"
                     height="500"
                     left="0"
diff --git a/indra/newview/skins/default/xui/en/menu_login.xml b/indra/newview/skins/default/xui/en/menu_login.xml
index 4f982cc8e9..0d4a095e14 100644
--- a/indra/newview/skins/default/xui/en/menu_login.xml
+++ b/indra/newview/skins/default/xui/en/menu_login.xml
@@ -176,13 +176,19 @@
              parameter="message_critical" />
         </menu_item_call>
         <menu_item_call
-         label="Web Browser Test"
+         label="Media Browser Test"
          name="Web Browser Test">
           <menu_item_call.on_click
            function="Advanced.WebBrowserTest"
            parameter="http://join.secondlife.com/"/>
         </menu_item_call>
-      <menu_item_separator/>
+      <menu_item_call
+       label="Web Content Floater Test"
+       name="Web Content Floater Test">
+        <menu_item_call.on_click
+         function="Advanced.WebContentTest"
+         parameter="http://www.google.com"/>
+      </menu_item_call>
       <menu_item_check
         label="Show Grid Picker"
         name="Show Grid Picker"
diff --git a/indra/newview/skins/default/xui/en/menu_mini_map.xml b/indra/newview/skins/default/xui/en/menu_mini_map.xml
index 8fe89d3934..ea263d05ce 100644
--- a/indra/newview/skins/default/xui/en/menu_mini_map.xml
+++ b/indra/newview/skins/default/xui/en/menu_mini_map.xml
@@ -8,7 +8,7 @@
  top="724"
  visible="false"
  width="128">
-    <menu_item_call
+	<menu_item_call
      label="Zoom Close"
      name="Zoom Close">
         <menu_item_call.on_click
@@ -29,7 +29,14 @@
          function="Minimap.Zoom"
          parameter="far" />
     </menu_item_call>
-    <menu_item_separator />
+	<menu_item_call
+     label="Zoom Default"
+     name="Zoom Default">
+		<menu_item_call.on_click
+         function="Minimap.Zoom"
+         parameter="default" />
+	</menu_item_call>
+	<menu_item_separator />
     <menu_item_check
        label="Rotate Map"
        name="Rotate Map">
diff --git a/indra/newview/skins/default/xui/en/menu_place.xml b/indra/newview/skins/default/xui/en/menu_place.xml
index 1b96eb51f0..288811d2f6 100644
--- a/indra/newview/skins/default/xui/en/menu_place.xml
+++ b/indra/newview/skins/default/xui/en/menu_place.xml
@@ -24,26 +24,4 @@
          function="Places.OverflowMenu.Enable"
          parameter="can_create_pick" />
     </menu_item_call>
-    <menu_item_separator
-     layout="topleft"/>
-    <menu_item_call
-     enabled="false"
-     label="Buy Pass"
-     layout="topleft"
-     name="pass">
-        <menu_item_call.on_click
-         function="Places.OverflowMenu.Action"
-         parameter="pass" />
-    </menu_item_call>
-    <menu_item_separator
-     layout="topleft"/>
-    <menu_item_call
-     enabled="false"
-     label="Edit"
-     layout="topleft"
-     name="edit">
-        <menu_item_call.on_click
-         function="Places.OverflowMenu.Action"
-         parameter="edit" />
-    </menu_item_call>
 </toggleable_menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 27ab7c4fbd..d997a262a8 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -976,6 +976,29 @@
                  parameter="perm_prefs" />
             </menu_item_call>
         </menu>
+        <menu_item_separator/>
+        <menu_item_call
+         enabled="false"
+         label="Undo"
+         name="Undo"
+         shortcut="control|Z">
+            <on_click
+             function="Edit.Undo"
+             userdata="" />
+            <on_enable
+             function="Edit.EnableUndo" />
+        </menu_item_call>
+        <menu_item_call
+         enabled="false"
+         label="Redo"
+         name="Redo"
+         shortcut="control|Y">
+            <on_click
+             function="Edit.Redo"
+             userdata="" />
+            <on_enable
+             function="Edit.EnableRedo" />
+        </menu_item_call>        
     </menu>
     <menu
      create_jump_keys="true"
@@ -990,6 +1013,14 @@
              function="ShowHelp"
              parameter="f1_help" />
         </menu_item_call>
+        <menu_item_check
+         label="Enable Hints"
+         name="Enable Hints">
+          <on_check
+            control="EnableUIHints"/>
+          <on_click
+            function="ToggleUIHints"/>
+        </menu_item_check>
 <!--        <menu_item_call
          label="Tutorial"
          name="Tutorial">
@@ -1023,14 +1054,6 @@
              function="Floater.Show"
              parameter="sl_about" />
         </menu_item_call>
-        <menu_item_check
-         label="Enable Hints"
-         name="Enable Hints">
-          <on_check
-            control="EnableUIHints"/>
-          <on_click
-            function="ToggleUIHints"/>
-        </menu_item_check>
     </menu>
     <menu
      create_jump_keys="true"
@@ -2623,13 +2646,21 @@
                  parameter="BottomPanelNew" />
             </menu_item_check>-->
             <menu_item_call
-             label="Web Browser Test"
+             label="Media Browser Test"
              name="Web Browser Test">
                 <menu_item_call.on_click
                  function="Advanced.WebBrowserTest"
                  parameter="http://secondlife.com/app/search/slurls.html"/>
             </menu_item_call>
-            <menu_item_call
+          <menu_item_call
+           label="Web Content Browser"
+           name="Web Content Browser"
+           shortcut="control|alt|W">
+            <menu_item_call.on_click
+             function="Advanced.WebContentTest"
+             parameter="http://google.com"/>
+          </menu_item_call>
+          <menu_item_call
              label="Dump SelectMgr"
              name="Dump SelectMgr">
                 <menu_item_call.on_click
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 60b876d163..3df53ac442 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -251,6 +251,16 @@ Save all changes to clothing/body parts?
      yestext="OK"/>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="FavoritesOnLogin"
+   type="alertmodal">    
+    Note: When you turn on this option, anyone who uses this computer can see your list of favorite locations.
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="GrantModifyRights"
@@ -441,6 +451,7 @@ Please invite members within 48 hours.
    icon="alertmodal.tga"
    name="LandBuyPass"
    type="alertmodal">
+   <tag>fail</tag>
 For L$[COST] you can enter this land (&apos;[PARCEL_NAME]&apos;) for [TIME] hours.  Buy a pass?
     <usetemplate
      name="okcancelbuttons"
@@ -1604,6 +1615,7 @@ If you continue to get this message, please check the [SUPPORT_SITE].
    icon="alertmodal.tga"
    name="blocked_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, teleport is currently blocked. Try again in a moment.  If you still cannot teleport, please log out and log back in to resolve the problem.
   </notification>
   <notification
@@ -1616,42 +1628,49 @@ Sorry, but system was unable to locate landmark destination.
    icon="alertmodal.tga"
    name="timeout_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, but system was unable to complete the teleport connection.  Try again in a moment.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="noaccess_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, you do not have access to that teleport destination.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="missing_attach_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Your attachments have not arrived yet. Try waiting for a few more seconds or log out and back in again before attempting to teleport.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="too_many_uploads_tport"
    type="alertmodal">
+   <tag>fail</tag>
 The asset queue in this region is currently clogged so your teleport request will not be able to succeed in a timely manner. Please try again in a few minutes or go to a less busy area.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="expired_tport"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, but the system was unable to complete your teleport request in a timely fashion. Please try again in a few minutes.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="expired_region_handoff"
    type="alertmodal">
+   <tag>fail</tag>
 Sorry, but the system was unable to complete your region crossing in a timely fashion. Please try again in a few minutes.
   </notification>
   <notification
    icon="alertmodal.tga"
    name="no_host"
    type="alertmodal">
+   <tag>fail</tag>
 Unable to find teleport destination. The destination may be temporarily unavailable or no longer exists. Please try again in a few minutes.
   </notification>
   <notification
@@ -2070,7 +2089,7 @@ Would you be my friend?
       <button
        default="true"
        index="0"
-       name="Offer"
+       name="OK"
        text="OK"/>
       <button
        index="1"
@@ -2092,7 +2111,7 @@ Would you be my friend?
       <button
        default="true"
        index="0"
-       name="Offer"
+       name="OK"
        text="OK"/>
       <button
        index="1"
@@ -2115,7 +2134,7 @@ Would you be my friend?
       <button
        default="true"
        index="0"
-       name="Offer"
+       name="OK"
        text="OK"/>
       <button
        index="1"
@@ -2419,6 +2438,7 @@ Display settings have been set to recommended levels based on your system config
    icon="alertmodal.tga"
    name="AvatarMovedDesired"
    type="alertmodal">
+   <tag>fail</tag>
 Your desired location is not currently available.
 You have been moved into a nearby region.
   </notification>
@@ -2427,6 +2447,7 @@ You have been moved into a nearby region.
    icon="alertmodal.tga"
    name="AvatarMovedLast"
    type="alertmodal">
+   <tag>fail</tag>
 Your last location is not currently available.
 You have been moved into a nearby region.
   </notification>
@@ -2435,6 +2456,7 @@ You have been moved into a nearby region.
    icon="alertmodal.tga"
    name="AvatarMovedHome"
    type="alertmodal">
+   <tag>fail</tag>
 Your home location is not currently available.
 You have been moved into a nearby region.
 You may want to set a new home location.
@@ -2444,6 +2466,7 @@ You may want to set a new home location.
    icon="alertmodal.tga"
    name="ClothingLoading"
    type="alertmodal">
+   <tag>fail</tag>
 Your clothing is still downloading.
 You can use [SECOND_LIFE] normally and other people will see you correctly.
     <form name="form">
@@ -2471,6 +2494,7 @@ Return to [http://join.secondlife.com secondlife.com] to create a new account?
    icon="alertmodal.tga"
    name="LoginPacketNeverReceived"
    type="alertmodal">
+   <tag>fail</tag>
 We&apos;re having trouble connecting. There may be a problem with your Internet connection or the [SECOND_LIFE_GRID].
 
 You can either check your Internet connection and try again in a few minutes, click Help to view the [SUPPORT_SITE], or click Teleport to attempt to teleport home.
@@ -2887,12 +2911,80 @@ http://secondlife.com/download.
      name="okbutton"
      yestext="OK"/>
   </notification>
+
   <notification
-   icon="notifytip.tga"
-   name="DownloadBackground"
-   type="notifytip">
-An updated version of [APP_NAME] has been downloaded.
-It will be applied the next time you restart [APP_NAME]
+   icon="alertmodal.tga"
+   name="FailedRequiredUpdateInstall"
+   type="alertmodal">
+We were unable to install a required update. 
+You will be unable to log in until [APP_NAME] has been updated.
+
+Please download and install the latest viewer from
+http://secondlife.com/download.
+    <usetemplate
+     name="okbutton"
+     yestext="Quit"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="UpdaterServiceNotRunning"
+   type="alertmodal">
+There is a required update for your Second Life Installation.
+
+You may download this update from http://www.secondlife.com/downloads
+or you can install it now.
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Quit Second Life"
+     yestext="Download and install now"/>
+  </notification>
+
+  <notification
+   icon="notify.tga"
+   name="DownloadBackgroundTip"
+   type="notify">
+We have downloaded an update to your [APP_NAME] installation.
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update]
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Later..."
+     yestext="Install now and restart [APP_NAME]"/>
+  </notification>
+
+  <notification
+ icon="alertmodal.tga"
+ name="DownloadBackgroundDialog"
+ type="alertmodal">
+We have downloaded an update to your [APP_NAME] installation.
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update]
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Later..."
+     yestext="Install now and restart [APP_NAME]"/>
+  </notification>
+  
+  <notification
+ icon="alertmodal.tga"
+ name="RequiredUpdateDownloadedVerboseDialog"
+ type="alertmodal">
+We have downloaded a required software update.
+Version [VERSION]
+
+We must restart [APP_NAME] to install the update.
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
+  </notification>
+  
+  <notification
+ icon="alertmodal.tga"
+ name="RequiredUpdateDownloadedDialog"
+ type="alertmodal">
+We must restart [APP_NAME] to install the update.
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
   </notification>
 
   <notification
@@ -3138,6 +3230,7 @@ You have reached your maximum number of groups. Please leave some group before j
    icon="alert.tga"
    name="KickUser"
    type="alert">
+   <tag>win</tag>
 Kick this Resident with what message?
     <form name="form">
       <input name="message" type="text">
@@ -3159,6 +3252,7 @@ An administrator has logged you off.
    icon="alert.tga"
    name="KickAllUsers"
    type="alert">
+   <tag>win</tag>
 Kick everyone currently on the grid with what message?
     <form name="form">
       <input name="message" type="text">
@@ -3180,6 +3274,7 @@ An administrator has logged you off.
    icon="alert.tga"
    name="FreezeUser"
    type="alert">
+   <tag>win</tag>
 Freeze this Resident with what message?
     <form name="form">
       <input name="message" type="text">
@@ -3201,6 +3296,7 @@ You have been frozen. You cannot move or chat. An administrator will contact you
    icon="alert.tga"
    name="UnFreezeUser"
    type="alert">
+   <tag>win</tag>
 Unfreeze this Resident with what message?
     <form name="form">
       <input name="message" type="text">
@@ -3572,6 +3668,7 @@ Are you sure you want to change the Estate Covenant?
    icon="alertmodal.tga"
    name="RegionEntryAccessBlocked"
    type="alertmodal">
+   <tag>fail</tag>
 You are not allowed in that Region due to your maturity Rating. This may be a result of a lack of information validating your age.
 
 Please verify you have the latest Viewer installed, and go to the Knowledge Base for details on accessing areas with this maturity rating.
@@ -3584,6 +3681,7 @@ Please verify you have the latest Viewer installed, and go to the Knowledge Base
    icon="alertmodal.tga"
    name="RegionEntryAccessBlocked_KB"
    type="alertmodal">
+   <tag>fail</tag>
 You are not allowed in that region due to your maturity Rating.
 
 Go to the Knowledge Base for more information about maturity Ratings?
@@ -3601,6 +3699,7 @@ Go to the Knowledge Base for more information about maturity Ratings?
    icon="notifytip.tga"
    name="RegionEntryAccessBlocked_Notify"
    type="notifytip">
+   <tag>fail</tag>
 You are not allowed in that region due to your maturity Rating.
   </notification>
 
@@ -3608,6 +3707,7 @@ You are not allowed in that region due to your maturity Rating.
    icon="alertmodal.tga"
    name="RegionEntryAccessBlocked_Change"
    type="alertmodal">
+   <tag>fail</tag>
 You are not allowed in that Region due to your maturity Rating preference.
 
 To enter the desired region, please change your maturity Rating preference. This will allow you to search for and access [REGIONMATURITY] content. To undo any changes, go to Me &gt; Preferences &gt; General.
@@ -4524,6 +4624,7 @@ Would you like to automatically wear the clothing you are about to create?
    icon="alertmodal.tga"
    name="NotAgeVerified"
    type="alertmodal">
+   <tag>fail</tag>
 You must be age-verified to visit this area.  Do you want to go to the [SECOND_LIFE] website and verify your age?
 
 [_URL]
@@ -4905,24 +5006,6 @@ Some terms in your search query were excluded due to content restrictions as cla
 Please select at least one type of content to search (General, Moderate, or Adult).
   </notification>
 
-  <notification
-   icon="notify.tga"
-   name="GroupVote"
-   type="notify">
-[NAME] has proposed to vote on:
-[MESSAGE]
-    <form name="form">
-      <button
-       index="0"
-       name="VoteNow"
-       text="Vote Now"/>
-      <button
-       index="1"
-       name="Later"
-       text="Later"/>
-    </form>
-  </notification>
-
   <notification
    icon="notify.tga"
    name="SystemMessage"
@@ -5009,7 +5092,7 @@ If you want to view streaming media on parcels that support it you should go to
    type="notify">
 No Media Plugin was found to handle the "[MIME_TYPE]" mime type.  Media of this type will be unavailable.
     <unique>
-      <context key="[MIME_TYPE]"/>
+      <context>MIME_TYPE</context>
     </unique>
 
   </notification>
@@ -5093,6 +5176,7 @@ You can be hurt here. If you die, you will be teleported to your home location.
    persist="true"
    type="notify"
    unique="true">
+   <tag>fail</tag>
 This area has flying disabled.
 You can&apos;t fly here.
   </notification>
@@ -5145,6 +5229,7 @@ This region is not running any scripts.
    name="NoOutsideScripts"
    persist="true"
    type="notify">
+   <tag>fail</tag>
 This land has outside scripts disabled.
 
 No scripts will work here except those belonging to the land owner.
@@ -5163,6 +5248,7 @@ You can only claim public land in the Region you&apos;re in.
    name="RegionTPAccessBlocked"
    persist="true"
    type="notify">
+   <tag>fail</tag>
 You aren&apos;t allowed in that Region due to your maturity Rating. You may need to validate your age and/or install the latest Viewer.
 
 Please go to the Knowledge Base for details on accessing areas with this maturity Rating.
@@ -5173,6 +5259,7 @@ Please go to the Knowledge Base for details on accessing areas with this maturit
 	name="URBannedFromRegion"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You are banned from the region.
   </notification>
 
@@ -5181,6 +5268,7 @@ You are banned from the region.
 	name="NoTeenGridAccess"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Your account cannot connect to this teen grid region.
   </notification>
 
@@ -5189,6 +5277,7 @@ Your account cannot connect to this teen grid region.
 	name="ImproperPaymentStatus"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You do not have proper payment status to enter this region.
   </notification>
 
@@ -5197,6 +5286,7 @@ You do not have proper payment status to enter this region.
 	name="MustGetAgeRgion"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You must be age-verified to enter this region.
   </notification>
 
@@ -5205,6 +5295,7 @@ You must be age-verified to enter this region.
 	name="MustGetAgeParcel"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You must be age-verified to enter this parcel.
   </notification>
 
@@ -5213,6 +5304,7 @@ You must be age-verified to enter this parcel.
 	name="NoDestRegion"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No destination region found.
   </notification>
 
@@ -5221,6 +5313,7 @@ No destination region found.
 	name="NotAllowedInDest"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You are not allowed into the destination.
   </notification>
 
@@ -5229,6 +5322,7 @@ You are not allowed into the destination.
 	name="RegionParcelBan"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Cannot region cross into banned parcel. Try another way.
   </notification>
 
@@ -5237,6 +5331,7 @@ Cannot region cross into banned parcel. Try another way.
 	name="TelehubRedirect"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 You have been redirected to a telehub.
   </notification>
 
@@ -5245,6 +5340,7 @@ You have been redirected to a telehub.
 	name="CouldntTPCloser"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Could not teleport closer to destination.
   </notification>
 
@@ -5261,6 +5357,7 @@ Teleport cancelled.
 	name="FullRegionTryAgain"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 The region you are attempting to enter is currently full.
 Please try again in a few moments.
   </notification>
@@ -5270,6 +5367,7 @@ Please try again in a few moments.
 	name="GeneralFailure"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 General failure.
   </notification>
 
@@ -5278,6 +5376,7 @@ General failure.
 	name="RoutedWrongRegion"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Routed to wrong region. Please try again.
   </notification>
 
@@ -5286,6 +5385,7 @@ Routed to wrong region. Please try again.
 	name="NoValidAgentID"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid agent id.
   </notification>
 
@@ -5294,6 +5394,7 @@ No valid agent id.
 	name="NoValidSession"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid session id.
   </notification>
 
@@ -5302,6 +5403,7 @@ No valid session id.
 	name="NoValidCircuit"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid circuit code.
   </notification>
 
@@ -5310,6 +5412,7 @@ No valid circuit code.
 	name="NoValidTimestamp"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid timestamp.
   </notification>
 
@@ -5318,6 +5421,7 @@ No valid timestamp.
 	name="NoPendingConnection"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Unable to create pending connection.
   </notification>
 
@@ -5326,6 +5430,7 @@ Unable to create pending connection.
 	name="InternalUsherError"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Internal error attempting to connect agent usher.
   </notification>
 
@@ -5334,6 +5439,7 @@ Internal error attempting to connect agent usher.
 	name="NoGoodTPDestination"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Unable to find a good teleport destination in this region.
   </notification>
 
@@ -5342,6 +5448,7 @@ Unable to find a good teleport destination in this region.
 	name="InternalErrorRegionResolver"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 Internal error attempting to activate region resolver.
   </notification>
 
@@ -5350,6 +5457,7 @@ Internal error attempting to activate region resolver.
 	name="NoValidLanding"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 A valid landing point could not be found.
   </notification>
 
@@ -5358,6 +5466,7 @@ A valid landing point could not be found.
 	name="NoValidParcel"
    persist="true"
 	type="notify">
+   <tag>fail</tag>
 No valid parcel could be found.
   </notification>
 
@@ -5734,6 +5843,7 @@ Grant this request?
    name="FirstBalanceIncrease"
    persist="true"
    type="notify">
+   <tag>win</tag>
 You just received L$[AMOUNT].
 Your L$ balance is shown in the upper-right.
   </notification>
@@ -5911,7 +6021,7 @@ You may only select up to [MAX_SELECT] items from this list.
 [NAME] is inviting you to a Voice Chat call.
 Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
+      <context>NAME</context>
     </unique>
     <form name="form">
       <button
@@ -5960,8 +6070,8 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
 [NAME] has joined a Voice Chat call with the group [GROUP].
 Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
-      <context key="GROUP"/>
+      <context>NAME</context>
+      <context>GROUP</context>
     </unique>
     <form name="form">
       <button
@@ -5986,7 +6096,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
 [NAME] has joined a voice chat call with a conference chat.
 Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
+      <context>NAME</context>
     </unique>
     <form name="form">
       <button
@@ -6011,7 +6121,7 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
 [NAME] is inviting you to a conference chat.
 Click Accept to join the chat or Decline to decline the invitation. Click Block to block this caller.
     <unique>
-      <context key="NAME"/>
+      <context>NAME</context>
     </unique>
     <form name="form">
       <button
@@ -6035,7 +6145,7 @@ Click Accept to join the chat or Decline to decline the invitation. Click Block
    type="notifytip">
 The voice call you are trying to join, [VOICE_CHANNEL_NAME], has reached maximum capacity. Please try again later.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6053,7 +6163,7 @@ We&apos;re sorry.  This area has reached maximum capacity for voice conversation
    type="notifytip">
 You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6063,7 +6173,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 [VOICE_CHANNEL_NAME] has ended the call.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6073,7 +6183,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 [VOICE_CHANNEL_NAME] has declined your call.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6083,7 +6193,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 [VOICE_CHANNEL_NAME] is not available to take your call.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6093,7 +6203,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME].  You will now be reconnect
    type="notifytip">
 Failed to connect to [VOICE_CHANNEL_NAME], please try again later.  You will now be reconnected to Nearby Voice Chat.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6153,6 +6263,7 @@ New Voice Morphs are available!
    icon="notifytip.tga"
    name="Cannot enter parcel: not a group member"
    type="notifytip">
+   <tag>fail</tag>
 Only members of a certain group can visit this area.
   </notification>
 
@@ -6160,6 +6271,7 @@ Only members of a certain group can visit this area.
    icon="notifytip.tga"
    name="Cannot enter parcel: banned"
    type="notifytip">
+   <tag>fail</tag>
 Cannot enter parcel, you have been banned.
   </notification>
 
@@ -6167,6 +6279,7 @@ Cannot enter parcel, you have been banned.
    icon="notifytip.tga"
    name="Cannot enter parcel: not on access list"
    type="notifytip">
+   <tag>fail</tag>
 Cannot enter parcel, you are not on the access list.
   </notification>
 
@@ -6176,7 +6289,7 @@ Cannot enter parcel, you are not on the access list.
    type="notifytip">
 You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6186,7 +6299,7 @@ You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].
    type="notifytip">
 An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_NAME].  Please try again later.
     <unique>
-      <context key="VOICE_CHANNEL_NAME"/>
+      <context>VOICE_CHANNEL_NAME</context>
     </unique>
   </notification>
 
@@ -6212,6 +6325,7 @@ The SLurl you clicked on is not supported.
    name="BlockedSLURL"
    priority="high"
    type="notifytip">
+   <tag>win</tag>
 A SLurl was received from an untrusted browser and has been blocked for your security.
   </notification>
 
@@ -6411,13 +6525,9 @@ Avatar '[NAME]' left appearance mode.
    type="alertmodal">
 We're having trouble connecting using [PROTOCOL] [HOSTID].
 Please check your network and firewall setup.
-    <form name="form">
-      <button
-       default="true"
-       index="0"
-       name="OK"
-       text="OK"/>
-    </form>
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
   </notification>
 
   <notification
@@ -6430,13 +6540,9 @@ We're having trouble connecting to your voice server:
 
 Voice communications will not be available.
 Please check your network and firewall setup.
-    <form name="form">
-      <button
-       default="true"
-       index="0"
-       name="OK"
-       text="OK"/>
-    </form>
+    <usetemplate
+     name="okbutton"
+     yestext="OK"/>
   </notification>
 
   <notification
@@ -6517,6 +6623,14 @@ Mute everyone?
     The Destination Guide contains thousands of new places to discover. Select a location and choose Teleport to start exploring.
   </notification>
 
+  <notification
+  name="HintAvatarPicker"
+  label="Change your Look"
+  type="hint"
+  unique="true">
+    Would you like to try a new look? Click the button below to see more Avatars.
+  </notification>
+
   <notification
     name="HintSidePanel"
     label="Side Panel"
@@ -6541,6 +6655,24 @@ Mute everyone?
     Set your customizable display name here. This is in addition to your unique username, which can't be changed. You can change how you see other people's names in your preferences.
   </notification>
 
+  <notification
+  name="HintMoveArrows"
+  label="Move"
+  type="hint"
+  unique="true">
+    To walk, use the directional keys on your keyboard. You can run by pressing the Up arrow twice.
+    <tag>custom_skin</tag>
+  </notification>
+
+  <notification
+  name="HintView"
+  label="View"
+  type="hint"
+  unique="true">
+    To change your camera view, use the Orbit and Pan controls. Reset your view by pressing Escape or walking.
+    <tag>custom_skin</tag>
+  </notification>
+
   <notification
   name="HintInventory"
   label="Inventory"
@@ -6574,6 +6706,23 @@ Mute everyone?
     </form>
   </notification>
 
+  <notification
+  name="AuthRequest"
+  type="browser">
+The site at &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; in realm &apos;[REALM]&apos; requires a user name and password.
+    <form name="form">
+      <input name="username" type="text" text="User Name"/>
+      <input name="password" type="password" text="Password    "/>
+      <button default="true"
+              index="0"
+              name="ok"
+              text="Submit"/>
+      <button index="1"
+              name="cancel"
+              text="Cancel"/>
+    </form>
+  </notification>
+
   
   <global name="UnsupportedCPU">
 - Your CPU speed does not meet the minimum requirements.
diff --git a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
index 6f3629cc8f..e40dc430fc 100644
--- a/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_avatar_list_item.xml
@@ -62,7 +62,7 @@
      name="avatar_name"
      top="6"
      use_ellipses="true"
-     value="Unknown"
+     value="(loading)"
      width="180" />
     <text
      follows="right"
@@ -134,7 +134,7 @@
     <button
      follows="right"
      height="20"
-     image_overlay="ForwardArrow_Off"
+     image_overlay="Web_Profile_Off"
      layout="topleft"
      left_pad="5"
      right="-28"
diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray.xml b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
index 63068a069f..013a8090f7 100644
--- a/indra/newview/skins/default/xui/en/panel_bottomtray.xml
+++ b/indra/newview/skins/default/xui/en/panel_bottomtray.xml
@@ -5,6 +5,7 @@
  bg_opaque_color="DkGray"
  chrome="true"
  follows="left|bottom|right"
+ focus_root="true" 
  height="33"
  layout="topleft"
  left="0"
diff --git a/indra/newview/skins/default/xui/en/panel_bottomtray_lite.xml b/indra/newview/skins/default/xui/en/panel_bottomtray_lite.xml
index efb1da4c05..b5e1a5f16d 100644
--- a/indra/newview/skins/default/xui/en/panel_bottomtray_lite.xml
+++ b/indra/newview/skins/default/xui/en/panel_bottomtray_lite.xml
@@ -10,6 +10,7 @@
  layout="topleft"
  left="0"
  name="bottom_tray_lite"
+ focus_root="true" 
  tab_stop="true"
  top="28"
  chrome="true"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_alpha.xml b/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
index 7bcd4962d2..813aa5d7a9 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_alpha.xml
@@ -8,6 +8,17 @@
 	 name="edit_alpha_panel"
 	 top_pad="10"
 	 width="333" >
+   <scroll_container
+    color="DkGray2"
+    follows="all"
+    height="400"
+    layout="topleft"
+    left="10"
+    top_pad="0"
+    name="avatar_alpha_color_panel_scroll"
+    reserve_scroll_corner="false"
+    opaque="true"
+    width="313">
    <panel
       border="false"
       bg_alpha_color="DkGray2"
@@ -16,14 +27,14 @@
       background_opaque="true"
       follows="top|left|right"
       height="400" 
-      left="10" 
+      left="0" 
       layout="topleft" 
       name="avatar_alpha_color_panel"
       top="0"
       width="313" >
        <check_box
         control_name="LowerAlphaTextureInvisible"
-        follows="left"
+        follows="left|top"
         height="16"
         layout="topleft"
         left="5"
@@ -48,7 +59,7 @@
 
        <check_box
         control_name="UpperAlphaTextureInvisible"
-        follows="left"
+        follows="left|top"
         height="16"
         layout="topleft"
         left_pad="20"
@@ -73,7 +84,7 @@
 
        <check_box
         control_name="HeadAlphaTextureInvisible"
-        follows="left"
+        follows="left|top"
         height="16"
         layout="topleft"
         left="5"
@@ -98,7 +109,7 @@
 
        <check_box
         control_name="Eye AlphaTextureInvisible"
-        follows="left"
+        follows="left|top"
         height="16"
         layout="topleft"
         left_pad="20"
@@ -123,7 +134,7 @@
 
        <check_box
         control_name="HairAlphaTextureInvisible"
-        follows="left"
+        follows="left|top"
         height="16"
         layout="topleft"
         left="5"
@@ -147,5 +158,6 @@
        </texture_picker>
 
 	 </panel>
+	 </scroll_container>
 </panel>
 
diff --git a/indra/newview/skins/default/xui/en/panel_edit_profile.xml b/indra/newview/skins/default/xui/en/panel_edit_profile.xml
index 90dbddaff7..37265d65f1 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_profile.xml
@@ -328,17 +328,6 @@
        name="homepage_edit"
        width="272">
       </line_editor>
-      <check_box
-       follows="left|top"
-       font="SansSerifSmall"
-       label="Show me in Search results"
-       layout="topleft"
-       left="8"
-       name="show_in_search_checkbox"
-       height="15"
-       label_text.text_color="white"
-       top_pad="12"
-       width="100" />
       <text
          follows="left|top"
          font="SansSerifSmall"
diff --git a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
index 23a08344ea..97f1a1a658 100644
--- a/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
+++ b/indra/newview/skins/default/xui/en/panel_edit_tattoo.xml
@@ -14,7 +14,7 @@
       bg_opaque_color="DkGray2"
       background_visible="true"
       background_opaque="true"
-	  follows="top|left|right"
+	  follows="all"
 	  height="400" 
 	  left="10" 
 	  layout="topleft" 
diff --git a/indra/newview/skins/default/xui/en/panel_group_invite.xml b/indra/newview/skins/default/xui/en/panel_group_invite.xml
index 15a3191bdf..cd834b61ce 100644
--- a/indra/newview/skins/default/xui/en/panel_group_invite.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_invite.xml
@@ -94,7 +94,7 @@
      left_pad="2"
      name="cancel_button"
      top_delta="0"
-     width="70" />
+     width="65" />
 	 <string 
 	 name="GroupInvitation">
 	 Group Invitation
diff --git a/indra/newview/skins/default/xui/en/panel_group_land_money.xml b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
index 1270a21710..61d6cbb2d0 100644
--- a/indra/newview/skins/default/xui/en/panel_group_land_money.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_land_money.xml
@@ -117,7 +117,7 @@
      name="map_button"
      top_delta="-4"
      left_pad="0"
-     width="60"
+     width="57"
      enabled="false" />
     <text
      type="string"
diff --git a/indra/newview/skins/default/xui/en/panel_group_list_item.xml b/indra/newview/skins/default/xui/en/panel_group_list_item.xml
index 0b84ac03c5..12735026fa 100644
--- a/indra/newview/skins/default/xui/en/panel_group_list_item.xml
+++ b/indra/newview/skins/default/xui/en/panel_group_list_item.xml
@@ -34,6 +34,7 @@
      mouse_opaque="true"
      left="5"
      top="2"
+     use_draw_context_alpha="false"
      width="20" />
    <text
      parse_urls="false"
@@ -62,7 +63,7 @@
     <button
      follows="right"
      height="20"
-     image_overlay="ForwardArrow_Off"
+     image_overlay="Web_Profile_Off"
      layout="topleft"
      left_pad="5"
      right="-3"
diff --git a/indra/newview/skins/default/xui/en/panel_landmarks.xml b/indra/newview/skins/default/xui/en/panel_landmarks.xml
index 2a5933e3e9..23d8cb11ca 100644
--- a/indra/newview/skins/default/xui/en/panel_landmarks.xml
+++ b/indra/newview/skins/default/xui/en/panel_landmarks.xml
@@ -114,6 +114,7 @@
 		       height="25"
 		       layout="topleft"
 		       name="options_gear_btn_panel"
+		       user_resize="false"
 		       width="32">
 		          <menu_button
 		           follows="bottom|left"
@@ -134,6 +135,7 @@
 		       height="25"
 		       layout="topleft"
 		       name="add_btn_panel"
+		       user_resize="false"
 		       width="32">
 		          <button
 		           follows="bottom|left"
@@ -154,6 +156,7 @@
 		       height="25"
 		       layout="topleft"
 		       name="dummy_panel"
+		       user_resize="false"
 		       width="212">
 		          <icon
 		           follows="bottom|left|right"
@@ -170,6 +173,7 @@
 		       height="25"
 		       layout="topleft"
 		       name="trash_btn_panel"
+		       user_resize="false"
 		       width="31">
 		          <dnd_button
 		           follows="bottom|left"
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 89feba7c3c..806182bcb4 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -5,17 +5,14 @@ height="600"
 layout="topleft"
 left="0"
 name="panel_login"
+focus_root="true" 
 top="600"
  width="996">
 <panel.string
      name="create_account_url">
        http://join.secondlife.com/
 </panel.string>
-<panel.string
-     name="real_url" translate="false">
-       http://secondlife.com/app/login/
-</panel.string>
-    <string name="reg_in_client_url" translate="false">
+<string name="reg_in_client_url" translate="false">
      http://secondlife.eniac15.lindenlab.com/reg-in-client/
 </string>
 <panel.string
@@ -64,23 +61,28 @@ left="20"
 width="150">
 Username:
 </text>
-<line_editor
+<combo_box
+allow_text_entry="true"
 follows="left|bottom"
 height="22"
-label="bobsmith12 or Steller Sunshine"
 left_delta="0"
-max_length_bytes="63"
-name="username_edit"
-prevalidate_callback="ascii" 
+max_chars="128"
+prevalidate_callback="ascii"
 select_on_focus="true"
 tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"
 top_pad="0"
-width="150" />
+name="username_combo"
+width="178">
+  <combo_box.combo_button
+   visible ="false"/>
+  <combo_box.drop_down_button
+   visible ="false"/>
+</combo_box>
 <text
 follows="left|bottom"
 font="SansSerifSmall"
 height="15"
-left_pad="8"
+left_pad="-19"
 name="password_text"
 top="20"
     width="150">
@@ -91,6 +93,7 @@ follows="left|bottom"
   height="22"
   max_length_bytes="16"
 name="password_edit"
+is_password="true" 
 select_on_focus="true"
   top_pad="0"
   width="135" />
diff --git a/indra/newview/skins/default/xui/en/panel_main_inventory.xml b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
index 2b6e082542..96633cb5b4 100644
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -118,6 +118,7 @@
        height="25"
        layout="topleft"
        name="options_gear_btn_panel"
+       user_resize="false"
        width="32">
           <menu_button
            follows="bottom|left"
@@ -138,6 +139,7 @@
        height="25"
        layout="topleft"
        name="add_btn_panel"
+       user_resize="false"
        width="32">
           <button
            follows="bottom|left"
@@ -158,6 +160,7 @@
        height="25"
        layout="topleft"
        name="dummy_panel"
+       user_resize="false"
        width="212">
           <icon
            follows="bottom|left|right"
@@ -174,6 +177,7 @@
        height="25"
        layout="topleft"
        name="trash_btn_panel"
+       user_resize="false"
        width="31">
           <dnd_button
            follows="bottom|left"
diff --git a/indra/newview/skins/default/xui/en/panel_my_profile.xml b/indra/newview/skins/default/xui/en/panel_my_profile.xml
index 1b41f602cd..4bd2235cda 100644
--- a/indra/newview/skins/default/xui/en/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_my_profile.xml
@@ -31,10 +31,18 @@
      name="no_group_text"
      value="None" />
     <string
-	 name="RegisterDateFormat">
-	 [REG_DATE] ([AGE])
-	</string>
-    <layout_stack
+	   name="RegisterDateFormat">
+	   [REG_DATE] ([AGE])
+	  </string>
+    <string
+      name="name_text_args">
+      [NAME]
+    </string>
+    <string
+      name="display_name_text_args">
+      [DISPLAY_NAME]
+    </string>
+  <layout_stack
      name="layout"
      orientation="vertical"
      follows="all"
@@ -79,11 +87,12 @@
                   name="second_life_image_panel"
                   top="0"
                   width="297">
+
               <texture_picker
                allow_no_texture="true"
                default_image_name="None"
                enabled="false"
-               fallback_image="Generic_Person_Large" 
+               fallback_image="Generic_Person_Large"
                follows="top|left"
                height="124"
                layout="topleft"
@@ -91,258 +100,47 @@
                name="2nd_life_pic"
                top="10"
                width="102" />
-              <icon
-              height="102"
-              image_name="Blank"
-              layout="topleft"
-              name="2nd_life_edit_icon"
-              label=""
-              left="3"
-              tool_tip="Click the Edit Profile button below to change image"
-              top="10"
-              width="102" />
-              <text
-               follows="left|top|right"
-         font.style="BOLD"
-               height="15"
-               layout="topleft"
-               left_pad="10"
-               name="title_sl_descr_text"
-               text_color="white"
-               top_delta="0"
-               value="[SECOND_LIFE]:"
-               width="180" />
-              <expandable_text
-               follows="left|top|right"
-               height="95"
-               layout="topleft"
-               left="107"
-               textbox.max_length="512"
-               textbox.show_context_menu="true"
-               name="sl_description_edit"
-               top_pad="-3"
-               translate="false"
-               width="181"
-               expanded_bg_visible="true"
-               expanded_bg_color="DkGray">
-                Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum.
-              </expandable_text>
-            </panel>
-            <panel
-             follows="left|top|right"
-             height="117"
-             layout="topleft"
-       top_pad="0"
-             left="10"
-             name="first_life_image_panel"
-             width="297">
-              <texture_picker
-               allow_no_texture="true"
-               default_image_name="None"
-               enabled="false"
-               fallback_image="Generic_Person_Large"
-               follows="top|left"
-               height="124"
-               layout="topleft"
-               left="3"
-               name="real_world_pic"
-               width="102" />
-              <icon
-              height="102"
-              image_name="Blank"
-              layout="topleft"
-              name="real_world_edit_icon"
-              label=""
-              left="3"
-              tool_tip="Click the Edit Profile button below to change image"
-              top="4"
-              width="102" />
+
               <text
-               follows="left|top|right"
-         font.style="BOLD"
-               height="15"
-               layout="topleft"
-               left_pad="10"
-               name="title_rw_descr_text"
-               text_color="white"
-               top_delta="0"
-               value="Real World:"
-               width="180" />
-              <expandable_text
-               follows="left|top|right"
-               height="95"
-               layout="topleft"
-               left="107"
-               textbox.max_length="512"
-               textbox.show_context_menu="true"
-               name="fl_description_edit"
-               top_pad="-3"
-               translate="false"
-               width="181"
-               expanded_bg_visible="true"
-               expanded_bg_color="DkGray">
-                Lorem ipsum dolor sit amet, consectetur adlkjpiscing elit moose moose. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet. adipiscing elit. Aenean rigviverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet sorbet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum.
-              </expandable_text>
-            </panel>
-            <text
-             follows="left|top"
-             height="15"
-       font.style="BOLD"
-       font="SansSerifMedium"
-             layout="topleft"
-             left="10"
-             name="homepage_edit"
-             top_pad="0"
-             translate="false"
-             value="http://librarianavengers.org"
-             width="300"
-             word_wrap="false"
-             use_ellipses="true"
-         />
-            <text
-             follows="left|top"
-           font.style="BOLD"
-             height="10"
-             layout="topleft"
-             left="10"
-             name="title_member_text"
-             text_color="white"
-             top_pad="10"
-             value="Resident Since:"
-             width="300" />
-            <text_editor
-             allow_scroll="false"
-             bg_visible="false"
-             follows="left|top"
-             h_pad="0"
-             height="15"
-             layout="topleft"
-             left="10"
-             name="register_date"
-             read_only="true"
-             translate="false"
-             v_pad="0"
-             value="05/31/2376"
-             width="300"
-             word_wrap="true" />
-            <text
-             follows="left|top"
-       font.style="BOLD"
-             height="15"
-             layout="topleft"
-             left="10"
-             name="title_acc_status_text"
-             text_color="white"
-             top_pad="5"
-             value="Account Status:"
-             width="300" />
-            <!-- <text
-         type="string"
-         follows="left|top"
-         font="SansSerifSmall"
-         height="15"
-         layout="topleft"
-         left_pad="10"
-         name="my_account_link"
-         top_delta="0"
-	 value="Go to Dashboard"
-         width="100"/> -->
-            <text_editor
-            allow_scroll="false"
-            bg_visible="false"
-            follows="left|top"
-            h_pad="0"
-            height="28"
-            layout="topleft"
-            left="10"
-            name="acc_status_text"
-            read_only="true"
-            top_pad="0"
-            translate="false"
-            v_pad="0"
-            width="300"
-            word_wrap="true">
-              Resident. No payment info on file.
-              Linden.
-            </text_editor>
-            <text
-             follows="left|top"
-       font.style="BOLD"
-             height="15"
-             layout="topleft"
-             left="10"
-             name="title_partner_text"
-             text_color="white"
-             top_pad="3"
-             value="Partner:"
-             width="300" />
-            <panel
-             follows="left|top"
-             height="15"
-             layout="topleft"
-             left="10"
-             name="partner_data_panel"
-             top_pad="0"
-             width="300">
+                follows="left|top|right"
+                font="SansSerifLarge"
+                font.style="BOLD"
+                height="15"
+                layout="topleft"
+                left_pad="10"
+                name="display_name_descr_text"
+                text_color="0.7 0.7 0.7 1.0"
+                top_delta="0"
+                width="280" >
+                User name
+                </text>
+
               <text
-               follows="left|top"
-               height="10"
-               initial_value="(retrieving)"
-               layout="topleft"
-               left="0"
-               link="true"
-               name="partner_text"
-               top="0"
-               use_ellipses="true" 
-           width="300" />
+                follows="left|top|right"
+                font.style="BOLD"
+                height="15"
+                layout="topleft"
+                left_delta="0"
+                name="name_descr_text"
+                text_color="0.4 0.4 0.4 1.0"
+                top_delta="20"
+                width="280">
+                Display Name
+              </text>
+
+              <button
+                follows="bottom"
+                height="23"
+                left_delta="0"
+                top_delta="20"
+                label="Profile"
+                name="see_profile_btn"
+                tool_tip="See profile for this avatar"
+                width="120" />
+
             </panel>
-            <text
-             follows="left|top"
-       font.style="BOLD"
-             height="13"
-             layout="topleft"
-             left="10"
-             name="title_groups_text"
-             text_color="white"
-             top_pad="3"
-             value="Groups:"
-             width="300" />
-            <expandable_text
-            follows="all"
-            height="113"
-            layout="topleft"
-            left="7"
-            name="sl_groups"
-          top_pad="0"
-            translate="false"
-            textbox.show_context_menu="true"
-            width="298"
-            expanded_bg_visible="true"
-            expanded_bg_color="DkGray">
-              Lorem ipsum dolor sit amet, consectetur adlkjpiscing elit moose moose. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet. adipiscing elit. Aenean rigviverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet sorbet ipsum. adipiscing elit. Aenean viverra orci et justo sagittis aliquet. Nullam malesuada mauris sit amet ipsum. Aenean viverra tulip moosetop. Slan de heelish marfnik tooplod. Sum sum to whop de wompam booster copm.
-            </expandable_text>
           </panel>
         </scroll_container>
       </layout_panel>
       </layout_stack>
- 	<panel
-     follows="bottom|left|right"
-     height="23"
-     layout="topleft"
-     left="0"
-     top_pad="1"
-     name="profile_me_buttons_panel"
-     visible="false"
-     width="315">
-        <button
-         follows="bottom"
-         height="23"
-         left="6"
-	 	 top="1"
-         label="Edit Profile"
-         name="edit_profile_btn"
-         tool_tip="Edit your personal information"
-         width="152" />
- 	</panel>
-
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
index 082d51ed3c..8a7bd53054 100644
--- a/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_navigation_bar.xml
@@ -4,6 +4,7 @@
  background_visible="true"
  bg_opaque_color="MouseGray"
  follows="left|top|right"
+ focus_root="true" 
  height="60"
  layout="topleft"
  name="navigation_bar"
diff --git a/indra/newview/skins/default/xui/en/panel_notify_textbox.xml b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml
index 4634eeed46..d5b6057233 100644
--- a/indra/newview/skins/default/xui/en/panel_notify_textbox.xml
+++ b/indra/newview/skins/default/xui/en/panel_notify_textbox.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes" ?>
 <panel
    background_visible="true"
-   height="230"
+   height="220"
    label="instant_message"
    layout="topleft"
    left="0"
@@ -14,55 +14,81 @@
   <panel
    bevel_style="none"
    follows="left|right|top"
-   height="150"
+   height="185"
    label="info_panel"
    layout="topleft"
    left="0"
    name="info_panel"
    top="0"
-   width="305">
+   width="305">    
+    <text_editor
+     bg_readonly_color="0.0 0.0 0.0 0"
+     enabled="false"
+     follows="left|right|top|bottom"
+     font="SansSerif"
+     height="110" 
+     layout="topleft"
+     left="10"
+     mouse_opaque="false"
+     name="text_editor_box"
+     read_only="true"
+     text_color="white"
+     text_readonly_color="white"
+     top="10"
+     width="285"
+     wrap="true"
+     parse_highlights="true"
+     parse_urls="true"/>
     <text_editor
      parse_urls="true"
      enabled="true"
      follows="all"
-     height="60"
+     height="50"
      layout="topleft"
-     left="25"
+     left="10"
      max_length="250"
      name="message"
      parse_highlights="true"
      read_only="false"
-     top="40"
+     top_pad="10"
      type="string"
      use_ellipses="true"
      value="message"
-     width="260"
-     word_wrap="true" >
+     width="285"
+     word_wrap="true"
+     parse_url="false" >
     </text_editor>
-     parse_urls="false"
-    <button
-     top="110"
-     follows="top|left"
-     height="20"
-     label="Submit"
-     layout="topleft"
-     left="25"
-     name="btn_submit"
-     width="70" />
   </panel>
   <panel
      background_visible="false"
      follows="left|right|bottom"
-     height="0" 
+     height="25" 
      width="290"
      label="control_panel"
      layout="topleft"
      left="10"
      name="control_panel"
-     top_pad="5">
+     top_pad="0">
     <!-- 
 	 Notes:
 	 This panel holds the Ignore button and possibly other buttons of notification.
       -->
+    <button
+     top="0"
+     follows="top|left"
+     height="20"
+     label="Submit"
+     layout="topleft"
+     name="btn_submit"
+     width="70" />
+    <button
+     follows="top|right"
+     height="20"
+     label="Ignore"
+     layout="topleft"
+     left="215"
+     name="ignore_btn"
+     top="0"
+     width="70" />
   </panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_places.xml b/indra/newview/skins/default/xui/en/panel_places.xml
index 21314703b0..d9c357f277 100644
--- a/indra/newview/skins/default/xui/en/panel_places.xml
+++ b/indra/newview/skins/default/xui/en/panel_places.xml
@@ -211,7 +211,7 @@ background_visible="true"
 				    user_resize="false" 
 				    auto_resize="true"
 					width="24">
-						<button
+						<menu_button
 				         follows="bottom|left|right"
 				         height="23"
 				         label="▼"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
index d6e4c56113..37aab059a9 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_advanced.xml
@@ -82,7 +82,7 @@
      control_name="AllowMultipleViewers"
      follows="top|left"
      height="15"
-     label="Allow Multiple Viewer"
+     label="Allow Multiple Viewers"
      layout="topleft"
      left="30"
      name="allow_multiple_viewer_check"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_colors.xml b/indra/newview/skins/default/xui/en/panel_preferences_colors.xml
index 5797a63f4e..8a37822413 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_colors.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_colors.xml
@@ -275,9 +275,9 @@
    height="12"
    name="bubble_chat"
    top_pad="20"
-   width="140"
+   width="450"
    >
-    Bubble chat background:
+    Name tag background color (also affects Bubble Chat):
   </text>
   <color_swatch
    can_apply_immediately="true"
@@ -290,7 +290,7 @@
    left_delta="10"
    top_pad="5"
    name="background"
-   tool_tip="Choose color for bubble chat"
+   tool_tip="Choose name tag color"
    width="44">
    <color_swatch.init_callback
     function="Pref.getUIColor"
@@ -310,6 +310,7 @@
    left_pad="10"
    label_width="70"
    name="bubble_chat_opacity"
+   tool_tip="Choose name tag opacity"
    top_delta = "6"
    width="378" />
   <text
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
index 626122c0b0..ef25588ca3 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_privacy.xml
@@ -40,6 +40,15 @@
      width="300">
        (Locations, images, web, search history)
     </text>
+    <check_box
+	 height="16"
+     enabled="true"
+     label="Show me in Search results"
+     layout="topleft"
+     left="30"
+     name="online_searchresults"
+     top_pad="20"
+     width="350" />
     <check_box
 	 height="16"
 	 enabled="false"
@@ -68,6 +77,16 @@
      left="30"
      name="auto_disengage_mic_check"
      top_pad="10"
+     width="350" />
+    <check_box
+     control_name="ShowFavoritesOnLogin"
+     enabled="false" 
+     height="16"
+     label="Show my Favorite Landmarks at Login (via &apos;Start At&apos; drop-down menu)"
+     layout="topleft"
+     left="30"
+     name="favorites_on_login_check"
+     top_pad="10"
      width="350" />
 	<text
       type="string"
@@ -78,7 +97,7 @@
      left="30"
      mouse_opaque="false"
      name="Logs:"
-     top_pad="30"
+     top_pad="20"
      width="350">
         Chat Logs:
     </text>
@@ -170,7 +189,7 @@
      layout="topleft"
      left="30"
      name="block_list"
-     top_pad="35"
+     top_pad="28"
      width="145">
         <!--<button.commit_callback
          function="SideTray.ShowPanel"-->
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
index 584bd1ea9d..901a1257e0 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml
@@ -142,7 +142,7 @@
    layout="topleft"
    left="80"
    name="Cache location"
-   top_delta="40"
+   top_delta="20"
    width="300">
     Cache location:
   </text>
@@ -341,20 +341,41 @@
    name="web_proxy_port"
    top_delta="0"
    width="145" />
-
-  <check_box
-    top_delta="2"
-    enabled="true"
-    follows="left|top"
-    height="18"
-    initial_value="true"
-    control_name="UpdaterServiceActive"
-    label="Automatically download and install [APP_NAME] updates"
-    left="30"
-    mouse_opaque="true"
-    name="updater_service_active"
-    radio_style="false"
-    width="400"
-    top_pad="10"/>
-
+  <text
+     type="string"
+     length="1"
+     follows="left|top"
+     height="10"
+     layout="topleft"
+     left="30"
+     name="Software updates:"
+     mouse_opaque="false"
+     top_pad="5"
+     width="300">
+    Software updates:
+  </text>
+  <combo_box
+     control_name="UpdaterServiceSetting"
+     follows="left|top"
+     height="23"
+     layout="topleft"
+     left_delta="50"
+	 top_pad="5"
+     name="updater_service_combobox"
+     width="300">
+        <combo_box.item
+         label="Install automatically"
+         name="Install_automatically"
+         value="3" />
+      <!--
+        <combo_box.item
+         label="Ask before installing"
+         name="Install_ask"
+         value="1" />
+      -->
+        <combo_box.item
+         label="Download and install updates manually"
+         name="Install_manual"
+         value="0" />
+  </combo_box>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
index da366f30ae..f0ce8b849a 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_sound.xml
@@ -296,6 +296,7 @@
 	<check_box
 		name="media_auto_play_btn"
 		control_name="ParcelMediaAutoPlayEnable"
+		enabled_control="AudioStreamingMedia"
 		value="true"
 		follows="left|bottom|right"
 		height="15"
diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index efc37c2127..61e3bb354f 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -59,7 +59,7 @@
          left="0"
          name="profile_scroll"
          opaque="true"
-         height="527"
+         height="400"
          width="317"
          top="0">
           <panel
@@ -432,7 +432,7 @@
 			    user_resize="false" 
 			    auto_resize="false"
 				width="24">
-					<button
+					<menu_button
 			         follows="bottom|left|right"
 			         height="23"
 			         label="▼"
diff --git a/indra/newview/skins/default/xui/en/panel_script_ed.xml b/indra/newview/skins/default/xui/en/panel_script_ed.xml
index a041c9b229..627b12cfe1 100644
--- a/indra/newview/skins/default/xui/en/panel_script_ed.xml
+++ b/indra/newview/skins/default/xui/en/panel_script_ed.xml
@@ -180,6 +180,7 @@
      name="Save_btn"
      width="81" />
     <button
+     enabled="false"
      follows="right|bottom"
      height="23"
      label="Edit..."
diff --git a/indra/newview/skins/default/xui/en/panel_status_bar.xml b/indra/newview/skins/default/xui/en/panel_status_bar.xml
index 2f52ca660b..d756dfb7de 100644
--- a/indra/newview/skins/default/xui/en/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_status_bar.xml
@@ -51,7 +51,7 @@
      height="18"
      left="0" 
      name="balance"
-     tool_tip="My Balance"
+     tool_tip="Click to refresh your L$ balance"
      v_pad="4"
      top="0"
      wrap="false" 
diff --git a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
index afaf41d073..e2b3d81bf6 100644
--- a/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
+++ b/indra/newview/skins/default/xui/en/sidepanel_task_info.xml
@@ -533,7 +533,7 @@
 		     left="5"
 		     name="open_btn"
 		     top="0"
-		     width="100" />
+		     width="73" />
 	    <button
 		     follows="bottom|left"
 		     height="23"
@@ -542,7 +542,7 @@
 		     left_pad="5"
 		     name="pay_btn"
 		     top="0"
-		     width="100" />
+		     width="73" />
 	    <button
 		     follows="bottom|left"
 		     height="23"
@@ -551,17 +551,16 @@
 		     left_pad="5"
 		     name="buy_btn"
 		     top="0"
-		     width="100" />
+		     width="73" />
         <button
 		     follows="bottom|left"
 		     height="23"
 		     label="Details"
 		     layout="topleft"
-		     left="5"
+		     left_pad="5"
 		     name="details_btn"
 		     top="0"
-		     width="100"
-			 visible="false" />
+		     width="74" />
 
 	</panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 51fba470cb..752bb6ed3a 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -1716,8 +1716,8 @@ integer llGetRegionAgentCount()
 Returns the number of avatars in the region
 	</string>
 	<string name="LSLTipText_llTextBox" translate="false">
-llTextBox(key avatar, string message, integer chat_channel
-Shows a dialog box on the avatar&apos;s screen with the message.
+llTextBox(key avatar, string message, integer chat_channel)
+Shows a window on the avatar&apos;s screen with the message.
 It contains a text box for input, and if entered that text is chatted on chat_channel.
 	</string>
 	<string name="LSLTipText_llGetAgentLanguage" translate="false">
diff --git a/indra/newview/skins/default/xui/en/widgets/button.xml b/indra/newview/skins/default/xui/en/widgets/button.xml
index 1746a045cf..16241ed84e 100644
--- a/indra/newview/skins/default/xui/en/widgets/button.xml
+++ b/indra/newview/skins/default/xui/en/widgets/button.xml
@@ -19,7 +19,7 @@
         image_color="ButtonImageColor"
         image_color_disabled="ButtonImageColor"
         flash_color="ButtonFlashBgColor"
-	font="SansSerifSmall"
+        font="SansSerifSmall"
         hover_glow_amount="0.15"
         halign="center"
         pad_bottom="3" 
diff --git a/indra/newview/skins/default/xui/en/widgets/check_box.xml b/indra/newview/skins/default/xui/en/widgets/check_box.xml
index 7a60bee338..cca64fad2a 100644
--- a/indra/newview/skins/default/xui/en/widgets/check_box.xml
+++ b/indra/newview/skins/default/xui/en/widgets/check_box.xml
@@ -2,9 +2,17 @@
 <check_box font="SansSerifSmall"
            follows="left|top">
   <check_box.label_text name="checkbox label"
+                        left="20"
+                        bottom="3" 
+                        width="0"
+                        height="0"
                         text_color="LabelTextColor"
                         text_readonly_color="LabelDisabledColor"/>
   <check_box.check_button name="CheckboxCtrl Button"
+                          left="2"
+                          bottom="2"
+                          width="13"
+                          height="13" 
                           commit_on_return="false"
                           label=""
                           is_toggle="true"
diff --git a/indra/newview/skins/default/xui/en/widgets/group_icon.xml b/indra/newview/skins/default/xui/en/widgets/group_icon.xml
index 58d5e19fcc..36ee6dd7eb 100644
--- a/indra/newview/skins/default/xui/en/widgets/group_icon.xml
+++ b/indra/newview/skins/default/xui/en/widgets/group_icon.xml
@@ -2,4 +2,5 @@
 <group_icon
  default_icon_name="Generic_Group"
  image_name="Generic_Group"
- name="group_icon" />
+ name="group_icon"
+ use_draw_context_alpha="false" />
diff --git a/indra/newview/skins/default/xui/es/panel_places.xml b/indra/newview/skins/default/xui/es/panel_places.xml
index 2e349c7fe2..4c90a7e6b4 100644
--- a/indra/newview/skins/default/xui/es/panel_places.xml
+++ b/indra/newview/skins/default/xui/es/panel_places.xml
@@ -21,7 +21,7 @@
 						<button label="Editar" name="edit_btn" tool_tip="Editar la información del hito"/>
 					</layout_panel>
 					<layout_panel name="overflow_btn_lp">
-						<button label="▼" name="overflow_btn" tool_tip="Ver más opciones"/>
+						<menu_button label="▼" name="overflow_btn" tool_tip="Ver más opciones"/>
 					</layout_panel>
 				</layout_stack>
 				<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/es/panel_profile.xml b/indra/newview/skins/default/xui/es/panel_profile.xml
index 5cfe83cd61..339a1f236b 100644
--- a/indra/newview/skins/default/xui/es/panel_profile.xml
+++ b/indra/newview/skins/default/xui/es/panel_profile.xml
@@ -53,7 +53,7 @@
 					<button label="Teleporte" name="teleport" tool_tip="Ofrecer teleporte"/>
 				</layout_panel>
 				<layout_panel name="overflow_btn_lp">
-					<button label="▼" name="overflow_btn" tool_tip="Pagar dinero al Residente o compartir algo del inventario con él"/>
+					<menu_button label="▼" name="overflow_btn" tool_tip="Pagar dinero al Residente o compartir algo del inventario con él"/>
 				</layout_panel>
 			</layout_stack>
 		</layout_panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_places.xml b/indra/newview/skins/default/xui/fr/panel_places.xml
index 7f3601b90d..e252c224f8 100644
--- a/indra/newview/skins/default/xui/fr/panel_places.xml
+++ b/indra/newview/skins/default/xui/fr/panel_places.xml
@@ -21,7 +21,7 @@
 						<button label="Modifier" name="edit_btn" tool_tip="Modifier les informations du repère"/>
 					</layout_panel>
 					<layout_panel name="overflow_btn_lp">
-						<button label="▼" name="overflow_btn" tool_tip="Afficher d&apos;autres options"/>
+						<menu_button label="▼" name="overflow_btn" tool_tip="Afficher d&apos;autres options"/>
 					</layout_panel>
 				</layout_stack>
 				<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/fr/panel_profile.xml b/indra/newview/skins/default/xui/fr/panel_profile.xml
index 4606f5a0c6..6b611923af 100644
--- a/indra/newview/skins/default/xui/fr/panel_profile.xml
+++ b/indra/newview/skins/default/xui/fr/panel_profile.xml
@@ -57,7 +57,7 @@
 					<button label="Téléporter" name="teleport" tool_tip="Proposer une téléportation"/>
 				</layout_panel>
 				<layout_panel name="overflow_btn_lp">
-					<button label="▼" name="overflow_btn" tool_tip="Payer le résident ou partager l&apos;inventaire avec lui"/>
+					<menu_button label="▼" name="overflow_btn" tool_tip="Payer le résident ou partager l&apos;inventaire avec lui"/>
 				</layout_panel>
 			</layout_stack>
 		</layout_panel>
diff --git a/indra/newview/skins/default/xui/it/panel_places.xml b/indra/newview/skins/default/xui/it/panel_places.xml
index e33f8190eb..61830f186f 100644
--- a/indra/newview/skins/default/xui/it/panel_places.xml
+++ b/indra/newview/skins/default/xui/it/panel_places.xml
@@ -21,7 +21,7 @@
 						<button label="Modifica" name="edit_btn" tool_tip="Modifica le informazioni del punto di riferimento"/>
 					</layout_panel>
 					<layout_panel name="overflow_btn_lp">
-						<button label="▼" name="overflow_btn" tool_tip="Mostra ulteriori opzioni"/>
+						<menu_button label="▼" name="overflow_btn" tool_tip="Mostra ulteriori opzioni"/>
 					</layout_panel>
 				</layout_stack>
 				<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/it/panel_profile.xml b/indra/newview/skins/default/xui/it/panel_profile.xml
index 8a8d8f5846..c11adeda3d 100644
--- a/indra/newview/skins/default/xui/it/panel_profile.xml
+++ b/indra/newview/skins/default/xui/it/panel_profile.xml
@@ -53,7 +53,7 @@
 					<button label="Teleport" name="teleport" tool_tip="Offri teleport"/>
 				</layout_panel>
 				<layout_panel name="overflow_btn_lp">
-					<button label="▼" name="overflow_btn" tool_tip="Paga del denaro o condividi qualcosa dall&apos;inventario con il residente"/>
+					<menu_button label="▼" name="overflow_btn" tool_tip="Paga del denaro o condividi qualcosa dall&apos;inventario con il residente"/>
 				</layout_panel>
 			</layout_stack>
 		</layout_panel>
diff --git a/indra/newview/skins/default/xui/ja/panel_places.xml b/indra/newview/skins/default/xui/ja/panel_places.xml
index 3e364c9b3a..e19b86e552 100644
--- a/indra/newview/skins/default/xui/ja/panel_places.xml
+++ b/indra/newview/skins/default/xui/ja/panel_places.xml
@@ -21,7 +21,7 @@
 						<button label="編集" name="edit_btn" tool_tip="ランドマークの情報を編集します"/>
 					</layout_panel>
 					<layout_panel name="overflow_btn_lp">
-						<button label="▼" name="overflow_btn" tool_tip="オプションを表示します"/>
+						<menu_button label="▼" name="overflow_btn" tool_tip="オプションを表示します"/>
 					</layout_panel>
 				</layout_stack>
 				<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/ja/panel_profile.xml b/indra/newview/skins/default/xui/ja/panel_profile.xml
index 860020c87c..c2ffd74ec0 100644
--- a/indra/newview/skins/default/xui/ja/panel_profile.xml
+++ b/indra/newview/skins/default/xui/ja/panel_profile.xml
@@ -57,7 +57,7 @@
 					<button label="テレポート" name="teleport" tool_tip="テレポートを送ります"/>
 				</layout_panel>
 				<layout_panel name="overflow_btn_lp">
-					<button label="▼" name="overflow_btn" tool_tip="住人にお金を渡すか持ち物を共有します"/>
+					<menu_button label="▼" name="overflow_btn" tool_tip="住人にお金を渡すか持ち物を共有します"/>
 				</layout_panel>
 			</layout_stack>
 		</layout_panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_places.xml b/indra/newview/skins/default/xui/pl/panel_places.xml
index e0a0cfd96a..34c105225d 100644
--- a/indra/newview/skins/default/xui/pl/panel_places.xml
+++ b/indra/newview/skins/default/xui/pl/panel_places.xml
@@ -21,7 +21,7 @@
 						<button label="Edytuj" name="edit_btn" tool_tip="Edytuj informacje landmarka"/>
 					</layout_panel>
 					<layout_panel name="overflow_btn_lp">
-						<button label="▼" name="overflow_btn" tool_tip="Pokaż opcje dodatkowe"/>
+						<menu_button label="▼" name="overflow_btn" tool_tip="Pokaż opcje dodatkowe"/>
 					</layout_panel>
 				</layout_stack>
 				<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/pl/panel_profile.xml b/indra/newview/skins/default/xui/pl/panel_profile.xml
index f4a5699f8d..4152c00386 100644
--- a/indra/newview/skins/default/xui/pl/panel_profile.xml
+++ b/indra/newview/skins/default/xui/pl/panel_profile.xml
@@ -42,7 +42,7 @@
 					<button label="Teleportuj" name="teleport" tool_tip="Teleportuj"/>
 				</layout_panel>
 				<layout_panel name="overflow_btn_lp">
-					<button label="▼" name="overflow_btn" tool_tip="Zapłać lub udostępnij obiekt Rezydentowi"/>
+					<menu_button label="▼" name="overflow_btn" tool_tip="Zapłać lub udostępnij obiekt Rezydentowi"/>
 				</layout_panel>
 			</layout_stack>
 		</layout_panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_places.xml b/indra/newview/skins/default/xui/pt/panel_places.xml
index 2e443bc057..828ef3e469 100644
--- a/indra/newview/skins/default/xui/pt/panel_places.xml
+++ b/indra/newview/skins/default/xui/pt/panel_places.xml
@@ -21,7 +21,7 @@
 						<button label="Editar" name="edit_btn" tool_tip="Editar dados do marco"/>
 					</layout_panel>
 					<layout_panel name="overflow_btn_lp">
-						<button label="▼" name="overflow_btn" tool_tip="Mostrar opções adicionais"/>
+						<menu_button label="▼" name="overflow_btn" tool_tip="Mostrar opções adicionais"/>
 					</layout_panel>
 				</layout_stack>
 				<layout_stack name="bottom_bar_ls3">
diff --git a/indra/newview/skins/default/xui/pt/panel_profile.xml b/indra/newview/skins/default/xui/pt/panel_profile.xml
index e4200ae5da..f984ed6a7b 100644
--- a/indra/newview/skins/default/xui/pt/panel_profile.xml
+++ b/indra/newview/skins/default/xui/pt/panel_profile.xml
@@ -53,7 +53,7 @@
 					<button label="Teletransportar" name="teleport" tool_tip="Oferecer teletransporte"/>
 				</layout_panel>
 				<layout_panel name="overflow_btn_lp">
-					<button label="▼" name="overflow_btn" tool_tip="Pagar ou compartilhar inventário com o residente"/>
+					<menu_button label="▼" name="overflow_btn" tool_tip="Pagar ou compartilhar inventário com o residente"/>
 				</layout_panel>
 			</layout_stack>
 		</layout_panel>
-- 
cgit v1.2.3


From 6ba8177410bde7d6041523b436629c9b01e23332 Mon Sep 17 00:00:00 2001
From: Eli Linden <eli@lindenlab.com>
Date: Wed, 19 Jan 2011 12:16:34 -0800
Subject: sync up with Viewer 2.5 from viewer-beta

---
 .../skins/default/xui/en/floater_web_content.xml   | 190 +++++++++++++++++++++
 .../default/xui/en/notification_visibility.xml     |   6 +
 .../skins/default/xui/en/panel_hint_image.xml      |  39 +++++
 .../skins/default/xui/en/widgets/sidetray_tab.xml  |   4 +
 4 files changed, 239 insertions(+)
 create mode 100644 indra/newview/skins/default/xui/en/floater_web_content.xml
 create mode 100644 indra/newview/skins/default/xui/en/notification_visibility.xml
 create mode 100644 indra/newview/skins/default/xui/en/panel_hint_image.xml
 create mode 100644 indra/newview/skins/default/xui/en/widgets/sidetray_tab.xml

diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml
new file mode 100644
index 0000000000..1c64a5eb44
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/floater_web_content.xml
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+  legacy_header_height="18"
+  can_resize="true"
+  height="775"
+  layout="topleft"
+  min_height="400"
+  min_width="500"
+  name="floater_web_content"
+  help_topic="floater_web_content"
+  save_rect="true"
+  auto_tile="true"
+  title=""
+  initial_mime_type="text/html"
+  width="735">
+  <layout_stack
+    bottom="775"
+    follows="left|right|top|bottom"
+    layout="topleft"
+    left="5"
+    name="stack1"
+    orientation="vertical"
+    top="20"
+    width="725">
+    <layout_panel
+      auto_resize="false"
+      default_tab_group="1"
+      height="22"
+      layout="topleft"
+      left="0"
+      min_height="20"
+      name="nav_controls"
+      top="400"
+      user_resize="false"
+      width="725">
+      <button
+        image_overlay="Arrow_Left_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+		    hover_glow_amount="0.15"
+        tool_tip="Navigate back"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="1"
+        name="back"
+        top="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.Back" />
+      </button>
+      <button
+        image_overlay="Arrow_Right_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+        tool_tip="Navigate forward"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="27"
+        name="forward"
+        top_delta="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.Forward" />
+      </button>
+      <button
+        image_overlay="Stop_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+        tool_tip="Stop navigation"
+        enabled="true"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="51"
+        name="stop"
+        top_delta="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.Stop" />
+      </button>
+      <button
+        image_overlay="Refresh_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+        tool_tip="Reload page"
+        follows="left|top"
+        height="22"
+        layout="topleft"
+        left="51"
+        name="reload"
+        top_delta="0"
+        width="22">
+        <button.commit_callback
+          function="WebContent.Reload" />
+      </button>
+      <combo_box
+        allow_text_entry="true"
+        follows="left|top|right"
+        tab_group="1"
+        height="22"
+        layout="topleft"
+        left_pad="4"
+        max_chars="1024"
+        name="address"
+        combo_editor.select_on_focus="true"
+        tool_tip="Enter URL here"
+        top_delta="0"
+        width="627">
+        <combo_box.commit_callback
+          function="WebContent.EnterAddress" />
+      </combo_box>
+      <icon
+        name="media_secure_lock_flag"
+        height="16"
+        follows="top|right"
+        image_name="Lock2"
+        layout="topleft"
+        left_delta="575"
+        top_delta="2"
+        visible="false" 
+        tool_tip="Secured Browsing"
+        width="16" />
+      <button
+        image_overlay="ExternalBrowser_Off"
+		    image_disabled="PushButton_Disabled"
+		    image_disabled_selected="PushButton_Disabled"
+		    image_selected="PushButton_Selected"
+		    image_unselected="PushButton_Off"
+        tool_tip="Open current URL in your desktop browser"
+        follows="right|top"
+        enabled="true" 
+        height="22"
+        layout="topleft"
+        name="popexternal"
+        right="725"
+        top_delta="-2"
+        width="22">
+        <button.commit_callback
+          function="WebContent.PopExternal" />
+      </button>
+    </layout_panel>
+    <layout_panel
+      height="40"
+      layout="topleft"
+      left_delta="0"
+      name="external_controls"
+      top_delta="0"
+      user_resize="false"
+      width="540">
+      <web_browser
+        bottom="-22"
+        follows="all"
+        layout="topleft"
+        left="0"
+        name="webbrowser"
+        top="0"/>
+      <text
+        type="string"
+        length="200"
+        follows="bottom|left"
+        height="20"
+        layout="topleft"
+        left_delta="0"
+        name="statusbartext"
+        parse_urls="false"
+        text_color="0.4 0.4 0.4 1"
+        top_pad="5"
+        width="520"/>
+      <progress_bar
+        color_bar="0.3 1.0 0.3 1"
+        follows="bottom|right"
+        height="16"
+        top_delta="-1"
+        left_pad="24"
+        layout="topleft"
+        name="statusbarprogress"
+        width="64"/>
+    </layout_panel>
+  </layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/en/notification_visibility.xml b/indra/newview/skins/default/xui/en/notification_visibility.xml
new file mode 100644
index 0000000000..db292100d7
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/notification_visibility.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" ?>
+<notification_visibility>
+  <hide tag="custom_skin"/>
+	<show/> 
+</notification_visibility>
+
diff --git a/indra/newview/skins/default/xui/en/panel_hint_image.xml b/indra/newview/skins/default/xui/en/panel_hint_image.xml
new file mode 100644
index 0000000000..00b6e42497
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_hint_image.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ width="205"
+ height="140"
+ layout="topleft">
+  <text name="hint_title"
+        font="SansSerifMedium" 
+        left="8"
+        right="180"
+        top="8"
+        bottom="20"
+        follows="left|right|top"
+        text_color="Black"
+        wrap="false"/>
+  <icon name="hint_image"
+        left="42"
+        top="25"
+        width="115"
+        height="86"
+        image_name="arrow_keys.png"
+        />
+  <text name="hint_text"
+        left="8"
+        right="197"
+        top_pad="5"
+        bottom="120"
+        follows="all" 
+        text_color="Black"
+        wrap="true"/>
+  <button right="197" 
+          top="8"
+          width="16" 
+          height="16"
+          name="close" 
+          follows="right|top" 
+          image_color="DkGray" 
+          image_unselected="Icon_Close_Foreground"
+          image_selected="Icon_Close_Press"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/en/widgets/sidetray_tab.xml b/indra/newview/skins/default/xui/en/widgets/sidetray_tab.xml
new file mode 100644
index 0000000000..aa8461d367
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/widgets/sidetray_tab.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<sidetray_tab 
+  focus_root="true"
+  />
-- 
cgit v1.2.3


From f91a9c87e5e758ecd32111d901ff32d282b73fa7 Mon Sep 17 00:00:00 2001
From: Dave SIMmONs <simon@lindenlab.com>
Date: Wed, 19 Jan 2011 12:54:05 -0800
Subject: ER-428 / CTS-422 : [PUBLIC] movement updates are lost when walking. 
 Changed code to detect if the circuit has stopped getting packets.  Reviewed
 by Andrew

---
 indra/llmessage/llcircuit.cpp    |  3 +++
 indra/llmessage/llcircuit.h      |  4 +++-
 indra/newview/llviewerobject.cpp | 14 ++++++--------
 indra/newview/llviewerobject.h   |  1 -
 4 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/indra/llmessage/llcircuit.cpp b/indra/llmessage/llcircuit.cpp
index 3ba2dfb104..e0410906fb 100644
--- a/indra/llmessage/llcircuit.cpp
+++ b/indra/llmessage/llcircuit.cpp
@@ -87,6 +87,7 @@ LLCircuitData::LLCircuitData(const LLHost &host, TPACKETID in_id,
 	mPingDelayAveraged((F32)INITIAL_PING_VALUE_MSEC), 
 	mUnackedPacketCount(0),
 	mUnackedPacketBytes(0),
+	mLastPacketInTime(0.0),
 	mLocalEndPointID(),
 	mPacketsOut(0),
 	mPacketsIn(0), 
@@ -667,6 +668,8 @@ void LLCircuitData::checkPacketInID(TPACKETID id, BOOL receive_resent)
 		mHighestPacketID = llmax(mHighestPacketID, id);
 	}
 
+	// Save packet arrival time
+	mLastPacketInTime = LLMessageSystem::getMessageTimeSeconds();
 
 	// Have we received anything on this circuit yet?
 	if (0 == mPacketsIn)
diff --git a/indra/llmessage/llcircuit.h b/indra/llmessage/llcircuit.h
index 874c0c0bee..d1c400c6a2 100644
--- a/indra/llmessage/llcircuit.h
+++ b/indra/llmessage/llcircuit.h
@@ -122,7 +122,7 @@ public:
 	U32			getPacketsLost() const;
 	TPACKETID	getPacketOutID() const;
 	BOOL		getTrusted() const;
-	F32 getAgeInSeconds() const;
+	F32			getAgeInSeconds() const;
 	S32			getUnackedPacketCount() const	{ return mUnackedPacketCount; }
 	S32			getUnackedPacketBytes() const	{ return mUnackedPacketBytes; }
 	F64         getNextPingSendTime() const { return mNextPingSendTime; }
@@ -130,6 +130,7 @@ public:
                     { return mOutOfOrderRate.meanValue(scale); }
     U32         getLastPacketGap() const { return mLastPacketGap; }
     LLHost      getHost() const { return mHost; }
+	F64			getLastPacketInTime() const		{ return mLastPacketInTime;	}
 
 	LLThrottleGroup &getThrottleGroup()		{	return mThrottles; }
 
@@ -248,6 +249,7 @@ protected:
 	S32										mUnackedPacketCount;
 	S32										mUnackedPacketBytes;
 
+	F64										mLastPacketInTime;		// Time of last packet arrival
 
 	LLUUID									mLocalEndPointID;
 
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 48794c4c9d..090d3cadd4 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -210,7 +210,6 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
 	mLastInterpUpdateSecs(0.f),
 	mLastMessageUpdateSecs(0.f),
 	mLatestRecvPacketID(0),
-	mCircuitPacketCount(0),
 	mData(NULL),
 	mAudioSourcep(NULL),
 	mAudioGain(1.f),
@@ -1884,7 +1883,6 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys,
 	}
 
 	mLatestRecvPacketID = packet_id;
-	mCircuitPacketCount = 0;
 
 	// Set the change flags for scale
 	if (new_scale != getScale())
@@ -2207,7 +2205,8 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt)
 		LLVector3 new_pos = (vel + (0.5f * (dt-PHYSICS_TIMESTEP)) * accel) * dt;	
 		LLVector3 new_v = accel * dt;
 
-		if (time_since_last_update > sPhaseOutUpdateInterpolationTime)
+		if (time_since_last_update > sPhaseOutUpdateInterpolationTime &&
+			sPhaseOutUpdateInterpolationTime > 0.0)
 		{	// Haven't seen a viewer update in a while, check to see if the ciruit is still active
 			if (mRegionp)
 			{	// The simulator will NOT send updates if the object continues normally on the path
@@ -2216,9 +2215,12 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt)
 				LLCircuitData *cdp = gMessageSystem->mCircuitInfo.findCircuit( mRegionp->getHost() );
 				if (cdp)
 				{
+					// Find out how many seconds since last packet arrived on the circuit
+					F64 time_since_last_packet = LLMessageSystem::getMessageTimeSeconds() - cdp->getLastPacketInTime();
+
 					if (!cdp->isAlive() ||		// Circuit is dead or blocked
 						 cdp->isBlocked() ||	// or doesn't seem to be getting any packets
-						 (mCircuitPacketCount > 0 && mCircuitPacketCount == cdp->getPacketsIn()))
+						 (time_since_last_packet > sPhaseOutUpdateInterpolationTime))
 					{
 						// Start to reduce motion interpolation since we haven't seen a server update in a while
 						F64 time_since_last_interpolation = time - mLastInterpUpdateSecs;
@@ -2249,9 +2251,6 @@ void LLViewerObject::interpolateLinearMotion(const F64 & time, const F32 & dt)
 						new_pos = new_pos * ((F32) phase_out);
 						new_v = new_v * ((F32) phase_out);
 					}
-
-					// Save current circuit packet count to see if it changes 
-					mCircuitPacketCount = cdp->getPacketsIn();
 				}
 			}
 		}
@@ -5105,7 +5104,6 @@ void LLViewerObject::setRegion(LLViewerRegion *regionp)
 	}
 	
 	mLatestRecvPacketID = 0;
-	mCircuitPacketCount = 0;
 	mRegionp = regionp;
 
 	for (child_list_t::iterator i = mChildList.begin(); i != mChildList.end(); ++i)
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 614a5e59fa..7afb7f464b 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -613,7 +613,6 @@ protected:
 	F64				mLastInterpUpdateSecs;			// Last update for purposes of interpolation
 	F64				mLastMessageUpdateSecs;			// Last update from a message from the simulator
 	TPACKETID		mLatestRecvPacketID;			// Latest time stamp on message from simulator
-	U32				mCircuitPacketCount;			// Packet tracking for early detection of a stopped simulator circuit
 
 	// extra data sent from the sim...currently only used for tree species info
 	U8* mData;
-- 
cgit v1.2.3


From 47e31543932815adf89712229c0ad71b17d8a0f1 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 19 Jan 2011 21:17:38 -0700
Subject: fix for SH-730: sculpted prim attachment shapes on impostored avatars
 load very slowly

---
 indra/newview/llviewertexture.cpp |  3 +++
 indra/newview/llvovolume.cpp      | 32 +++++++++++++++++++++++---------
 indra/newview/llvovolume.h        |  1 +
 indra/newview/pipeline.cpp        | 34 +++++++++++++++++-----------------
 4 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index f96b93da4d..1c246a5c87 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -1205,12 +1205,15 @@ void LLViewerFetchedTexture::cleanup()
 
 void LLViewerFetchedTexture::setForSculpt()
 {
+	static const S32 MAX_INTERVAL = 8 ; //frames
+
 	mForSculpt = TRUE ;
 	if(isForSculptOnly() && !getBoundRecently())
 	{
 		destroyGLTexture() ; //sculpt image does not need gl texture.
 	}
 	checkCachedRawSculptImage() ;
+	setMaxVirtualSizeResetInterval(MAX_INTERVAL) ;
 }
 
 BOOL LLViewerFetchedTexture::isForSculptOnly() const
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 858e0321e1..f67e3a9770 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -669,11 +669,32 @@ void LLVOVolume::updateTextures()
 	}
 }
 
+BOOL LLVOVolume::isVisible() const 
+{
+	if(mDrawable.notNull() && mDrawable->isVisible())
+	{
+		return TRUE ;
+	}
+
+	if(isAttachment())
+	{
+		LLViewerObject* objp = (LLViewerObject*)getParent() ;
+		while(objp && !objp->isAvatar())
+		{
+			objp = (LLViewerObject*)objp->getParent() ;
+		}
+
+		return objp && objp->mDrawable.notNull() && objp->mDrawable->isVisible() ;
+	}
+
+	return FALSE ;
+}
+
 void LLVOVolume::updateTextureVirtualSize()
 {
 	// Update the pixel area of all faces
 
-	if(mDrawable.isNull() || !mDrawable->isVisible())
+	if(!isVisible())
 	{
 		return ;
 	}
@@ -2740,14 +2761,7 @@ void LLVOVolume::updateRadius()
 
 BOOL LLVOVolume::isAttachment() const
 {
-	if (mState == 0)
-	{
-		return FALSE;
-	}
-	else
-	{
-		return TRUE;
-	}
+	return mState != 0 ;
 }
 
 BOOL LLVOVolume::isHUDAttachment() const
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 1e9b9737b1..8b68e7c78a 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -102,6 +102,7 @@ public:
 				void	animateTextures();
 	/*virtual*/ BOOL	idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
 
+	            BOOL    isVisible() const ;
 	/*virtual*/ BOOL	isActive() const;
 	/*virtual*/ BOOL	isAttachment() const;
 	/*virtual*/ BOOL	isRootEdit() const; // overridden for sake of attachments treating themselves as a root object
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index e6c6c74fce..db5d6ac4ef 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1969,12 +1969,12 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
 
 	if(drawablep && !drawablep->isDead())
 	{
-	if (drawablep->isSpatialBridge())
-	{
+		if (drawablep->isSpatialBridge())
+		{
 			const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
 			llassert(root); // trying to catch a bad assumption
 			if (root && //  // this test may not be needed, see above
-			    root->getVObj()->isAttachment())
+					root->getVObj()->isAttachment())
 			{
 				LLDrawable* rootparent = root->getParent();
 				if (rootparent) // this IS sometimes NULL
@@ -1982,24 +1982,24 @@ void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
 					LLViewerObject *vobj = rootparent->getVObj();
 					llassert(vobj); // trying to catch a bad assumption
 					if (vobj) // this test may not be needed, see above
-		{
+					{
 						const LLVOAvatar* av = vobj->asAvatar();
-			if (av && av->isImpostor())
-			{
-				return;
-			}
-		}
+						if (av && av->isImpostor())
+						{
+							return;
+						}
+					}
 				}
 			}
-		sCull->pushBridge((LLSpatialBridge*) drawablep);
-	}
-	else
-	{
-		sCull->pushDrawable(drawablep);
-	}
+			sCull->pushBridge((LLSpatialBridge*) drawablep);
+		}
+		else
+		{
+			sCull->pushDrawable(drawablep);
+		}
 
-	drawablep->setVisible(camera);
-}
+		drawablep->setVisible(camera);
+	}
 }
 
 void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
-- 
cgit v1.2.3


From e3f5b66d5a649b061e470bba44fa29a56f7b93b5 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Thu, 20 Jan 2011 15:20:27 -0700
Subject: fix for SH-829: Viewer attempting to load precached images in file
 types that are not being used.

---
 indra/llimage/llimage.cpp        | 18 +++++++++---------
 indra/llimage/llimage.h          |  4 ++--
 indra/newview/lltexturecache.cpp |  6 ++++++
 3 files changed, 17 insertions(+), 11 deletions(-)

diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index 5c33b675ca..38396916c7 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -276,11 +276,11 @@ LLImageRaw::LLImageRaw(U8 *data, U16 width, U16 height, S8 components)
 	++sRawImageCount;
 }
 
-LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
-	: LLImageBase()
-{
-	createFromFile(filename, j2c_lowest_mip_only);
-}
+//LLImageRaw::LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only)
+//	: LLImageBase()
+//{
+//	createFromFile(filename, j2c_lowest_mip_only);
+//}
 
 LLImageRaw::~LLImageRaw()
 {
@@ -1180,7 +1180,7 @@ file_extensions[] =
 	{ "png", IMG_CODEC_PNG }
 };
 #define NUM_FILE_EXTENSIONS LL_ARRAY_SIZE(file_extensions)
-
+#if 0
 static std::string find_file(std::string &name, S8 *codec)
 {
 	std::string tname;
@@ -1198,7 +1198,7 @@ static std::string find_file(std::string &name, S8 *codec)
 	}
 	return std::string("");
 }
-
+#endif
 EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
 {
 	for (int i=0; i<(int)(NUM_FILE_EXTENSIONS); i++)
@@ -1208,7 +1208,7 @@ EImageCodec LLImageBase::getCodecFromExtension(const std::string& exten)
 	}
 	return IMG_CODEC_INVALID;
 }
-
+#if 0
 bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip_only)
 {
 	std::string name = filename;
@@ -1315,7 +1315,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
 
 	return true;
 }
-
+#endif
 //---------------------------------------------------------------------------
 // LLImageFormatted
 //---------------------------------------------------------------------------
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index bca7e915fa..825b9aab1a 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -164,7 +164,7 @@ public:
 	LLImageRaw(U16 width, U16 height, S8 components);
 	LLImageRaw(U8 *data, U16 width, U16 height, S8 components);
 	// Construct using createFromFile (used by tools)
-	LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
+	//LLImageRaw(const std::string& filename, bool j2c_lowest_mip_only = false);
 
 	/*virtual*/ void deleteData();
 	/*virtual*/ U8* allocateData(S32 size = -1);
@@ -226,7 +226,7 @@ public:
 
 protected:
 	// Create an image from a local file (generally used in tools)
-	bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false);
+	//bool createFromFile(const std::string& filename, bool j2c_lowest_mip_only = false);
 
 	void copyLineScaled( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len, S32 in_pixel_step, S32 out_pixel_step );
 	void compositeRowScaled4onto3( U8* in, U8* out, S32 in_pixel_len, S32 out_pixel_len );
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 6a213309a0..83772496d5 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -326,6 +326,7 @@ bool LLTextureCacheRemoteWorker::doRead()
 	// First state / stage : find out if the file is local
 	if (mState == INIT)
 	{
+#if 0
 		std::string filename = mCache->getLocalFileName(mID);	
 		// Is it a JPEG2000 file? 
 		{
@@ -360,6 +361,11 @@ bool LLTextureCacheRemoteWorker::doRead()
 		}
 		// Determine the next stage: if we found a file, then LOCAL else CACHE
 		mState = (local_size > 0 ? LOCAL : CACHE);
+
+		llassert_always(mState == CACHE) ;
+#else
+		mState = CACHE;
+#endif
 	}
 
 	// Second state / stage : if the file is local, load it and leave
-- 
cgit v1.2.3


From 97a9211d87fac90994846e5bf91a78a708ec5a9c Mon Sep 17 00:00:00 2001
From: Aleric Inglewood <Aleric.Inglewood@gmail.com>
Date: Fri, 21 Jan 2011 15:48:12 -0500
Subject: VWR-24354: correct manifest dependencies to prevent parallel install
 problem

---
 doc/contributions.txt        |  1 +
 indra/newview/CMakeLists.txt | 34 ++++++++++++++++++++++------------
 2 files changed, 23 insertions(+), 12 deletions(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 70ae5a2ba5..b601f93806 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -83,6 +83,7 @@ Aleric Inglewood
 	VWR-24315
 	VWR-24317
 	VWR-24320
+ 	VWR-24354
 	SNOW-84
 	SNOW-477
 	SNOW-744
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 5d2342e925..af6beacdfa 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1718,6 +1718,17 @@ set(ARTWORK_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE PATH
 if (LINUX)
   set(product SecondLife-${ARCH}-${viewer_VERSION})
 
+  # These are the generated targets that are copied to package/
+  set(COPY_INPUT_DEPENDENCIES
+	${VIEWER_BINARY_NAME}
+	linux-crash-logger
+	linux-updater
+	SLPlugin
+	media_plugin_webkit
+	media_plugin_gstreamer010
+	llcommon
+	)
+
   add_custom_command(
       OUTPUT ${product}.tar.bz2
       COMMAND ${PYTHON_EXECUTABLE}
@@ -1735,18 +1746,11 @@ if (LINUX)
         --login_channel=${VIEWER_LOGIN_CHANNEL}
         --source=${CMAKE_CURRENT_SOURCE_DIR}
         --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched
-      DEPENDS ${VIEWER_BINARY_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+      DEPENDS
+        ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py
+        ${COPY_INPUT_DEPENDENCIES}
       )
 
-  add_dependencies(${VIEWER_BINARY_NAME} SLPlugin media_plugin_gstreamer010 media_plugin_webkit)
-
-  if (PACKAGE)
-    add_custom_target(package ALL DEPENDS ${product}.tar.bz2)
-    add_dependencies(package linux-crash-logger-target)
-    add_dependencies(package linux-updater-target)
-    check_message_template(package)
-  endif (PACKAGE)
-
   add_custom_command(
     OUTPUT  ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched
     COMMAND ${PYTHON_EXECUTABLE}
@@ -1766,9 +1770,15 @@ if (LINUX)
       ${COPY_INPUT_DEPENDENCIES}
     COMMENT "Performing viewer_manifest copy"
     )
-    
+
   add_custom_target(copy_l_viewer_manifest ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.copy_touched) 
-  add_dependencies(copy_l_viewer_manifest "${VIEWER_BINARY_NAME}" linux-crash-logger-target linux-updater-target)
+
+  if (PACKAGE)
+    add_custom_target(package ALL DEPENDS ${product}.tar.bz2)
+    # Make sure we don't run two instances of viewer_manifest.py at the same time.
+    add_dependencies(package copy_l_viewer_manifest)
+    check_message_template(package)
+  endif (PACKAGE)
 endif (LINUX)
 
 if (DARWIN)
-- 
cgit v1.2.3


From ee6a40beb102819fcd2e95106fe7892d2d25193f Mon Sep 17 00:00:00 2001
From: Aleric Inglewood <Aleric.Inglewood@gmail.com>
Date: Fri, 21 Jan 2011 16:02:38 -0500
Subject: VWR-24519: make debugging easier by not spawning spare process

---
 doc/contributions.txt           |  1 +
 indra/newview/llviewermedia.cpp | 10 +++++++---
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index b601f93806..66533d8da9 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -84,6 +84,7 @@ Aleric Inglewood
 	VWR-24317
 	VWR-24320
  	VWR-24354
+	VWR-24519
 	SNOW-84
 	SNOW-477
 	SNOW-744
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index d3b6dcd86f..ed18d67b62 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1436,9 +1436,12 @@ void LLViewerMedia::proxyWindowClosed(const std::string &uuid)
 // static
 void LLViewerMedia::createSpareBrowserMediaSource()
 {
-	if(!sSpareBrowserMediaSource)
+	// If we don't have a spare browser media source, create one.
+	// However, if PluginAttachDebuggerToPlugins is set then don't spawn a spare
+	// SLPlugin process in order to not be confused by an unrelated gdb terminal
+	// popping up at the moment we start a media plugin.
+	if (!sSpareBrowserMediaSource && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
 	{
-		// If we don't have a spare browser media source, create one.
 		// The null owner will keep the browser plugin from fully initializing 
 		// (specifically, it keeps LLPluginClassMedia from negotiating a size change, 
 		// which keeps MediaPluginWebkit::initBrowserWindow from doing anything until we have some necessary data, like the background color)
@@ -1694,7 +1697,8 @@ LLPluginClassMedia* LLViewerMediaImpl::newSourceFromMediaType(std::string media_
 	LLPluginClassMedia* media_source = NULL;
 	
 	// HACK: we always try to keep a spare running webkit plugin around to improve launch times.
-	if(plugin_basename == "media_plugin_webkit")
+	// If a spare was already created before PluginAttachDebuggerToPlugins was set, don't use it.
+	if(plugin_basename == "media_plugin_webkit" && !gSavedSettings.getBOOL("PluginAttachDebuggerToPlugins"))
 	{
 		media_source = LLViewerMedia::getSpareBrowserMediaSource();
 		if(media_source)
-- 
cgit v1.2.3


From 7a453b7c9351a743b222bbb2b94809cf7c6b3ce8 Mon Sep 17 00:00:00 2001
From: Oz Linden <oz@lindenlab.com>
Date: Fri, 21 Jan 2011 16:20:29 -0500
Subject: add missing entry in contributions.txt for VWR-24347

---
 doc/contributions.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 66533d8da9..5255acc041 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -384,6 +384,7 @@ Jonathan Yap
 	STORM-785
 	STORM-812
 	VWR-17801
+	VWR-24347
 	STORM-844
 Kage Pixel
 	VWR-11
-- 
cgit v1.2.3


From c47e606625750ee1669e3b3b2d9cc7d210f08823 Mon Sep 17 00:00:00 2001
From: Eli Linden <eli@lindenlab.com>
Date: Fri, 21 Jan 2011 16:11:09 -0800
Subject: INTL-20,CT-635 WIP DE,FR,ES,PT,PL translation for Viewer 2.5

---
 indra/newview/skins/default/xui/de/menu_login.xml  |  3 +-
 .../newview/skins/default/xui/de/menu_mini_map.xml |  1 +
 indra/newview/skins/default/xui/de/menu_viewer.xml |  7 +-
 .../newview/skins/default/xui/de/notifications.xml | 80 ++++++++++++++-----
 .../default/xui/de/panel_avatar_list_item.xml      |  2 +-
 .../skins/default/xui/de/panel_edit_alpha.xml      | 16 ++--
 indra/newview/skins/default/xui/de/panel_login.xml |  2 +-
 .../skins/default/xui/de/panel_my_profile.xml      | 33 ++++----
 .../skins/default/xui/de/panel_notify_textbox.xml  |  5 +-
 .../default/xui/de/panel_preferences_colors.xml    |  6 +-
 .../default/xui/de/panel_preferences_privacy.xml   |  2 +
 .../default/xui/de/panel_preferences_setup.xml     |  8 +-
 .../skins/default/xui/de/panel_status_bar.xml      |  2 +-
 indra/newview/skins/default/xui/es/menu_login.xml  |  3 +-
 .../newview/skins/default/xui/es/menu_mini_map.xml |  1 +
 indra/newview/skins/default/xui/es/menu_viewer.xml |  7 +-
 .../newview/skins/default/xui/es/notifications.xml | 82 +++++++++++++++-----
 .../default/xui/es/panel_avatar_list_item.xml      |  2 +-
 .../skins/default/xui/es/panel_edit_alpha.xml      | 16 ++--
 indra/newview/skins/default/xui/es/panel_login.xml |  2 +-
 .../skins/default/xui/es/panel_my_profile.xml      | 29 ++++---
 .../skins/default/xui/es/panel_notify_textbox.xml  |  5 +-
 .../default/xui/es/panel_preferences_colors.xml    |  6 +-
 .../default/xui/es/panel_preferences_privacy.xml   |  2 +
 .../default/xui/es/panel_preferences_setup.xml     |  8 +-
 .../skins/default/xui/es/panel_status_bar.xml      |  2 +-
 indra/newview/skins/default/xui/fr/menu_login.xml  |  3 +-
 .../newview/skins/default/xui/fr/menu_mini_map.xml |  1 +
 indra/newview/skins/default/xui/fr/menu_viewer.xml |  7 +-
 .../newview/skins/default/xui/fr/notifications.xml | 82 +++++++++++++++-----
 .../default/xui/fr/panel_avatar_list_item.xml      |  2 +-
 .../skins/default/xui/fr/panel_edit_alpha.xml      | 16 ++--
 indra/newview/skins/default/xui/fr/panel_login.xml |  2 +-
 .../skins/default/xui/fr/panel_my_profile.xml      | 33 ++++----
 .../skins/default/xui/fr/panel_notify_textbox.xml  |  5 +-
 .../default/xui/fr/panel_preferences_colors.xml    |  6 +-
 .../default/xui/fr/panel_preferences_privacy.xml   |  2 +
 .../default/xui/fr/panel_preferences_setup.xml     |  8 +-
 .../skins/default/xui/fr/panel_status_bar.xml      |  2 +-
 .../default/xui/pl/floater_hardware_settings.xml   |  3 +
 .../skins/default/xui/pl/floater_preferences.xml   |  4 +-
 .../default/xui/pl/menu_inventory_gear_default.xml |  9 ++-
 indra/newview/skins/default/xui/pl/menu_login.xml  |  3 +-
 .../newview/skins/default/xui/pl/menu_mini_map.xml |  1 +
 indra/newview/skins/default/xui/pl/menu_viewer.xml | 26 ++++---
 .../newview/skins/default/xui/pl/notifications.xml | 89 +++++++++++++++++-----
 .../default/xui/pl/panel_avatar_list_item.xml      |  2 +-
 .../skins/default/xui/pl/panel_edit_alpha.xml      | 16 ++--
 .../skins/default/xui/pl/panel_edit_gloves.xml     |  2 +-
 .../skins/default/xui/pl/panel_edit_jacket.xml     |  4 +-
 .../skins/default/xui/pl/panel_edit_pants.xml      |  2 +-
 .../skins/default/xui/pl/panel_edit_shirt.xml      |  2 +-
 .../skins/default/xui/pl/panel_edit_shoes.xml      |  2 +-
 .../skins/default/xui/pl/panel_edit_skirt.xml      |  2 +-
 .../skins/default/xui/pl/panel_edit_socks.xml      |  2 +-
 .../skins/default/xui/pl/panel_edit_underpants.xml |  2 +-
 .../skins/default/xui/pl/panel_edit_undershirt.xml |  2 +-
 indra/newview/skins/default/xui/pl/panel_login.xml |  5 +-
 .../skins/default/xui/pl/panel_my_profile.xml      | 29 ++++---
 .../newview/skins/default/xui/pl/panel_people.xml  | 10 +--
 .../default/xui/pl/panel_preferences_advanced.xml  | 29 ++-----
 .../default/xui/pl/panel_preferences_chat.xml      | 43 ++---------
 .../default/xui/pl/panel_preferences_general.xml   | 12 ++-
 .../default/xui/pl/panel_preferences_graphics1.xml |  1 +
 .../default/xui/pl/panel_preferences_privacy.xml   | 11 ++-
 .../default/xui/pl/panel_preferences_setup.xml     | 15 ++--
 .../default/xui/pl/panel_preferences_sound.xml     |  8 ++
 .../skins/default/xui/pl/panel_script_ed.xml       | 11 +--
 .../skins/default/xui/pl/panel_status_bar.xml      |  2 +-
 indra/newview/skins/default/xui/pl/strings.xml     |  7 +-
 indra/newview/skins/default/xui/pt/menu_login.xml  |  3 +-
 .../newview/skins/default/xui/pt/menu_mini_map.xml |  1 +
 indra/newview/skins/default/xui/pt/menu_viewer.xml |  7 +-
 .../newview/skins/default/xui/pt/notifications.xml | 82 +++++++++++++++-----
 .../default/xui/pt/panel_avatar_list_item.xml      |  2 +-
 .../skins/default/xui/pt/panel_edit_alpha.xml      | 16 ++--
 indra/newview/skins/default/xui/pt/panel_login.xml |  2 +-
 .../skins/default/xui/pt/panel_my_profile.xml      | 29 ++++---
 .../skins/default/xui/pt/panel_notify_textbox.xml  |  5 +-
 .../default/xui/pt/panel_preferences_colors.xml    |  6 +-
 .../default/xui/pt/panel_preferences_privacy.xml   |  2 +
 .../default/xui/pt/panel_preferences_setup.xml     |  8 +-
 .../skins/default/xui/pt/panel_status_bar.xml      |  2 +-
 83 files changed, 630 insertions(+), 392 deletions(-)

diff --git a/indra/newview/skins/default/xui/de/menu_login.xml b/indra/newview/skins/default/xui/de/menu_login.xml
index 70d31f93de..a373e15338 100644
--- a/indra/newview/skins/default/xui/de/menu_login.xml
+++ b/indra/newview/skins/default/xui/de/menu_login.xml
@@ -17,7 +17,8 @@
 		<menu_item_call label="Fenstergröße einstellen..." name="Set Window Size..."/>
 		<menu_item_call label="Servicebedingungen anzeigen" name="TOS"/>
 		<menu_item_call label="Wichtige Meldung anzeigen" name="Critical"/>
-		<menu_item_call label="Web-Browser-Test" name="Web Browser Test"/>
+		<menu_item_call label="Test Medienbrowser" name="Web Browser Test"/>
+		<menu_item_call label="Test Webinhalt-Floater" name="Web Content Floater Test"/>
 		<menu_item_check label="Grid-Auswahl anzeigen" name="Show Grid Picker"/>
 		<menu_item_call label="Benachrichtigungs-Konsole anzeigen" name="Show Notifications Console"/>
 	</menu>
diff --git a/indra/newview/skins/default/xui/de/menu_mini_map.xml b/indra/newview/skins/default/xui/de/menu_mini_map.xml
index bec79be34d..2e0d72c40c 100644
--- a/indra/newview/skins/default/xui/de/menu_mini_map.xml
+++ b/indra/newview/skins/default/xui/de/menu_mini_map.xml
@@ -3,6 +3,7 @@
 	<menu_item_call label="Zoom Nah" name="Zoom Close"/>
 	<menu_item_call label="Zoom Mittel" name="Zoom Medium"/>
 	<menu_item_call label="Zoom Weit" name="Zoom Far"/>
+	<menu_item_call label="Zoom-Standard" name="Zoom Default"/>
 	<menu_item_check label="Karte drehen" name="Rotate Map"/>
 	<menu_item_check label="Automatisch zentrieren" name="Auto Center"/>
 	<menu_item_call label="Verfolgung abschalten" name="Stop Tracking"/>
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index 9eeeaccdea..4a043e1233 100644
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -121,13 +121,15 @@
 			<menu_item_call label="Animation ([COST] L$)..." name="Upload Animation"/>
 			<menu_item_call label="Mehrfach-Upload ([COST] L$ pro Datei)..." name="Bulk Upload"/>
 		</menu>
+		<menu_item_call label="Rückgängig" name="Undo"/>
+		<menu_item_call label="Wiederholen" name="Redo"/>
 	</menu>
 	<menu label="Hilfe" name="Help">
 		<menu_item_call label="[SECOND_LIFE]-Hilfe" name="Second Life Help"/>
+		<menu_item_check label="Hinweise aktivieren" name="Enable Hints"/>
 		<menu_item_call label="Missbrauch melden" name="Report Abuse"/>
 		<menu_item_call label="Fehler melden" name="Report Bug"/>
 		<menu_item_call label="INFO ÜBER [APP_NAME]" name="About Second Life"/>
-		<menu_item_check label="Hinweise aktivieren" name="Enable Hints"/>
 	</menu>
 	<menu label="Erweitert" name="Advanced">
 		<menu_item_call label="Textur neu laden" name="Rebake Texture"/>
@@ -308,7 +310,8 @@
 			<menu_item_call label="Regionsobjekt-Cache ausgeben" name="Dump Region Object Cache"/>
 		</menu>
 		<menu label="UI" name="UI">
-			<menu_item_call label="Web-Browser-Test" name="Web Browser Test"/>
+			<menu_item_call label="Test Medienbrowser" name="Web Browser Test"/>
+			<menu_item_call label="Webinhaltsbrowser" name="Web Content Browser"/>
 			<menu_item_call label="SelectMgr ausgeben" name="Dump SelectMgr"/>
 			<menu_item_call label="Inventarinfo ausgeben" name="Dump Inventory"/>
 			<menu_item_call label="Timer ausgeben" name="Dump Timers"/>
diff --git a/indra/newview/skins/default/xui/de/notifications.xml b/indra/newview/skins/default/xui/de/notifications.xml
index 06cc02cd84..bf525dd7c3 100644
--- a/indra/newview/skins/default/xui/de/notifications.xml
+++ b/indra/newview/skins/default/xui/de/notifications.xml
@@ -109,6 +109,10 @@ Wählen Sie ein einzelnes Objekt aus und versuchen Sie es erneut.
 		Leute, die nicht auf Ihrer Freundesliste stehen, werden nicht wissen, dass Sie deren Anrufe oder Sofortnachrichten ignoriert haben.
 		<usetemplate name="okbutton" yestext="Ja"/>
 	</notification>
+	<notification name="FavoritesOnLogin">
+		Hinweis: Bei Aktivierung dieser Option sehen alle Personen, die diesen Computer benutzen, Ihre Lieblingsorte.
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
 	<notification name="GrantModifyRights">
 		Wenn Sie einem anderen Einwohner Änderungsrechte gewähren, dann kann dieser JEDES Objekt, das Sie inworld besitzen, ändern, löschen oder an sich nehmen. Seien Sie daher beim Gewähren dieser Rechte sehr vorsichtig!
 Möchten Sie [NAME] Änderungsrechte gewähren?
@@ -957,7 +961,7 @@ Sie sind nicht berechtigt, Land für die aktive Gruppe zu kaufen.
 			<input name="message">
 				[DESC] (neu)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Abbrechen"/>
 		</form>
 	</notification>
@@ -967,7 +971,7 @@ Sie sind nicht berechtigt, Land für die aktive Gruppe zu kaufen.
 			<input name="message">
 				[DESC] (neu)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Abbrechen"/>
 		</form>
 	</notification>
@@ -977,7 +981,7 @@ Sie sind nicht berechtigt, Land für die aktive Gruppe zu kaufen.
 			<input name="new_name">
 				[NAME]
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Abbrechen"/>
 		</form>
 	</notification>
@@ -1355,9 +1359,39 @@ In Ihren Anwendungsordner herunterladen?
 Laden Sie den neuesten Viewer von http://secondlife.com/download herunter und installieren Sie ihn.
 		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
-	<notification name="DownloadBackground">
-		Eine aktualisierte Version von [APP_NAME] wurde heruntergeladen.
-Sie wird beim nächsten Neustart von [APP_NAME] verwendet.
+	<notification name="FailedRequiredUpdateInstall">
+		Ein erforderliches Update konnte nicht installiert werden. 
+Sie können sich erst anmelden, wenn [APP_NAME] aktualisiert wurde.
+
+Laden Sie den neuesten Viewer von http://secondlife.com/download herunter und installieren Sie ihn.
+		<usetemplate name="okbutton" yestext="Beenden"/>
+	</notification>
+	<notification name="UpdaterServiceNotRunning">
+		Für Ihre SecondLife-Installation ist ein Update erforderlich.
+
+Sie können dieses Update von http://www.secondlife.com/downloads herunterladen oder jetzt installieren.
+		<usetemplate name="okcancelbuttons" notext="Second Life beenden" yestext="Jetzt herunterladen und installieren"/>
+	</notification>
+	<notification name="DownloadBackgroundTip">
+		Für Ihre [APP_NAME]-Installation wurde ein Update heruntergeladen.
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Informationen zu diesem Update]
+		<usetemplate name="okcancelbuttons" notext="Später..." yestext="Jetzt installieren und [APP_NAME] neu starten"/>
+	</notification>
+	<notification name="DownloadBackgroundDialog">
+		Für Ihre [APP_NAME]-Installation wurde ein Update heruntergeladen.
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Informationen zu diesem Update]
+		<usetemplate name="okcancelbuttons" notext="Später..." yestext="Jetzt installieren und [APP_NAME] neu starten"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedVerboseDialog">
+		Ein erforderliches Softwareupdate wurde heruntergeladen.
+Version [VERSION]
+
+Zur Installation des Updates muss [APP_NAME] neu gestartet werden.
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedDialog">
+		Zur Installation des Updates muss [APP_NAME] neu gestartet werden.
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="DeedObjectToGroup">
 		Bei Übertragung dieses Objekts erhält die Gruppe:
@@ -2225,14 +2259,6 @@ Wählen Sie eine kleinere Landfläche.
 	<notification name="NoContentToSearch">
 		Bitte wählen Sie mindestens eine Inhaltsart für die Suche aus (Generell, Moderat oder Adult).
 	</notification>
-	<notification name="GroupVote">
-		[NAME] hat eine Abstimmung vorgeschlagen über:
-[MESSAGE]
-		<form name="form">
-			<button name="VoteNow" text="Abstimmen"/>
-			<button name="Later" text="Später"/>
-		</form>
-	</notification>
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
@@ -2796,9 +2822,7 @@ Avatar &apos;[NAME]&apos; hat Modus „Aussehen bearbeiten&quot; verlassen.
 	<notification name="NoConnect">
 		Es gibt Probleme mit der Verbindung mit [PROTOCOL] [HOSTID].
 Bitte überprüfen Sie Ihre Netzwerk- und Firewalleinstellungen.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="NoVoiceConnect">
 		Verbindung mit Voice-Server ist leider nicht möglich:
@@ -2807,9 +2831,7 @@ Bitte überprüfen Sie Ihre Netzwerk- und Firewalleinstellungen.
 
 Voice-Kommunikation ist leider nicht verfügbar.
 Bitte überprüfen Sie Ihr Netzwerk- und Firewall-Setup.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="AvatarRezLeftNotification">
 		(Seit [EXISTENCE] Sekunden inworld )
@@ -2844,6 +2866,9 @@ Alle stummschalten?
 	<notification label="Welt erkunden" name="HintDestinationGuide">
 		Im Reiseführer finden Sie Tausende von interessanten Orten. Wählen Sie einfach einen Ort aus und klicken Sie auf „Teleportieren“.
 	</notification>
+	<notification label="Aussehen ändern" name="HintAvatarPicker">
+		Möchten Sie einen neuen Look ausprobieren? Klicken Sie auf die Schaltfläche unten, um mehr Avatare zu sehen.
+	</notification>
 	<notification label="Seitenleiste" name="HintSidePanel">
 		In der Seitenleiste können Sie schnell auf Ihr Inventar, Ihre Outfits, Ihre Profile u. ä. zugreifen.
 	</notification>
@@ -2853,6 +2878,12 @@ Alle stummschalten?
 	<notification label="Anzeigename" name="HintDisplayName">
 		Hier können Sie Ihren anpassbaren Anzeigenamen festlegen. Der Anzeigename unterscheidet sich von Ihrem eindeutigen Benutzernamen, der nicht geändert werden kann. In den Einstellungen können Sie festlegen, welcher Name von anderen Einwohnern angezeigt wird.
 	</notification>
+	<notification label="Bewegen" name="HintMoveArrows">
+		Verwenden Sie zum Gehen die Pfeiltasten auf Ihrer Tastatur. Drücken Sie die Nach-oben-Taste zweimal, um zu rennen.
+	</notification>
+	<notification label="Ansicht" name="HintView">
+		Um die Kameraansicht zu ändern, verwenden Sie die Schwenk- und Kreissteuerungen. Um die Ansicht zurückzusetzen, drücken Sie die Esc-Taste oder laufen Sie einfach.
+	</notification>
 	<notification label="Inventar" name="HintInventory">
 		In Ihrem Inventar befinden sich verschiedene Objekte. Die neuesten Objekte finden Sie in der Registerkarte „Aktuell“.
 	</notification>
@@ -2866,6 +2897,15 @@ Alle stummschalten?
 			<button name="open" text="Popup-Fenster öffnen"/>
 		</form>
 	</notification>
+	<notification name="AuthRequest">
+		Für die Site „&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;“ in der Domäne „[REALM]“ ist ein Benutzername und Kennwort erforderlich.
+		<form name="form">
+			<input name="username" text="Benutzername"/>
+			<input name="password" text="Kennwort"/>
+			<button name="ok" text="Senden"/>
+			<button name="cancel" text="Abbrechen"/>
+		</form>
+	</notification>
 	<global name="UnsupportedCPU">
 		- Ihre CPU-Geschwindigkeit entspricht nicht den Mindestanforderungen.
 	</global>
diff --git a/indra/newview/skins/default/xui/de/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/de/panel_avatar_list_item.xml
index 2db8cf7c09..dcfcffa6e2 100644
--- a/indra/newview/skins/default/xui/de/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/de/panel_avatar_list_item.xml
@@ -21,7 +21,7 @@
 	<string name="FormatYears">
 		[COUNT]J
 	</string>
-	<text name="avatar_name" value="Unbekannt"/>
+	<text name="avatar_name" value="(laden)"/>
 	<text name="last_interaction" value="0s"/>
 	<icon name="permission_edit_theirs_icon" tool_tip="Sie können die Objekte dieses Freunds bearbeiten"/>
 	<icon name="permission_edit_mine_icon" tool_tip="Dieser Freund kann Ihre Objekte bearbeiten, löschen und an sich nehmen"/>
diff --git a/indra/newview/skins/default/xui/de/panel_edit_alpha.xml b/indra/newview/skins/default/xui/de/panel_edit_alpha.xml
index 4b48950341..4c6facf5e3 100644
--- a/indra/newview/skins/default/xui/de/panel_edit_alpha.xml
+++ b/indra/newview/skins/default/xui/de/panel_edit_alpha.xml
@@ -1,10 +1,12 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_alpha_panel">
-	<panel name="avatar_alpha_color_panel">
-		<texture_picker label="Alpha: Unten" name="Lower Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
-		<texture_picker label="Alpha: Oben" name="Upper Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
-		<texture_picker label="Kopf: Alpha" name="Head Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
-		<texture_picker label="Alpha: Augen" name="Eye Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
-		<texture_picker label="Alpha: Haare" name="Hair Alpha" tool_tip="Zum Auswählen eines Bildes hier klicken"/>
-	</panel>
+	<scroll_container name="avatar_alpha_color_panel_scroll">
+		<panel name="avatar_alpha_color_panel">
+			<texture_picker label="Alpha: Unten" name="Lower Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/>
+			<texture_picker label="Alpha: Oben" name="Upper Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/>
+			<texture_picker label="Alpha: Kopf" name="Head Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/>
+			<texture_picker label="Alpha: Augen" name="Eye Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/>
+			<texture_picker label="Alpha: Haare" name="Hair Alpha" tool_tip="Klicken, um ein Bild auszuwählen"/>
+		</panel>
+	</scroll_container>
 </panel>
diff --git a/indra/newview/skins/default/xui/de/panel_login.xml b/indra/newview/skins/default/xui/de/panel_login.xml
index 0fc4fa7117..1bee6b1ead 100644
--- a/indra/newview/skins/default/xui/de/panel_login.xml
+++ b/indra/newview/skins/default/xui/de/panel_login.xml
@@ -11,7 +11,7 @@
 			<text name="username_text">
 				Benutzername:
 			</text>
-			<line_editor label="berndschmidt12 oder Liebe Sonne" name="username_edit" tool_tip="Bei der Registrierung gewählter Benutzername wie „berndschmidt12“ oder „Liebe Sonne“"/>
+			<combo_box name="username_combo" tool_tip="Bei der Registrierung gewählter Benutzername wie „berndschmidt12“ oder „Liebe Sonne“"/>
 			<text name="password_text">
 				Kennwort:
 			</text>
diff --git a/indra/newview/skins/default/xui/de/panel_my_profile.xml b/indra/newview/skins/default/xui/de/panel_my_profile.xml
index aea87cc2c4..89a4dfdaba 100644
--- a/indra/newview/skins/default/xui/de/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/de/panel_my_profile.xml
@@ -16,34 +16,27 @@
 	<string name="RegisterDateFormat">
 		[REG_DATE] ([AGE])
 	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
 	<layout_stack name="layout">
 		<layout_panel name="profile_stack">
 			<scroll_container name="profile_scroll">
 				<panel name="scroll_content_panel">
 					<panel name="second_life_image_panel">
-						<icon label="" name="2nd_life_edit_icon" tool_tip="Klicken Sie unten auf die Schaltfläche Profil bearbeiten, um das Bild zu ändern."/>
-						<text name="title_sl_descr_text" value="[SECOND_LIFE]:"/>
-					</panel>
-					<panel name="first_life_image_panel">
-						<icon label="" name="real_world_edit_icon" tool_tip="Klicken Sie unten auf die Schaltfläche Profil bearbeiten, um das Bild zu ändern."/>
-						<text name="title_rw_descr_text" value="Echtes Leben:"/>
-					</panel>
-					<text name="title_member_text" value="Einwohner seit:"/>
-					<text name="title_acc_status_text" value="Kontostatus:"/>
-					<text_editor name="acc_status_text">
-						Einwohner. Keine Zahlungsinfo archiviert.
-              Linden.
-					</text_editor>
-					<text name="title_partner_text" value="Partner:"/>
-					<panel name="partner_data_panel">
-						<name_box initial_value="(wird in Datenbank gesucht)" name="partner_text"/>
+						<text name="display_name_descr_text">
+							Benutzername
+						</text>
+						<text name="name_descr_text">
+							Anzeigename
+						</text>
+						<button label="Profil" name="see_profile_btn" tool_tip="Profil zu diesem Avatar anzeigen"/>
 					</panel>
-					<text name="title_groups_text" value="Gruppen:"/>
 				</panel>
 			</scroll_container>
 		</layout_panel>
 	</layout_stack>
-	<panel name="profile_me_buttons_panel">
-		<button label="Profil bearbeiten" name="edit_profile_btn" tool_tip="Ihre persönlichen Informationen bearbeiten"/>
-	</panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/de/panel_notify_textbox.xml b/indra/newview/skins/default/xui/de/panel_notify_textbox.xml
index 7187be570c..da672a0309 100644
--- a/indra/newview/skins/default/xui/de/panel_notify_textbox.xml
+++ b/indra/newview/skins/default/xui/de/panel_notify_textbox.xml
@@ -3,8 +3,9 @@
 	<string name="message_max_lines_count" value="7"/>
 	<panel label="info_panel" name="info_panel">
 		<text_editor name="message" value="message"/>
-		parse_urls=&quot;false&quot;
+	</panel>
+	<panel label="control_panel" name="control_panel">
 		<button label="Senden" name="btn_submit"/>
+		<button label="Ignorieren" name="ignore_btn"/>
 	</panel>
-	<panel label="control_panel" name="control_panel"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/de/panel_preferences_colors.xml b/indra/newview/skins/default/xui/de/panel_preferences_colors.xml
index d9e5c7f2b5..22681ffdf2 100644
--- a/indra/newview/skins/default/xui/de/panel_preferences_colors.xml
+++ b/indra/newview/skins/default/xui/de/panel_preferences_colors.xml
@@ -29,10 +29,10 @@
 		URLs
 	</text>
 	<text name="bubble_chat">
-		Hintergrund für Blasen-Chat:
+		Hintergrundfarbe für Avatarnamen (wirkt sich auch auf Blasen-Chat aus):
 	</text>
-	<color_swatch name="background" tool_tip="Farbe für Blasen-Chat auswählen"/>
-	<slider label="Deckkraft:" name="bubble_chat_opacity"/>
+	<color_swatch name="background" tool_tip="Farbe für Avatarnamen auswählen"/>
+	<slider label="Deckkraft:" name="bubble_chat_opacity" tool_tip="Deckkraft für Avatarnamen auswählen"/>
 	<text name="floater_opacity">
 		Floater-Deckkraft:
 	</text>
diff --git a/indra/newview/skins/default/xui/de/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/de/panel_preferences_privacy.xml
index d78064833b..b56f150394 100644
--- a/indra/newview/skins/default/xui/de/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/de/panel_preferences_privacy.xml
@@ -7,9 +7,11 @@
 	<text name="cache_size_label_l">
 		(Standorte, Bilder, Web, Suchverlauf)
 	</text>
+	<check_box label="In Suchergebnissen anzeigen" name="online_searchresults"/>
 	<check_box label="Nur Freunde und Gruppen wissen, dass ich online bin" name="online_visibility"/>
 	<check_box label="Nur Freunde und Gruppen können mich anrufen oder mir eine IM schicken" name="voice_call_friends_only_check"/>
 	<check_box label="Mikrofon ausschalten, wenn Anrufe beendet werden" name="auto_disengage_mic_check"/>
+	<check_box label="Meine Lieblingslandmarken bei Anmeldung anzeigen (im Dropdown-Menü „Hier anfangen“)" name="favorites_on_login_check"/>
 	<text name="Logs:">
 		Chatprotokolle:
 	</text>
diff --git a/indra/newview/skins/default/xui/de/panel_preferences_setup.xml b/indra/newview/skins/default/xui/de/panel_preferences_setup.xml
index c4d095dde5..490cead17d 100644
--- a/indra/newview/skins/default/xui/de/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/de/panel_preferences_setup.xml
@@ -39,5 +39,11 @@
 	</text>
 	<line_editor name="web_proxy_editor" tool_tip="Name oder IP Adresse des Proxyservers, den Sie benutzen möchten"/>
 	<spinner label="Portnummer:" name="web_proxy_port"/>
-	<check_box initial_value="true" label="Updates für [APP_NAME] automatisch herunterladen und installieren" name="updater_service_active"/>
+	<text name="Software updates:">
+		Softwareupdates:
+	</text>
+	<combo_box name="updater_service_combobox">
+		<combo_box.item label="Automatisch installieren" name="Install_automatically"/>
+		<combo_box.item label="Updates manuell herunterladen und installieren" name="Install_manual"/>
+	</combo_box>
 </panel>
diff --git a/indra/newview/skins/default/xui/de/panel_status_bar.xml b/indra/newview/skins/default/xui/de/panel_status_bar.xml
index 005290c1ff..04ed58f944 100644
--- a/indra/newview/skins/default/xui/de/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/de/panel_status_bar.xml
@@ -22,7 +22,7 @@
 		[AMT] L$
 	</panel.string>
 	<panel name="balance_bg">
-		<text name="balance" tool_tip="Mein Kontostand" value="20 L$"/>
+		<text name="balance" tool_tip="Klicken, um L$-Guthaben zu aktualisieren" value="20 L$"/>
 		<button label="L$ kaufen" name="buyL" tool_tip="Hier klicken, um mehr L$ zu kaufen"/>
 	</panel>
 	<text name="TimeText" tool_tip="Aktuelle Zeit (Pazifik)">
diff --git a/indra/newview/skins/default/xui/es/menu_login.xml b/indra/newview/skins/default/xui/es/menu_login.xml
index 5386f82ee5..c27d624732 100644
--- a/indra/newview/skins/default/xui/es/menu_login.xml
+++ b/indra/newview/skins/default/xui/es/menu_login.xml
@@ -16,7 +16,8 @@
 		<menu_item_call label="Definir el tamaño de la ventana..." name="Set Window Size..."/>
 		<menu_item_call label="Mostrar los &apos;TOS&apos;" name="TOS"/>
 		<menu_item_call label="Mostrar mensaje crítico" name="Critical"/>
-		<menu_item_call label="Web Browser Test" name="Web Browser Test"/>
+		<menu_item_call label="Prueba de navegadores de medios" name="Web Browser Test"/>
+		<menu_item_call label="Prueba de ventanas de contenidos web" name="Web Content Floater Test"/>
 		<menu_item_check label="Mostrar el selector de Grid" name="Show Grid Picker"/>
 		<menu_item_call label="Mostrar la consola de notificaciones" name="Show Notifications Console"/>
 	</menu>
diff --git a/indra/newview/skins/default/xui/es/menu_mini_map.xml b/indra/newview/skins/default/xui/es/menu_mini_map.xml
index 41dc817551..07d1b08572 100644
--- a/indra/newview/skins/default/xui/es/menu_mini_map.xml
+++ b/indra/newview/skins/default/xui/es/menu_mini_map.xml
@@ -3,6 +3,7 @@
 	<menu_item_call label="Zoom cerca" name="Zoom Close"/>
 	<menu_item_call label="Zoom medio" name="Zoom Medium"/>
 	<menu_item_call label="Zoom lejos" name="Zoom Far"/>
+	<menu_item_call label="Zoom por defecto" name="Zoom Default"/>
 	<menu_item_check label="Girar el mapa" name="Rotate Map"/>
 	<menu_item_check label="Centrar automáticamente" name="Auto Center"/>
 	<menu_item_call label="Parar la búsqueda" name="Stop Tracking"/>
diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml
index 3dd940c331..2fe7db1041 100644
--- a/indra/newview/skins/default/xui/es/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/es/menu_viewer.xml
@@ -121,13 +121,15 @@
 			<menu_item_call label="Animación ([COST] L$)..." name="Upload Animation"/>
 			<menu_item_call label="Masivo ([COST] L$ por archivo)..." name="Bulk Upload"/>
 		</menu>
+		<menu_item_call label="Deshacer" name="Undo"/>
+		<menu_item_call label="Rehacer" name="Redo"/>
 	</menu>
 	<menu label="Ayuda" name="Help">
 		<menu_item_call label="Ayuda de [SECOND_LIFE]" name="Second Life Help"/>
+		<menu_item_check label="Permitir consejos" name="Enable Hints"/>
 		<menu_item_call label="Denunciar una infracción" name="Report Abuse"/>
 		<menu_item_call label="Informar de un fallo" name="Report Bug"/>
 		<menu_item_call label="Acerca de [APP_NAME]" name="About Second Life"/>
-		<menu_item_check label="Permitir consejos" name="Enable Hints"/>
 	</menu>
 	<menu label="Avanzado" name="Advanced">
 		<menu_item_call label="Recargar las texturas" name="Rebake Texture"/>
@@ -268,7 +270,8 @@
 			<menu_item_call label="Dump Region Object Cache" name="Dump Region Object Cache"/>
 		</menu>
 		<menu label="UI" name="UI">
-			<menu_item_call label="Web Browser Test" name="Web Browser Test"/>
+			<menu_item_call label="Prueba de navegadores de medios" name="Web Browser Test"/>
+			<menu_item_call label="Navegador de contenido web" name="Web Content Browser"/>
 			<menu_item_call label="Print Selected Object Info" name="Print Selected Object Info"/>
 			<menu_item_call label="Memory Stats" name="Memory Stats"/>
 			<menu_item_check label="Consola de depuración de región" name="Region Debug Console"/>
diff --git a/indra/newview/skins/default/xui/es/notifications.xml b/indra/newview/skins/default/xui/es/notifications.xml
index 2dd7a6b0f5..051314bdfa 100644
--- a/indra/newview/skins/default/xui/es/notifications.xml
+++ b/indra/newview/skins/default/xui/es/notifications.xml
@@ -108,6 +108,10 @@ Asegúrate de que tu conexión a Internet está funcionando adecuadamente.
 		Quienes no sean tus amigos no sabrán que has elegido ignorar sus llamadas y mensajes instantáneos.
 		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
+	<notification name="FavoritesOnLogin">
+		Nota: Al activar esta opción, cualquiera que utilice este ordenador podrá ver tu lista de lugares favoritos.
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
 	<notification name="GrantModifyRights">
 		Al conceder permisos de modificación a otro Residente, le estás permitiendo cambiar, borrar o tomar CUALQUIER objeto que tengas en el mundo. Sé MUY cuidadoso al conceder este permiso.
 ¿Quieres conceder permisos de modificación a [NAME]?
@@ -946,7 +950,7 @@ no tienes el permiso de comprar terreno para el grupo que tienes activado actual
 			<input name="message">
 				[DESC] (nuevo)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Cancelar"/>
 		</form>
 	</notification>
@@ -956,7 +960,7 @@ no tienes el permiso de comprar terreno para el grupo que tienes activado actual
 			<input name="message">
 				[DESC] (nuevo)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Cancelar"/>
 		</form>
 	</notification>
@@ -966,7 +970,7 @@ no tienes el permiso de comprar terreno para el grupo que tienes activado actual
 			<input name="new_name">
 				[NAME]
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Cancelar"/>
 		</form>
 	</notification>
@@ -1347,9 +1351,41 @@ Descarga e instala el último visor a través de
 http://secondlife.com/download.
 		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
-	<notification name="DownloadBackground">
-		Se ha descargado una versión actualizada de [APP_NAME].
-Se aplicará la próxima vez que reinicies [APP_NAME]
+	<notification name="FailedRequiredUpdateInstall">
+		No hemos podido instalar una actualización necesaria. 
+No podrás iniciar sesión hasta que [APP_NAME] se haya actualizado.
+
+Descarga e instala el último visor a través de
+http://secondlife.com/download.
+		<usetemplate name="okbutton" yestext="Salir"/>
+	</notification>
+	<notification name="UpdaterServiceNotRunning">
+		Hay una actualización necesaria para la instalación de Second Life.
+
+Puedes descargar esta actualización de http://www.secondlife.com/downloads
+o instalarla ahora.
+		<usetemplate name="okcancelbuttons" notext="Salir de Second Life" yestext="Descargar e instalar ahora"/>
+	</notification>
+	<notification name="DownloadBackgroundTip">
+		Hemos descargado una actualización para la instalación de [APP_NAME].
+Versión [VERSION] [[RELEASE_NOTES_FULL_URL]; información acerca de esta actualización]
+		<usetemplate name="okcancelbuttons" notext="Más tarde..." yestext="Instalar ahora y reiniciar [NOMBRE_APL]"/>
+	</notification>
+	<notification name="DownloadBackgroundDialog">
+		Hemos descargado una actualización para la instalación de [APP_NAME].
+Versión [VERSION] [[RELEASE_NOTES_FULL_URL]; información acerca de esta actualización]
+		<usetemplate name="okcancelbuttons" notext="Más tarde..." yestext="Instalar ahora y reiniciar [APP_NAME]"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedVerboseDialog">
+		Hemos descargado una actualización de software necesaria.
+Versión [VERSION]
+
+Debemos reiniciar [APP_NAME] para instalar la actualización.
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedDialog">
+		Debemos reiniciar [APP_NAME] para instalar la actualización.
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="DeedObjectToGroup">
 		Transferir este objeto al grupo hará que:
@@ -2217,14 +2253,6 @@ Inténtalo seleccionando un trozo más pequeño de terreno.
 	<notification name="NoContentToSearch">
 		Por favor, elige al menos un tipo de contenido a buscar (&apos;PG&apos;, &apos;Mature&apos;, o &apos;Adult&apos;).
 	</notification>
-	<notification name="GroupVote">
-		[NAME] ha propuesto votar:
-[MESSAGE]
-		<form name="form">
-			<button name="VoteNow" text="Votar ahora"/>
-			<button name="Later" text="Más tarde"/>
-		</form>
-	</notification>
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
@@ -2783,9 +2811,7 @@ El avatar &apos;[NAME]&apos; desactivó el modo de apariencia.
 	<notification name="NoConnect">
 		Tenemos problemas de conexión con [PROTOCOL] [HOSTID].
 Comprueba la configuración de la red y del servidor de seguridad.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="NoVoiceConnect">
 		Tenemos problemas de conexión con tu servidor de voz:
@@ -2794,9 +2820,7 @@ Comprueba la configuración de la red y del servidor de seguridad.
 
 No podrás establecer comunicaciones de voz.
 Comprueba la configuración de la red y del servidor de seguridad.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="AvatarRezLeftNotification">
 		( [EXISTENCE] segundos vivo)
@@ -2830,6 +2854,9 @@ Si lo haces, todos los residentes que se unan posteriormente a la llamada tambi
 	<notification label="Explora el mundo" name="HintDestinationGuide">
 		La Guía de destinos contiene miles de nuevos lugares por descubrir. Selecciona una ubicación y elige Teleportarme para iniciar la exploración.
 	</notification>
+	<notification label="Cambiar de apariencia" name="HintAvatarPicker">
+		¿Te gustaría cambiar de apariencia? Haz clic en el botón que aparece a continuación para ver más avatares.
+	</notification>
 	<notification label="Panel lateral" name="HintSidePanel">
 		Accede de manera rápida a tu inventario, así como a tu ropa, los perfiles y el resto de la información disponible en el panel lateral.
 	</notification>
@@ -2839,6 +2866,12 @@ Si lo haces, todos los residentes que se unan posteriormente a la llamada tambi
 	<notification label="Nombre mostrado" name="HintDisplayName">
 		Configura y personaliza aquí tu nombre mostrado. Esto se añadirá a tu nombre de usuario personal, que no puedes modificar. Puedes cambiar la manera en que ves los nombres de otras personas en tus preferencias.
 	</notification>
+	<notification label="Mover" name="HintMoveArrows">
+		Para caminar, utiliza las flechas de dirección del teclado. Para correr, pulsa dos veces la flecha hacia arriba.
+	</notification>
+	<notification label="Visión" name="HintView">
+		Para cambiar la vista de la cámara, utiliza los controles Orbital y Panorámica. Para restablecer tu vista, pulsa Esc o camina.
+	</notification>
 	<notification label="Inventario" name="HintInventory">
 		Accede a tu inventario para buscar ítems. Los ítems más recientes se pueden encontrar fácilmente en la pestaña Recientes.
 	</notification>
@@ -2852,6 +2885,15 @@ Si lo haces, todos los residentes que se unan posteriormente a la llamada tambi
 			<button name="open" text="Abrir ventana emergente"/>
 		</form>
 	</notification>
+	<notification name="AuthRequest">
+		El sitio en &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; de la plataforma &apos;[REALM]&apos; requiere un nombre de usuario y una contraseña.
+		<form name="form">
+			<input name="username" text="Nombre de usuario"/>
+			<input name="password" text="Contraseña"/>
+			<button name="ok" text="Enviar"/>
+			<button name="cancel" text="Cancelar"/>
+		</form>
+	</notification>
 	<global name="UnsupportedCPU">
 		- La velocidad de tu CPU no cumple los requerimientos mínimos.
 	</global>
diff --git a/indra/newview/skins/default/xui/es/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/es/panel_avatar_list_item.xml
index 09221c5599..5220df5d21 100644
--- a/indra/newview/skins/default/xui/es/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/es/panel_avatar_list_item.xml
@@ -21,7 +21,7 @@
 	<string name="FormatYears">
 		[COUNT] año/s
 	</string>
-	<text name="avatar_name" value="Desconocido"/>
+	<text name="avatar_name" value="(cargando...)"/>
 	<icon name="permission_edit_theirs_icon" tool_tip="Puedes editar los objetos de este amigo"/>
 	<icon name="permission_edit_mine_icon" tool_tip="Este amigo puede editar, eliminar o manipular tus objetos"/>
 	<icon name="permission_map_icon" tool_tip="Este amigo puede encontrarte en el mapa"/>
diff --git a/indra/newview/skins/default/xui/es/panel_edit_alpha.xml b/indra/newview/skins/default/xui/es/panel_edit_alpha.xml
index 3f238da9d0..829c206ae1 100644
--- a/indra/newview/skins/default/xui/es/panel_edit_alpha.xml
+++ b/indra/newview/skins/default/xui/es/panel_edit_alpha.xml
@@ -1,10 +1,12 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_alpha_panel">
-	<panel name="avatar_alpha_color_panel">
-		<texture_picker label="Alfa inferior" name="Lower Alpha" tool_tip="Pulsa para elegir una imagen"/>
-		<texture_picker label="Alfa superior" name="Upper Alpha" tool_tip="Pulsa para elegir una imagen"/>
-		<texture_picker label="Alfa de la cabeza" name="Head Alpha" tool_tip="Pulsa para elegir una imagen"/>
-		<texture_picker label="Alfa de los ojos" name="Eye Alpha" tool_tip="Pulsa para elegir una imagen"/>
-		<texture_picker label="Alfa del pelo" name="Hair Alpha" tool_tip="Pulsa para elegir una imagen"/>
-	</panel>
+	<scroll_container name="avatar_alpha_color_panel_scroll">
+		<panel name="avatar_alpha_color_panel">
+			<texture_picker label="Alfa inferior" name="Lower Alpha" tool_tip="Pulsa para elegir una imagen"/>
+			<texture_picker label="Alfa superior" name="Upper Alpha" tool_tip="Pulsa para elegir una imagen"/>
+			<texture_picker label="Alfa de la cabeza" name="Head Alpha" tool_tip="Pulsa para elegir una imagen"/>
+			<texture_picker label="Alfa de los ojos" name="Eye Alpha" tool_tip="Pulsa para elegir una imagen"/>
+			<texture_picker label="Alfa del pelo" name="Hair Alpha" tool_tip="Pulsa para elegir una imagen"/>
+		</panel>
+	</scroll_container>
 </panel>
diff --git a/indra/newview/skins/default/xui/es/panel_login.xml b/indra/newview/skins/default/xui/es/panel_login.xml
index 49d4881737..ada964f33e 100644
--- a/indra/newview/skins/default/xui/es/panel_login.xml
+++ b/indra/newview/skins/default/xui/es/panel_login.xml
@@ -11,7 +11,7 @@
 			<text name="username_text">
 				Nombre de usuario:
 			</text>
-			<line_editor label="bobsmith12 o Steller Sunshine" name="username_edit" tool_tip="El nombre de usuario que elegiste al registrarte, como bobsmith12 o Steller Sunshine"/>
+			<combo_box name="username_combo" tool_tip="El nombre de usuario que elegiste al registrarte, como bobsmith12 o Steller Sunshine"/>
 			<text name="password_text">
 				Contraseña:
 			</text>
diff --git a/indra/newview/skins/default/xui/es/panel_my_profile.xml b/indra/newview/skins/default/xui/es/panel_my_profile.xml
index 14c94acf5b..29e5e6f652 100644
--- a/indra/newview/skins/default/xui/es/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/es/panel_my_profile.xml
@@ -5,30 +5,27 @@
 	<string name="RegisterDateFormat">
 		[REG_DATE] ([AGE])
 	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
 	<layout_stack name="layout">
 		<layout_panel name="profile_stack">
 			<scroll_container name="profile_scroll">
 				<panel name="scroll_content_panel">
 					<panel name="second_life_image_panel">
-						<icon label="" name="2nd_life_edit_icon" tool_tip="Pulsa el botón Editar el perfil para cambiar la imagen"/>
-						<text name="title_sl_descr_text" value="[SECOND_LIFE]:"/>
-					</panel>
-					<panel name="first_life_image_panel">
-						<icon label="" name="real_world_edit_icon" tool_tip="Pulsa el botón Editar el perfil para cambiar la imagen"/>
-						<text name="title_rw_descr_text" value="Mundo real:"/>
-					</panel>
-					<text name="title_member_text" value="Residente desde:"/>
-					<text name="title_acc_status_text" value="Estado de la cuenta:"/>
-					<text name="title_partner_text" value="Compañero/a:"/>
-					<panel name="partner_data_panel">
-						<name_box initial_value="(obteniendo)" name="partner_text"/>
+						<text name="display_name_descr_text">
+							Nombre de usuario
+						</text>
+						<text name="name_descr_text">
+							Nombre mostrado
+						</text>
+						<button label="Perfil" name="see_profile_btn" tool_tip="Ver el perfil de este avatar"/>
 					</panel>
-					<text name="title_groups_text" value="Grupos:"/>
 				</panel>
 			</scroll_container>
 		</layout_panel>
 	</layout_stack>
-	<panel name="profile_me_buttons_panel">
-		<button label="Editar el perfil" name="edit_profile_btn" tool_tip="Modificar tu información personal"/>
-	</panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/es/panel_notify_textbox.xml b/indra/newview/skins/default/xui/es/panel_notify_textbox.xml
index 10aaa288d7..dc7c873303 100644
--- a/indra/newview/skins/default/xui/es/panel_notify_textbox.xml
+++ b/indra/newview/skins/default/xui/es/panel_notify_textbox.xml
@@ -3,8 +3,9 @@
 	<string name="message_max_lines_count" value="7"/>
 	<panel label="info_panel" name="info_panel">
 		<text_editor name="message" value="message"/>
-		parse_urls=&quot;false&quot;
+	</panel>
+	<panel label="control_panel" name="control_panel">
 		<button label="Enviar" name="btn_submit"/>
+		<button label="Ignorar" name="ignore_btn"/>
 	</panel>
-	<panel label="control_panel" name="control_panel"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_colors.xml b/indra/newview/skins/default/xui/es/panel_preferences_colors.xml
index 4fa5c4ce63..edd417d564 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_colors.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_colors.xml
@@ -29,10 +29,10 @@
 		URL
 	</text>
 	<text name="bubble_chat">
-		Fondo de los bocadillos del chat:
+		Color de fondo de la etiqueta del nombre (afectará también a los bocadillos del chat):
 	</text>
-	<color_swatch name="background" tool_tip="Elegir el color de los bocadillos del chat"/>
-	<slider label="Opacidad:" name="bubble_chat_opacity"/>
+	<color_swatch name="background" tool_tip="Seleccionar el color de la etiqueta del nombre"/>
+	<slider label="Opacidad:" name="bubble_chat_opacity" tool_tip="Seleccionar opacidad de la etiqueta del nombre"/>
 	<text name="floater_opacity">
 		Opacidad de la ventana:
 	</text>
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/es/panel_preferences_privacy.xml
index abff72c346..5eaa345c98 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_privacy.xml
@@ -7,9 +7,11 @@
 	<text name="cache_size_label_l">
 		(Localizaciones, imágenes, web, historial de búsqueda)
 	</text>
+	<check_box label="Mostrarme en los resultados de la búsqueda" name="online_searchresults"/>
 	<check_box label="Sólo saben si estoy conectado mis amigos y grupos" name="online_visibility"/>
 	<check_box label="Sólo pueden llamarme o mandarme un MI mis amigos y grupos" name="voice_call_friends_only_check"/>
 	<check_box label="Desconectar el micrófono cuando finalicen las llamadas" name="auto_disengage_mic_check"/>
+	<check_box label="Mostrar mis Hitos favoritos en Inicio de sesión (mediante el menú desplegable &quot;Empezar en&quot;)" name="favorites_on_login_check"/>
 	<text name="Logs:">
 		Registros de chat:
 	</text>
diff --git a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml
index f968f48910..68484645b7 100644
--- a/indra/newview/skins/default/xui/es/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/es/panel_preferences_setup.xml
@@ -39,5 +39,11 @@
 	</text>
 	<line_editor name="web_proxy_editor" tool_tip="Nombre o dirección IP del proxy que quieres usar"/>
 	<spinner label="Nº del puerto:" name="web_proxy_port"/>
-	<check_box initial_value="verdadero" label="Descargar e instalar automáticamente actualizaciones de [APP_NAME]" name="updater_service_active"/>
+	<text name="Software updates:">
+		Actualizaciones de software:
+	</text>
+	<combo_box name="updater_service_combobox">
+		<combo_box.item label="Instalar automáticamente" name="Install_automatically"/>
+		<combo_box.item label="Descargar e instalar actualizaciones manualmente" name="Install_manual"/>
+	</combo_box>
 </panel>
diff --git a/indra/newview/skins/default/xui/es/panel_status_bar.xml b/indra/newview/skins/default/xui/es/panel_status_bar.xml
index 13ed1acf0b..ab76d3f994 100644
--- a/indra/newview/skins/default/xui/es/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/es/panel_status_bar.xml
@@ -22,7 +22,7 @@
 		[AMT] L$
 	</panel.string>
 	<panel name="balance_bg">
-		<text name="balance" tool_tip="Mi saldo" value="20 L$"/>
+		<text name="balance" tool_tip="Haz clic para actualizar tu saldo en L$" value="20 L$"/>
 		<button label="COMPRAR L$" name="buyL" tool_tip="Pulsa para comprar más L$"/>
 	</panel>
 	<text name="TimeText" tool_tip="Hora actual (Pacífico)">
diff --git a/indra/newview/skins/default/xui/fr/menu_login.xml b/indra/newview/skins/default/xui/fr/menu_login.xml
index b712c008cd..400c77e51a 100644
--- a/indra/newview/skins/default/xui/fr/menu_login.xml
+++ b/indra/newview/skins/default/xui/fr/menu_login.xml
@@ -17,7 +17,8 @@
 		<menu_item_call label="Définir la taille de la fenêtre..." name="Set Window Size..."/>
 		<menu_item_call label="Afficher les conditions d&apos;utilisation" name="TOS"/>
 		<menu_item_call label="Afficher le message critique" name="Critical"/>
-		<menu_item_call label="Test du navigateur Web" name="Web Browser Test"/>
+		<menu_item_call label="Test du navigateur de médias" name="Web Browser Test"/>
+		<menu_item_call label="Test de la fenêtre flottante du contenu Web" name="Web Content Floater Test"/>
 		<menu_item_check label="Afficher le sélecteur de grille" name="Show Grid Picker"/>
 		<menu_item_call label="Afficher la console des notifications" name="Show Notifications Console"/>
 	</menu>
diff --git a/indra/newview/skins/default/xui/fr/menu_mini_map.xml b/indra/newview/skins/default/xui/fr/menu_mini_map.xml
index 7530f31d4e..b9d0a70383 100644
--- a/indra/newview/skins/default/xui/fr/menu_mini_map.xml
+++ b/indra/newview/skins/default/xui/fr/menu_mini_map.xml
@@ -3,6 +3,7 @@
 	<menu_item_call label="Zoom rapproché" name="Zoom Close"/>
 	<menu_item_call label="Zoom moyen" name="Zoom Medium"/>
 	<menu_item_call label="Zoom éloigné" name="Zoom Far"/>
+	<menu_item_call label="Zoom par défaut" name="Zoom Default"/>
 	<menu_item_check label="Faire pivoter la carte" name="Rotate Map"/>
 	<menu_item_check label="Centrage auto" name="Auto Center"/>
 	<menu_item_call label="Arrêter de suivre" name="Stop Tracking"/>
diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml
index fb4ab314af..65a00c2e6c 100644
--- a/indra/newview/skins/default/xui/fr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml
@@ -121,13 +121,15 @@
 			<menu_item_call label="Animation ([COST] L$)..." name="Upload Animation"/>
 			<menu_item_call label="Lot ([COST] L$ par fichier)..." name="Bulk Upload"/>
 		</menu>
+		<menu_item_call label="Annuler" name="Undo"/>
+		<menu_item_call label="Refaire" name="Redo"/>
 	</menu>
 	<menu label="Aide" name="Help">
 		<menu_item_call label="Aide de [SECOND_LIFE]" name="Second Life Help"/>
+		<menu_item_check label="Activer les astuces" name="Enable Hints"/>
 		<menu_item_call label="Signaler une infraction" name="Report Abuse"/>
 		<menu_item_call label="Signaler un bug" name="Report Bug"/>
 		<menu_item_call label="À propos de [APP_NAME]" name="About Second Life"/>
-		<menu_item_check label="Activer les astuces" name="Enable Hints"/>
 	</menu>
 	<menu label="Avancé" name="Advanced">
 		<menu_item_call label="Refixer les textures" name="Rebake Texture"/>
@@ -307,7 +309,8 @@
 			<menu_item_call label="Dump Region Object Cache" name="Dump Region Object Cache"/>
 		</menu>
 		<menu label="Interface" name="UI">
-			<menu_item_call label="Test du navigateur Web" name="Web Browser Test"/>
+			<menu_item_call label="Test du navigateur de médias" name="Web Browser Test"/>
+			<menu_item_call label="Navigateur du contenu Web" name="Web Content Browser"/>
 			<menu_item_call label="Dump SelectMgr" name="Dump SelectMgr"/>
 			<menu_item_call label="Dump inventaire" name="Dump Inventory"/>
 			<menu_item_call label="Dump Timers" name="Dump Timers"/>
diff --git a/indra/newview/skins/default/xui/fr/notifications.xml b/indra/newview/skins/default/xui/fr/notifications.xml
index ec362d7f22..140bbcc18b 100644
--- a/indra/newview/skins/default/xui/fr/notifications.xml
+++ b/indra/newview/skins/default/xui/fr/notifications.xml
@@ -109,6 +109,10 @@ Veuillez ne sélectionner qu&apos;un seul objet.
 		Les résidents qui ne sont pas vos amis ne sauront pas que vous avez choisi d&apos;ignorer leurs appels et leurs messages instantanés.
 		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
+	<notification name="FavoritesOnLogin">
+		Remarque : si vous activez cette option, toutes les personnes utilisant cet ordinateur pourront voir votre liste d&apos;endroits favoris.
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
 	<notification name="GrantModifyRights">
 		Lorsque vous accordez des droits de modification à un autre résident, vous lui permettez de changer, supprimer ou prendre n&apos;importe lequel de vos objets dans Second Life. Réfléchissez bien avant d&apos;accorder ces droits.
 Voulez-vous vraiment accorder des droits de modification à [NAME] ?
@@ -945,7 +949,7 @@ Proposer à [NAME] de devenir votre ami(e) ?
 			<input name="message">
 				[DESC] (nouv.)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Annuler"/>
 		</form>
 	</notification>
@@ -955,7 +959,7 @@ Proposer à [NAME] de devenir votre ami(e) ?
 			<input name="message">
 				[DESC] (nouv.)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Annuler"/>
 		</form>
 	</notification>
@@ -965,7 +969,7 @@ Proposer à [NAME] de devenir votre ami(e) ?
 			<input name="new_name">
 				[NAME]
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Annuler"/>
 		</form>
 	</notification>
@@ -1338,9 +1342,41 @@ Veuillez télécharger et installer la dernière version du client à la page We
 http://secondlife.com/download.
 		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
-	<notification name="DownloadBackground">
-		Une mise à jour de [APP_NAME] a été téléchargée.
-Elle sera appliquée au prochain redémarrage de [APP_NAME].
+	<notification name="FailedRequiredUpdateInstall">
+		Impossible d&apos;installer une mise à jour requise. 
+Vous ne pourrez pas vous connecter tant que [APP_NAME] ne sera pas mis à jour.
+
+Veuillez télécharger et installer la dernière version du client à la page Web
+http://secondlife.com/download.
+		<usetemplate name="okbutton" yestext="Quitter"/>
+	</notification>
+	<notification name="UpdaterServiceNotRunning">
+		Une mise à jour requise pour votre installation Second Life existe.
+
+Pour la télécharger, accédez à http://www.secondlife.com/downloads.
+Vous pouvez également l&apos;installer dès maintenant.
+		<usetemplate name="okcancelbuttons" notext="Quitter Second Life" yestext="Télécharger et installer maintenant"/>
+	</notification>
+	<notification name="DownloadBackgroundTip">
+		Nous avons téléchargé une mise à jour de votre installation [APP_NAME].
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Informations relatives à cette mise à jour]
+		<usetemplate name="okcancelbuttons" notext="Ultérieurement..." yestext="Installer maintenant et redémarrer [APP_NAME]"/>
+	</notification>
+	<notification name="DownloadBackgroundDialog">
+		Nous avons téléchargé une mise à jour de votre installation [APP_NAME].
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Informations relatives à cette mise à jour]
+		<usetemplate name="okcancelbuttons" notext="Ultérieurement..." yestext="Installer maintenant et redémarrer [APP_NAME]"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedVerboseDialog">
+		Nous avons téléchargé une mise à jour logicielle requise.
+Version [VERSION]
+
+[APP_NAME] doit être redémarré pour que la mise à jour soit installée.
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedDialog">
+		[APP_NAME] doit être redémarré pour que la mise à jour soit installée.
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="DeedObjectToGroup">
 		Si vous cédez cet objet, le groupe :
@@ -2209,14 +2245,6 @@ Veuillez sélectionner un terrain plus petit.
 	<notification name="NoContentToSearch">
 		Veuillez sélectionner au moins un type de contenu à rechercher (Général, Modéré ou Adulte)
 	</notification>
-	<notification name="GroupVote">
-		[NAME] a proposé un vote pour :
-[MESSAGE]
-		<form name="form">
-			<button name="VoteNow" text="Voter"/>
-			<button name="Later" text="Plus tard"/>
-		</form>
-	</notification>
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
@@ -2779,9 +2807,7 @@ L&apos;avatar [NAME] a quitté le mode Apparence.
 	<notification name="NoConnect">
 		Problèmes de connexion via [PROTOCOL] [HOSTID].
 Veuillez vérifier la configuration de votre réseau et de votre pare-feu.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="NoVoiceConnect">
 		Problèmes de connexion à votre serveur vocal :
@@ -2790,9 +2816,7 @@ Veuillez vérifier la configuration de votre réseau et de votre pare-feu.
 
 Aucune communication vocale n&apos;est disponible.
 Veuillez vérifier la configuration de votre réseau et de votre pare-feu.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="AvatarRezLeftNotification">
 		([EXISTENCE] secondes d&apos;existence)
@@ -2827,6 +2851,9 @@ Ignorer les autres ?
 	<notification label="Explorer le monde" name="HintDestinationGuide">
 		Le Guide des destinations comprend des milliers d&apos;endroits nouveaux à découvrir. Sélectionnez-en un, puis cliquez sur Téléporter pour commencer à l&apos;explorer.
 	</notification>
+	<notification label="Changer d&apos;apparence" name="HintAvatarPicker">
+		Vous souhaitez changer de look ? Cliquez sur le bouton ci-dessous pour voir plus d&apos;avatars.
+	</notification>
 	<notification label="Panneau latéral" name="HintSidePanel">
 		Obtenir un accès rapide à votre inventaire, à vos habits, à vos profils et bien plus encore dans le panneau latéral.
 	</notification>
@@ -2836,6 +2863,12 @@ Ignorer les autres ?
 	<notification label="Nom d&apos;affichage" name="HintDisplayName">
 		Définissez ici votre nom d&apos;affichage personnalisable. Cette fonctionnalité vous est fournie en plus de votre nom d&apos;utilisateur unique qui, lui, ne peut être changé. Vous pouvez modifier l&apos;apparence des noms des autres résidents dans vos préférences.
 	</notification>
+	<notification label="Bouger" name="HintMoveArrows">
+		Pour marcher, utilisez les touches fléchées de votre clavier. Pour courir, appuyez deux fois sur la flèche vers le haut.
+	</notification>
+	<notification label="Affichage" name="HintView">
+		Pour changer d&apos;angle de vision, utilisez les contrôles Faire tourner et Faire un panoramique. Pour réinitialiser la vue, appuyez sur Échap ou marchez.
+	</notification>
 	<notification label="Inventaire" name="HintInventory">
 		Permet de rechercher des articles dans l&apos;inventaire. Pour accéder aux derniers articles ajoutés, cliquez sur l&apos;onglet Récent.
 	</notification>
@@ -2849,6 +2882,15 @@ Ignorer les autres ?
 			<button name="open" text="Ouvrir la fenêtre popup"/>
 		</form>
 	</notification>
+	<notification name="AuthRequest">
+		Nom d&apos;utilisateur et mot de passe requis pour le site se trouvant à l&apos;emplacement suivant : &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos;, domaine &apos;[REALM]&apos;.
+		<form name="form">
+			<input name="username" text="Nom d&apos;utilisateur"/>
+			<input name="password" text="Mot de passe"/>
+			<button name="ok" text="Soumettre"/>
+			<button name="cancel" text="Annuler"/>
+		</form>
+	</notification>
 	<global name="UnsupportedCPU">
 		- Votre processeur ne remplit pas les conditions minimum requises.
 	</global>
diff --git a/indra/newview/skins/default/xui/fr/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/fr/panel_avatar_list_item.xml
index 607665ddd8..54b8f53e59 100644
--- a/indra/newview/skins/default/xui/fr/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/fr/panel_avatar_list_item.xml
@@ -21,7 +21,7 @@
 	<string name="FormatYears">
 		[COUNT] a
 	</string>
-	<text name="avatar_name" value="Inconnu"/>
+	<text name="avatar_name" value="(chargement)"/>
 	<text name="last_interaction" value="0s"/>
 	<icon name="permission_edit_theirs_icon" tool_tip="Vous pouvez modifier les objets de cet(te) ami(e)."/>
 	<icon name="permission_edit_mine_icon" tool_tip="Cet(te) ami(e) peut modifier, supprimer ou prendre vos objets."/>
diff --git a/indra/newview/skins/default/xui/fr/panel_edit_alpha.xml b/indra/newview/skins/default/xui/fr/panel_edit_alpha.xml
index 3b81ef2a5f..a8b95c66fb 100644
--- a/indra/newview/skins/default/xui/fr/panel_edit_alpha.xml
+++ b/indra/newview/skins/default/xui/fr/panel_edit_alpha.xml
@@ -1,10 +1,12 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_alpha_panel">
-	<panel name="avatar_alpha_color_panel">
-		<texture_picker label="Alpha bas" name="Lower Alpha" tool_tip="Cliquez pour sélectionner une image"/>
-		<texture_picker label="Alpha haut" name="Upper Alpha" tool_tip="Cliquez pour sélectionner une image"/>
-		<texture_picker label="Alpha tête" name="Head Alpha" tool_tip="Cliquez pour sélectionner une image"/>
-		<texture_picker label="Alpha yeux" name="Eye Alpha" tool_tip="Cliquez pour sélectionner une image"/>
-		<texture_picker label="Alpha cheveux" width="80" name="Hair Alpha" tool_tip="Cliquez pour sélectionner une image"/>
-	</panel>
+	<scroll_container name="avatar_alpha_color_panel_scroll">
+		<panel name="avatar_alpha_color_panel">
+			<texture_picker label="Alpha bas" name="Lower Alpha" tool_tip="Cliquer pour sélectionner une image."/>
+			<texture_picker label="Alpha haut" name="Upper Alpha" tool_tip="Cliquer pour sélectionner une image."/>
+			<texture_picker label="Alpha tête" name="Head Alpha" tool_tip="Cliquer pour sélectionner une image."/>
+			<texture_picker label="Alpha yeux" name="Eye Alpha" tool_tip="Cliquer pour sélectionner une image."/>
+			<texture_picker label="Alpha cheveux" name="Hair Alpha" tool_tip="Cliquer pour sélectionner une image."/>
+		</panel>
+	</scroll_container>
 </panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_login.xml b/indra/newview/skins/default/xui/fr/panel_login.xml
index b667780180..ef55ba7991 100644
--- a/indra/newview/skins/default/xui/fr/panel_login.xml
+++ b/indra/newview/skins/default/xui/fr/panel_login.xml
@@ -11,7 +11,7 @@
 			<text name="username_text">
 				Nom d&apos;utilisateur :
 			</text>
-			<line_editor label="bobsmith12 ou Steller Sunshine" name="username_edit" tool_tip="Nom d&apos;utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/>
+			<combo_box name="username_combo" tool_tip="Nom d&apos;utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/>
 			<text name="password_text">
 				Mot de passe :
 			</text>
diff --git a/indra/newview/skins/default/xui/fr/panel_my_profile.xml b/indra/newview/skins/default/xui/fr/panel_my_profile.xml
index 8dbc22d3c7..5207c5a28e 100644
--- a/indra/newview/skins/default/xui/fr/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/fr/panel_my_profile.xml
@@ -16,34 +16,27 @@
 	<string name="RegisterDateFormat">
 		[REG_DATE] ([AGE])
 	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
 	<layout_stack name="layout">
 		<layout_panel name="profile_stack">
 			<scroll_container name="profile_scroll">
 				<panel name="scroll_content_panel">
 					<panel name="second_life_image_panel">
-						<icon label="" name="2nd_life_edit_icon" tool_tip="Cliquez sur le bouton Modifier le profil ci-dessous pour changer d&apos;image"/>
-						<text name="title_sl_descr_text" value="[SECOND_LIFE]:"/>
-					</panel>
-					<panel name="first_life_image_panel">
-						<icon label="" name="real_world_edit_icon" tool_tip="Cliquez sur le bouton Modifier le profil ci-dessous pour changer d&apos;image"/>
-						<text name="title_rw_descr_text" value="Vie réelle :"/>
-					</panel>
-					<text name="title_member_text" value="Résident depuis :"/>
-					<text name="title_acc_status_text" value="Statut du compte :"/>
-					<text_editor name="acc_status_text">
-						Résident. Aucune info de paiement enregistrée.
-              Linden.
-					</text_editor>
-					<text name="title_partner_text" value="Partenaire :"/>
-					<panel name="partner_data_panel">
-						<name_box initial_value="(récupération en cours)" name="partner_text"/>
+						<text name="display_name_descr_text">
+							Nom d&apos;utilisateur
+						</text>
+						<text name="name_descr_text">
+							Nom d&apos;affichage
+						</text>
+						<button label="Profil" name="see_profile_btn" tool_tip="Afficher le profil de cet avatar."/>
 					</panel>
-					<text name="title_groups_text" value="Groupes :"/>
 				</panel>
 			</scroll_container>
 		</layout_panel>
 	</layout_stack>
-	<panel name="profile_me_buttons_panel">
-		<button label="Modifier le profil" name="edit_profile_btn" tool_tip="Modifier vos informations personnelles"/>
-	</panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_notify_textbox.xml b/indra/newview/skins/default/xui/fr/panel_notify_textbox.xml
index a37770e184..6ce09cde4b 100644
--- a/indra/newview/skins/default/xui/fr/panel_notify_textbox.xml
+++ b/indra/newview/skins/default/xui/fr/panel_notify_textbox.xml
@@ -3,8 +3,9 @@
 	<string name="message_max_lines_count" value="7"/>
 	<panel label="info_panel" name="info_panel">
 		<text_editor name="message" value="message"/>
-		parse_urls=&quot;false&quot;
+	</panel>
+	<panel label="control_panel" name="control_panel">
 		<button label="Soumettre" name="btn_submit"/>
+		<button label="Ignorer" name="ignore_btn"/>
 	</panel>
-	<panel label="control_panel" name="control_panel"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_colors.xml b/indra/newview/skins/default/xui/fr/panel_preferences_colors.xml
index e94bb08c9c..4e7d75e1b9 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_colors.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_colors.xml
@@ -29,10 +29,10 @@
 		URL
 	</text>
 	<text name="bubble_chat">
-		Arrière-plan des bulles de chat :
+		Couleur de fond des noms (bulles de chat comprises) :
 	</text>
-	<color_swatch name="background" tool_tip="Choisir la couleur des bulles de chat."/>
-	<slider label="Opacité :" name="bubble_chat_opacity"/>
+	<color_swatch name="background" tool_tip="Choisir une couleur pour les noms."/>
+	<slider label="Opacité :" name="bubble_chat_opacity" tool_tip="Choisir une opacité pour les noms."/>
 	<text name="floater_opacity">
 		Opacité des fenêtres flottantes :
 	</text>
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/fr/panel_preferences_privacy.xml
index 6a4c77a10e..202ec779f5 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_privacy.xml
@@ -7,9 +7,11 @@
 	<text name="cache_size_label_l">
 		(Endroits, images, web, historique des recherches)
 	</text>
+	<check_box label="M&apos;afficher dans les résultats de recherche" name="online_searchresults"/>
 	<check_box label="Seuls mes amis et groupes voient quand je suis en ligne" name="online_visibility"/>
 	<check_box label="Seuls mes amis et groupes peuvent m&apos;appeler ou m&apos;envoyer un IM" name="voice_call_friends_only_check"/>
 	<check_box label="Fermer le micro à la fin d&apos;un appel" name="auto_disengage_mic_check"/>
+	<check_box label="Afficher mes repères favoris à la connexion (liste déroulante Lieu de départ)" name="favorites_on_login_check"/>
 	<text name="Logs:">
 		Journaux de chat :
 	</text>
diff --git a/indra/newview/skins/default/xui/fr/panel_preferences_setup.xml b/indra/newview/skins/default/xui/fr/panel_preferences_setup.xml
index 8fa499d14a..bfe0defd56 100644
--- a/indra/newview/skins/default/xui/fr/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/fr/panel_preferences_setup.xml
@@ -39,5 +39,11 @@
 	</text>
 	<line_editor name="web_proxy_editor" tool_tip="Le nom ou adresse IP du proxy que vous souhaitez utiliser"/>
 	<spinner label="Numéro de port :" label_width="95" name="web_proxy_port" width="170"/>
-	<check_box initial_value="true" label="Télécharger et installer automatiquement les mises à jour [APP_NAME]" name="updater_service_active"/>
+	<text name="Software updates:">
+		Mises à jour logicielles :
+	</text>
+	<combo_box name="updater_service_combobox">
+		<combo_box.item label="Installation automatique" name="Install_automatically"/>
+		<combo_box.item label="Téléchargement et installation manuels" name="Install_manual"/>
+	</combo_box>
 </panel>
diff --git a/indra/newview/skins/default/xui/fr/panel_status_bar.xml b/indra/newview/skins/default/xui/fr/panel_status_bar.xml
index 85429a18c7..69aec99e1d 100644
--- a/indra/newview/skins/default/xui/fr/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/fr/panel_status_bar.xml
@@ -22,7 +22,7 @@
 		[AMT] L$
 	</panel.string>
 	<panel name="balance_bg">
-		<text name="balance" tool_tip="Mon solde" value="20 L$"/>
+		<text name="balance" tool_tip="Cliquer sur ce bouton pour actualiser votre solde en L$." value="20 L$"/>
 		<button label="ACHETER L$" name="buyL" tool_tip="Cliquer pour acheter plus de L$"/>
 	</panel>
 	<text name="TimeText" tool_tip="Heure actuelle (Pacifique)">
diff --git a/indra/newview/skins/default/xui/pl/floater_hardware_settings.xml b/indra/newview/skins/default/xui/pl/floater_hardware_settings.xml
index bd5dd7e7d2..471d2c39ba 100644
--- a/indra/newview/skins/default/xui/pl/floater_hardware_settings.xml
+++ b/indra/newview/skins/default/xui/pl/floater_hardware_settings.xml
@@ -14,6 +14,9 @@
 		<combo_box.item label="8x" name="8x"/>
 		<combo_box.item label="16x" name="16x"/>
 	</combo_box>
+	<text name="antialiasing restart">
+		(Restart wymagany)
+	</text>
 	<spinner label="Gamma:" name="gamma"/>
 	<text name="(brightness, lower is brighter)">
 		(0=domyślna jaskrawość, niższa wartość=jaśniej)
diff --git a/indra/newview/skins/default/xui/pl/floater_preferences.xml b/indra/newview/skins/default/xui/pl/floater_preferences.xml
index 3f62d764c6..930a5c76b0 100644
--- a/indra/newview/skins/default/xui/pl/floater_preferences.xml
+++ b/indra/newview/skins/default/xui/pl/floater_preferences.xml
@@ -5,10 +5,12 @@
 	<tab_container name="pref core">
 		<panel label="Ogólne" name="general"/>
 		<panel label="Grafika" name="display"/>
-		<panel label="Prywatność" name="im"/>
 		<panel label="Dźwięk &amp; Media" name="audio"/>
 		<panel label="Czat" name="chat"/>
+		<panel label="Ruch &amp; Widok" name="move"/>
 		<panel label="Powiadomienia" name="msgs"/>
+		<panel label="Kolory" name="colors"/>
+		<panel label="Prywatność" name="im"/>
 		<panel label="Ustawienie" name="input"/>
 		<panel label="Zaawansowane" name="advanced1"/>
 	</tab_container>
diff --git a/indra/newview/skins/default/xui/pl/menu_inventory_gear_default.xml b/indra/newview/skins/default/xui/pl/menu_inventory_gear_default.xml
index d110a2f02e..491b4deeaa 100644
--- a/indra/newview/skins/default/xui/pl/menu_inventory_gear_default.xml
+++ b/indra/newview/skins/default/xui/pl/menu_inventory_gear_default.xml
@@ -1,8 +1,9 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<menu name="menu_gear_default">
+<toggleable_menu name="menu_gear_default">
 	<menu_item_call label="Nowe okno Szafy" name="new_window"/>
-	<menu_item_call label="Porządkuj według nazwy" name="sort_by_name"/>
-	<menu_item_call label="Porządkuj według daty" name="sort_by_recent"/>
+	<menu_item_check label="Porządkuj według nazwy" name="sort_by_name"/>
+	<menu_item_check label="Porządkuj według daty" name="sort_by_recent"/>
+	<menu_item_check label="Posortuj foldery systemowe od góry" name="sort_system_folders_to_top"/>
 	<menu_item_call label="Pokaż filtry" name="show_filters"/>
 	<menu_item_call label="Zresetuj filtry" name="reset_filters"/>
 	<menu_item_call label="Zamknij wszystkie foldery" name="close_folders"/>
@@ -12,4 +13,4 @@
 	<menu_item_call label="Znajdź oryginał" name="Find Original"/>
 	<menu_item_call label="Znajdź wszystkie linki" name="Find All Links"/>
 	<menu_item_call label="Opróżnij Kosz" name="empty_trash"/>
-</menu>
+</toggleable_menu>
diff --git a/indra/newview/skins/default/xui/pl/menu_login.xml b/indra/newview/skins/default/xui/pl/menu_login.xml
index 0dd6117b85..e50b694641 100644
--- a/indra/newview/skins/default/xui/pl/menu_login.xml
+++ b/indra/newview/skins/default/xui/pl/menu_login.xml
@@ -16,7 +16,8 @@
 		<menu_item_call label="Ustaw rozmiar interfejsu..." name="Set Window Size..."/>
 		<menu_item_call label="Wyświetl TOS" name="TOS"/>
 		<menu_item_call label="Wyświetl wiadomość krytyczną" name="Critical"/>
-		<menu_item_call label="Test przeglądarki internetowej" name="Web Browser Test"/>
+		<menu_item_call label="Test przeglądarki mediów" name="Web Browser Test"/>
+		<menu_item_call label="Test zawartości strony" name="Web Content Floater Test"/>
 		<menu_item_check label="Pokaż siatkę" name="Show Grid Picker"/>
 		<menu_item_call label="Pokaż konsolę Zawiadomień" name="Show Notifications Console"/>
 	</menu>
diff --git a/indra/newview/skins/default/xui/pl/menu_mini_map.xml b/indra/newview/skins/default/xui/pl/menu_mini_map.xml
index 148adfba0d..8f86965416 100644
--- a/indra/newview/skins/default/xui/pl/menu_mini_map.xml
+++ b/indra/newview/skins/default/xui/pl/menu_mini_map.xml
@@ -3,6 +3,7 @@
 	<menu_item_call label="Zoom blisko" name="Zoom Close"/>
 	<menu_item_call label="Zoom średnio" name="Zoom Medium"/>
 	<menu_item_call label="Zoom daleko" name="Zoom Far"/>
+	<menu_item_call label="Zoom domyślny" name="Zoom Default"/>
 	<menu_item_check label="Obróć mapę" name="Rotate Map"/>
 	<menu_item_check label="Autocentrowanie" name="Auto Center"/>
 	<menu_item_call label="Zatrzymaj" name="Stop Tracking"/>
diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml
index a359180ffb..e6a9d360c4 100644
--- a/indra/newview/skins/default/xui/pl/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml
@@ -10,6 +10,12 @@
 		<menu_item_check label="Moja Szafa" name="ShowSidetrayInventory"/>
 		<menu_item_check label="Moje gesturki" name="Gestures"/>
 		<menu_item_check label="Mój głos" name="ShowVoice"/>
+		<menu label="Ruch" name="Movement">
+			<menu_item_call label="Usiądź" name="Sit Down Here"/>
+			<menu_item_check label="Zacznij latać" name="Fly"/>
+			<menu_item_check label="Zawsze biegnij" name="Always Run"/>
+			<menu_item_call label="Zatrzymaj animacje" name="Stop Animating My Avatar"/>
+		</menu>
 		<menu label="Mój Status" name="Status">
 			<menu_item_call label="Tryb oddalenia" name="Set Away"/>
 			<menu_item_call label="Tryb pracy" name="Set Busy"/>
@@ -45,6 +51,7 @@
 			<menu_item_check label="Właściciele posiadłości" name="Land Owners"/>
 			<menu_item_check label="Współrzędne" name="Coordinates"/>
 			<menu_item_check label="Właściwości posiadłości" name="Parcel Properties"/>
+			<menu_item_check label="Menu Zaawansowane" name="Show Advanced Menu"/>
 		</menu>
 		<menu_item_call label="Teleportuj do Miejsca Startu" name="Teleport Home"/>
 		<menu_item_call label="Ustaw Miejsce Startu" name="Set Home to Here"/>
@@ -112,16 +119,17 @@
 			<menu_item_call label="animację (L$[COST])..." name="Upload Animation"/>
 			<menu_item_call label="zbiór plików (L$[COST] za jeden plik)..." name="Bulk Upload"/>
 		</menu>
+		<menu_item_call label="Cofnij" name="Undo"/>
+		<menu_item_call label="Ponów" name="Redo"/>
 	</menu>
 	<menu label="Pomoc" name="Help">
 		<menu_item_call label="[SECOND_LIFE] Portal Pomocy" name="Second Life Help"/>
+		<menu_item_check label="Włącz podpowiedzi" name="Enable Hints"/>
 		<menu_item_call label="Złóż Raport o Nadużyciu" name="Report Abuse"/>
 		<menu_item_call label="Zgłoś błędy klienta" name="Report Bug"/>
 		<menu_item_call label="O [APP_NAME]" name="About Second Life"/>
-		<menu_item_check label="Włącz podpowiedzi" name="Enable Hints"/>
 	</menu>
 	<menu label="Zaawansowane" name="Advanced">
-		<menu_item_call label="Zatrzymaj wszystkie animacje" name="Stop Animating My Avatar"/>
 		<menu_item_call label="Odswież wyświetlanie tekstur" name="Rebake Texture"/>
 		<menu_item_call label="Domyślne ustawienia rozmiaru interfejsu" name="Set UI Size to Default"/>
 		<menu_item_call label="Ustaw rozmiar interfejsu..." name="Set Window Size..."/>
@@ -175,8 +183,7 @@
 			<menu_item_check label="Szukaj" name="Search"/>
 			<menu_item_call label="Zwolnij klawisze" name="Release Keys"/>
 			<menu_item_call label="Domyślne ustawienia rozmiaru interfejsu" name="Set UI Size to Default"/>
-			<menu_item_check label="Biegnij" name="Always Run"/>
-			<menu_item_check label="Zacznij latać" name="Fly"/>
+			<menu_item_check label="Pokaż menu Zaawansowane - skrót" name="Show Advanced Menu - legacy shortcut"/>
 			<menu_item_call label="Zamknij okno" name="Close Window"/>
 			<menu_item_call label="Zamknij wszystkie okna" name="Close All Windows"/>
 			<menu_item_call label="Zapisz zdjęcie na dysk twardy" name="Snapshot to Disk"/>
@@ -194,7 +201,6 @@
 			<menu_item_call label="Przybliż" name="Zoom In"/>
 			<menu_item_call label="Domyślne przybliżenie" name="Zoom Default"/>
 			<menu_item_call label="Oddal" name="Zoom Out"/>
-			<menu_item_check label="Pokaż menu Zaawansowane" name="Show Advanced Menu"/>
 		</menu>
 		<menu_item_call label="Pokaż ustawienia debugowania" name="Debug Settings"/>
 		<menu_item_check label="Pokaż menu progresu" name="Debug Mode"/>
@@ -262,19 +268,17 @@
 			<menu_item_call label="Zachowaj bufor pamięci obiektów regionu" name="Dump Region Object Cache"/>
 		</menu>
 		<menu label="UI" name="UI">
-			<menu_item_call label="Test przeglądarki internetowej" name="Web Browser Test"/>
+			<menu_item_call label="Test przeglądarki mediów" name="Web Browser Test"/>
+			<menu_item_call label="Przeglądarka zawartości strony" name="Web Content Browser"/>
 			<menu_item_call label="Drukuj zaznaczone informacje o obiekcie" name="Print Selected Object Info"/>
 			<menu_item_call label="Statystyki pamięci" name="Memory Stats"/>
-			<menu_item_check label="Auto-pilot na podwójne kliknięcie" name="Double-ClickAuto-Pilot"/>
-			<menu_item_check label="Podwójne kliknięcie - Teleportuj" name="DoubleClick Teleport"/>
+			<menu_item_check label="Konsola debugowania regionu" name="Region Debug Console"/>
 			<menu_item_check label="Debugowanie zdarzeń klikania" name="Debug Clicks"/>
 			<menu_item_check label="Debugowanie zdarzeń myszy" name="Debug Mouse Events"/>
 		</menu>
 		<menu label="XUI" name="XUI">
 			<menu_item_call label="Załaduj ustawienia koloru" name="Reload Color Settings"/>
 			<menu_item_call label="Pokaż test czcionki" name="Show Font Test"/>
-			<menu_item_call label="Załaduj z XML" name="Load from XML"/>
-			<menu_item_call label="Zapisz jako XML" name="Save to XML"/>
 			<menu_item_check label="Pokaż nazwy XUI" name="Show XUI Names"/>
 			<menu_item_call label="Wyślij wiadomość (IM) testową" name="Send Test IMs"/>
 			<menu_item_call label="Wyczyść bufor pamięci nazw" name="Flush Names Caches"/>
@@ -301,9 +305,9 @@
 		</menu>
 		<menu_item_check label="Tekstury HTTP" name="HTTP Textures"/>
 		<menu_item_check label="Aktywacja okna konsoli podczas następnego uruchomienia" name="Console Window"/>
-		<menu_item_check label="Pokaż menu administratora" name="View Admin Options"/>
 		<menu_item_call label="Uzyskaj status administratora" name="Request Admin Options"/>
 		<menu_item_call label="Opuść status administratora" name="Leave Admin Options"/>
+		<menu_item_check label="Pokaż menu administratora" name="View Admin Options"/>
 	</menu>
 	<menu label="Administrator" name="Admin">
 		<menu label="Object">
diff --git a/indra/newview/skins/default/xui/pl/notifications.xml b/indra/newview/skins/default/xui/pl/notifications.xml
index 8151c7eb93..8dc4b041cd 100644
--- a/indra/newview/skins/default/xui/pl/notifications.xml
+++ b/indra/newview/skins/default/xui/pl/notifications.xml
@@ -109,6 +109,10 @@ Wybierz pojedynczy obiekt i spróbuj jeszcze raz.
 		Osoby spoza listy znajomych, których rozmowy głosowe i IM są ignorowane, nie wiedzą o tym.
 		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
+	<notification name="FavoritesOnLogin">
+		Pamiętaj: kiedy wyłączysz tą opcję, każdy kto używa tego komputera, może zobaczyć Twoją listę ulubionych miejsc.
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
 	<notification name="GrantModifyRights">
 		Udzielenie praw modyfikacji innemu Rezydentowi umożliwia modyfikację, usuwanie lub wzięcie JAKIEGOKOLWIEK z Twoich obiektów. Używaj tej opcji z rozwagą!
 Czy chcesz udzielić prawa do modyfikacji [NAME]?
@@ -383,6 +387,9 @@ Pamiętaj: Opcja ta wyczyszcza bufor danych.
 	<notification name="ChangeSkin">
 		Nowa skórka zostanie wczytana po restarcie aplikacji [APP_NAME].
 	</notification>
+	<notification name="ChangeLanguage">
+		Zmiana języka zadziała po restarcie [APP_NAME].
+	</notification>
 	<notification name="GoToAuctionPage">
 		Odwiedzić stronę internetową [SECOND_LIFE] żeby zobaczyć szczgóły aukcji lub zrobić ofertę?
 		<usetemplate name="okcancelbuttons" notext="Anuluj" yestext="OK"/>
@@ -578,6 +585,10 @@ Oczekiwana - [VALIDS]
 	</notification>
 	<notification name="SoundFileInvalidHeader">
 		Brak bloku &apos;data&apos; w nagłówku pliku WAV:
+[FILE]
+	</notification>
+	<notification name="SoundFileInvalidChunkSize">
+		Niewłaściwy rozmiar &quot;chunk&quot; w pliku WAV:
 [FILE]
 	</notification>
 	<notification name="SoundFileInvalidTooLong">
@@ -917,7 +928,7 @@ Zaproponować znajomość [NAME]?
 			<input name="message">
 				[DESC] (nowe)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Anuluj"/>
 		</form>
 	</notification>
@@ -927,7 +938,7 @@ Zaproponować znajomość [NAME]?
 			<input name="message">
 				[DESC] (nowy)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Anuluj"/>
 		</form>
 	</notification>
@@ -937,7 +948,7 @@ Zaproponować znajomość [NAME]?
 			<input name="new_name">
 				[NAME]
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Anuluj"/>
 		</form>
 	</notification>
@@ -1303,6 +1314,40 @@ Aktualizacja nie jest wymagana ale jest zalecana w celu poprawy prędkości i st
 Pobrać i zapisać w folderze Aplikacji?
 		<usetemplate name="okcancelbuttons" notext="Kontynuuj" yestext="Załaduj"/>
 	</notification>
+	<notification name="FailedUpdateInstall">
+		Podczas aktualizacji pojawił się błąd. Proszę pobrać i zainstalować najnowszego klienta z http://secondlife.com/download.
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
+	<notification name="FailedRequiredUpdateInstall">
+		Nie można zainstalować wymaganej aktualizacji. Nie będzie można zalogować się dopóki [APP_NAME] nie zostanie zaktualizowana.
+				Proszę pobrać i zainstalować najnowszą wersję z http://secondlife.com/download.
+		<usetemplate name="okbutton" yestext="Rezygnuj"/>
+	</notification>
+	<notification name="UpdaterServiceNotRunning">
+		Istnieje obowiązkowa aktualizacja dla Second Life. Możesz ją pobrać z http://www.secondlife.com/downloads lub zainstalować teraz.
+		<usetemplate name="okcancelbuttons" notext="Opuść Second Life" yestext="Pobierz i zainstaluj teraz"/>
+	</notification>
+	<notification name="DownloadBackgroundTip">
+		Aktualizacja dla [APP_NAME] została pobrana.
+Wersja [VERSION] [[RELEASE_NOTES_FULL_URL] Informacja o tej aktualizacji]
+		<usetemplate name="okcancelbuttons" notext="Później..." yestext="Zainstaluj teraz i restartuj [APP_NAME]"/>
+	</notification>
+	<notification name="DownloadBackgroundDialog">
+		Aktualizacja [APP_NAME] została pobrana.
+Wersja [VERSION] [[RELEASE_NOTES_FULL_URL] Informacja o aktualizacji]
+		<usetemplate name="okcancelbuttons" notext="Później..." yestext="Zainstaluj teraz i restartuj [APP_NAME]"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedVerboseDialog">
+		Pobrano wymaganą aktualizację.
+Wersja [VERSION]
+
+W celu instalacji aktualizacji musi zostać wykonany restart [APP_NAME].
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedDialog">
+		W celu instalacji aktualizacji musi zostać wykonany restart [APP_NAME].
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
 	<notification name="DeedObjectToGroup">
 		Przekazanie tego obiektu spowoduje, że grupa:
 * Otrzyma L$ zapłacone temu obiektowi
@@ -2171,14 +2216,6 @@ Spróbuj wybrać mniejszy obszar.
 	<notification name="NoContentToSearch">
 		Proszę wybrać przynajmiej jeden z podanych rodzajów treści jaką zawiera region podczas wyszukiwania (&apos;General&apos;, &apos;Moderate&apos;, lub &apos;Adult&apos;).
 	</notification>
-	<notification name="GroupVote">
-		[NAME] zaprasza do głosowania nad propozycją:
-[MESSAGE]
-		<form name="form">
-			<button name="VoteNow" text="Głosuj Teraz"/>
-			<button name="Later" text="Później"/>
-		</form>
-	</notification>
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
@@ -2440,8 +2477,8 @@ Spróbuj ponowanie za kilka minut.
 		Propozycja znajomości została odrzucona.
 	</notification>
 	<notification name="OfferCallingCard">
-		[NAME] daje Tobie swoją wizytówkę.
-Wizytówka będzie znajdowała się w Szafie i umożliwi szybkie wysłanie IM do tego Rezydenta.
+		[NAME] oferuje swoją wizytówkę.
+Wizytówka w Twojej Szafie umożliwi szybki kontakt IM z tym Rezydentem.
 		<form name="form">
 			<button name="Accept" text="Zaakceptuj"/>
 			<button name="Decline" text="Odmów"/>
@@ -2740,9 +2777,7 @@ Awatar &apos;[NAME]&apos; opuścił edycję wyglądu.
 	<notification name="NoConnect">
 		Występuje problem z połączeniem [PROTOCOL] [HOSTID].
 Proszę sprawdź swoją sieć i ustawienia firewall.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="NoVoiceConnect">
 		Występuje problem z Twoim połączniem głosowym:
@@ -2751,9 +2786,7 @@ Proszę sprawdź swoją sieć i ustawienia firewall.
 
 Komunikacja głosowa nie będzie dostępna.
 Proszę sprawdź swoją sieć i ustawienia firewall.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="AvatarRezLeftNotification">
 		( [EXISTENCE] sekund w Second Life)
@@ -2787,6 +2820,9 @@ Wyciszyć wszystkich?
 	<notification label="Odkrywaj Świat" name="HintDestinationGuide">
 		Destination Guide zawiera tysiące nowych miejsc do odkrycia. Wybierz lokalizację i teleportuj się aby rozpocząć zwiedzanie.
 	</notification>
+	<notification label="Zmień wygląd swojego awatara" name="HintAvatarPicker">
+		Czy chcesz inaczej wyglądać? Kliknij poniższy przycisk aby zobaczyć więcej przykładów awatarów.
+	</notification>
 	<notification label="Schowek" name="HintSidePanel">
 		Schowek umożliwia szybki dostęp do Twojej Szafy, ubrań, profili i innych w panelu bocznym.
 	</notification>
@@ -2796,6 +2832,12 @@ Wyciszyć wszystkich?
 	<notification label="Wyświetlana nazwa" name="HintDisplayName">
 		Ustaw wyświetlaną nazwę, którą możesz zmieniać tutaj. Jest ona dodatkiem do unikatowej nazwy użytkownika, która nie może być zmieniona. Możesz zmienić sposób w jaki widzisz nazwy innych osób w Twoich Ustawieniach.
 	</notification>
+	<notification label="Ruch" name="HintMoveArrows">
+		Użyj przycisków ze strzałkami z klawiatury aby chodzić. Jeśli wciśniesz strzałkę &apos;do góry&apos; podwójnie, zaczniesz biec.
+	</notification>
+	<notification label="Widok" name="HintView">
+		To change your camera view, use the Orbit and Pan controls. Zresetuj widok poprzez wciśnięcie klawisza Esc lub chodzenie.
+	</notification>
 	<notification label="Szafa" name="HintInventory">
 		Sprawdź swoją Szafę aby znaleźć obiekty. Najnowsze obiekty mogą być łatwo odnalezione w zakładce Nowe obiekty.
 	</notification>
@@ -2809,6 +2851,15 @@ Wyciszyć wszystkich?
 			<button name="open" text="Otwórz wyskakujące okno."/>
 		</form>
 	</notification>
+	<notification name="AuthRequest">
+		Strpna &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; w domenie &apos;[REALM]&apos; wymaga nazwy użytkownika i hasła.
+		<form name="form">
+			<input name="username" text="Nazwa użytkownika"/>
+			<input name="password" text="Hasło"/>
+			<button name="ok" text="Wyślij"/>
+			<button name="cancel" text="Anuluj"/>
+		</form>
+	</notification>
 	<global name="UnsupportedCPU">
 		- Prędkość Twojego CPU nie spełnia minimalnych wymagań.
 	</global>
diff --git a/indra/newview/skins/default/xui/pl/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/pl/panel_avatar_list_item.xml
index 1ab95eec00..c43a9bed81 100644
--- a/indra/newview/skins/default/xui/pl/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/pl/panel_avatar_list_item.xml
@@ -21,7 +21,7 @@
 	<string name="FormatYears">
 		[COUNT]lat
 	</string>
-	<text name="avatar_name" value="Nieznane"/>
+	<text name="avatar_name" value="(ładowanie)"/>
 	<icon name="permission_edit_theirs_icon" tool_tip="Możesz edytować obiekty tego Znajomego"/>
 	<icon name="permission_edit_mine_icon" tool_tip="Ten Znajomy może edytować, kasować lub wziąć Twoje obiekty"/>
 	<icon name="permission_map_icon" tool_tip="Ten Znajomy może zlokalizować Ciebie na mapie"/>
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_alpha.xml b/indra/newview/skins/default/xui/pl/panel_edit_alpha.xml
index a22d4b0482..51ee3af00d 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_alpha.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_alpha.xml
@@ -1,10 +1,12 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_alpha_panel">
-	<panel name="avatar_alpha_color_panel">
-		<texture_picker label="Alpha dolnej części ciała" name="Lower Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
-		<texture_picker label="Alpha górnej części ciała" name="Upper Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
-		<texture_picker label="Alpha głowy" name="Head Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
-		<texture_picker label="Alpha oka" name="Eye Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
-		<texture_picker label="Alpha włosów" name="Hair Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
-	</panel>
+	<scroll_container name="avatar_alpha_color_panel_scroll">
+		<panel name="avatar_alpha_color_panel">
+			<texture_picker label="Alpha dolnej części ciała" name="Lower Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
+			<texture_picker label="Alpha górnej części ciała" name="Upper Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
+			<texture_picker label="Alpha głowy" name="Head Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
+			<texture_picker label="Alpha oka" name="Eye Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
+			<texture_picker label="Alpha włosów" name="Hair Alpha" tool_tip="Kliknij aby wybrać teksturę"/>
+		</panel>
+	</scroll_container>
 </panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_gloves.xml b/indra/newview/skins/default/xui/pl/panel_edit_gloves.xml
index 166e3c4551..d32646d1a3 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_gloves.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_gloves.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_gloves_panel">
 	<panel name="avatar_gloves_color_panel">
-		<texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
+		<texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
 		<color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać teksturę"/>
 	</panel>
 	<panel name="accordion_panel">
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_jacket.xml b/indra/newview/skins/default/xui/pl/panel_edit_jacket.xml
index ba0b908394..7653e84cc0 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_jacket.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_jacket.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_jacket_panel">
 	<panel name="avatar_jacket_color_panel">
-		<texture_picker label="Górny materiał" name="Upper Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
-		<texture_picker label="Dolny materiał" name="Lower Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
+		<texture_picker label="Górna tekstura" name="Upper Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
+		<texture_picker label="Dolna tekstura" name="Lower Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
 		<color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/>
 	</panel>
 	<panel name="accordion_panel">
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_pants.xml b/indra/newview/skins/default/xui/pl/panel_edit_pants.xml
index 4adac604f4..7975e55746 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_pants.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_pants.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_pants_panel">
 	<panel name="avatar_pants_color_panel">
-		<texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
+		<texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
 		<color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/>
 	</panel>
 	<panel name="accordion_panel">
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_shirt.xml b/indra/newview/skins/default/xui/pl/panel_edit_shirt.xml
index 3bcf992d4d..9530c781ab 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_shirt.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_shirt.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_shirt_panel">
 	<panel name="avatar_shirt_color_panel">
-		<texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij by wybrać grafikę"/>
+		<texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij by wybrać grafikę"/>
 		<color_swatch label="Kolor/Odcień" name="Color/Tint" tool_tip="Kliknij by wybrać kolor"/>
 	</panel>
 	<panel name="accordion_panel">
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_shoes.xml b/indra/newview/skins/default/xui/pl/panel_edit_shoes.xml
index e2c00c0506..d90a6d8726 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_shoes.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_shoes.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_shoes_panel">
 	<panel name="avatar_shoes_color_panel">
-		<texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
+		<texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
 		<color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/>
 	</panel>
 	<panel name="accordion_panel">
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_skirt.xml b/indra/newview/skins/default/xui/pl/panel_edit_skirt.xml
index 3fa9cefeb6..f74ad916cd 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_skirt.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_skirt.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_skirt_panel">
 	<panel name="avatar_skirt_color_panel">
-		<texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
+		<texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
 		<color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/>
 	</panel>
 	<panel name="accordion_panel">
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_socks.xml b/indra/newview/skins/default/xui/pl/panel_edit_socks.xml
index bb2cd637b5..b41069e8d7 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_socks.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_socks.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_socks_panel">
 	<panel name="avatar_socks_color_panel">
-		<texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
+		<texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
 		<color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/>
 	</panel>
 	<panel name="accordion_panel">
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_underpants.xml b/indra/newview/skins/default/xui/pl/panel_edit_underpants.xml
index 010d9b53d9..f2a9b10f17 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_underpants.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_underpants.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_underpants_panel">
 	<panel name="avatar_underpants_color_panel">
-		<texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać kolor"/>
+		<texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać kolor"/>
 		<color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/>
 	</panel>
 	<panel name="accordion_panel">
diff --git a/indra/newview/skins/default/xui/pl/panel_edit_undershirt.xml b/indra/newview/skins/default/xui/pl/panel_edit_undershirt.xml
index 63ae1215e0..7da1341e96 100644
--- a/indra/newview/skins/default/xui/pl/panel_edit_undershirt.xml
+++ b/indra/newview/skins/default/xui/pl/panel_edit_undershirt.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_undershirt_panel">
 	<panel name="avatar_undershirt_color_panel">
-		<texture_picker label="Materiał" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
+		<texture_picker label="Tekstura" name="Fabric" tool_tip="Kliknij aby wybrać teksturę"/>
 		<color_swatch label="Kolor/Barwa" name="Color/Tint" tool_tip="Kliknij aby wybrać kolor"/>
 	</panel>
 	<panel name="accordion_panel">
diff --git a/indra/newview/skins/default/xui/pl/panel_login.xml b/indra/newview/skins/default/xui/pl/panel_login.xml
index 30432c509d..81da94a659 100644
--- a/indra/newview/skins/default/xui/pl/panel_login.xml
+++ b/indra/newview/skins/default/xui/pl/panel_login.xml
@@ -1,8 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="panel_login">
-	<panel.string name="real_url">
-		http://secondlife.com/app/login/
-	</panel.string>
 	<panel.string name="forgot_password_url">
 		http://secondlife.com/account/request.php
 	</panel.string>
@@ -11,7 +8,7 @@
 			<text name="username_text">
 				Użytkownik:
 			</text>
-			<line_editor label="bobsmith12 lub Steller Sunshine" name="username_edit" tool_tip="Nazwę użytkownika wybierasz podczas rejestracji, np: like bobsmith12 lub Steller Sunshine"/>
+			<combo_box name="username_combo" tool_tip="Nazwę użytkownika wybierasz przy rejestracji, np. bobsmith12 lub Steller Sunshine"/>
 			<text name="password_text">
 				Hasło:
 			</text>
diff --git a/indra/newview/skins/default/xui/pl/panel_my_profile.xml b/indra/newview/skins/default/xui/pl/panel_my_profile.xml
index 6b0ba44bb4..cdc833241d 100644
--- a/indra/newview/skins/default/xui/pl/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/pl/panel_my_profile.xml
@@ -5,30 +5,27 @@
 	<string name="RegisterDateFormat">
 		[REG_DATE] ([AGE])
 	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
 	<layout_stack name="layout">
 		<layout_panel name="profile_stack">
 			<scroll_container name="profile_scroll">
 				<panel name="scroll_content_panel">
 					<panel name="second_life_image_panel">
-						<icon label="" name="2nd_life_edit_icon" tool_tip="Kliknij przycisk Edytuj profil by zmienić zdjęcie"/>
-						<text name="title_sl_descr_text" value="[SECOND_LIFE]:"/>
-					</panel>
-					<panel name="first_life_image_panel">
-						<icon label="" name="real_world_edit_icon" tool_tip="Kliknij przycisk Edytuj profil by zmienić zdjęcie"/>
-						<text name="title_rw_descr_text" value="Życie#1:"/>
-					</panel>
-					<text name="title_member_text" value="Urodziny:"/>
-					<text name="title_acc_status_text" value="Konto:"/>
-					<text name="title_partner_text" value="Partner:"/>
-					<panel name="partner_data_panel">
-						<name_box initial_value="(przetwarzanie)" name="partner_text"/>
+						<text name="display_name_descr_text">
+							Nazwa użytkownika
+						</text>
+						<text name="name_descr_text">
+							Wyświetlana nazwa
+						</text>
+						<button label="Profil" name="see_profile_btn" tool_tip="Zobacz profil tego awatara"/>
 					</panel>
-					<text name="title_groups_text" value="Grupy:"/>
 				</panel>
 			</scroll_container>
 		</layout_panel>
 	</layout_stack>
-	<panel name="profile_me_buttons_panel">
-		<button label="Edytuj profil" name="edit_profile_btn" tool_tip="Edytuj informacje o sobie"/>
-	</panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_people.xml b/indra/newview/skins/default/xui/pl/panel_people.xml
index fcb6b19635..1bd5b4a912 100644
--- a/indra/newview/skins/default/xui/pl/panel_people.xml
+++ b/indra/newview/skins/default/xui/pl/panel_people.xml
@@ -22,7 +22,7 @@ Chcesz spotkać ludzi? Spróbuj [secondlife:///app/worldmap Mapa Świata].
 	<tab_container name="tabs">
 		<panel label="W POBLIŻU" name="nearby_panel">
 			<panel label="bottom_panel" name="bottom_panel">
-				<button name="nearby_view_sort_btn" tool_tip="Opcje"/>
+				<menu_button name="nearby_view_sort_btn" tool_tip="Opcje"/>
 				<button name="add_friend_btn" tool_tip="Dodaj wybranego Rezydenta do znajomych"/>
 			</panel>
 		</panel>
@@ -34,27 +34,27 @@ Chcesz spotkać ludzi? Spróbuj [secondlife:///app/worldmap Mapa Świata].
 			<panel label="bottom_panel" name="bottom_panel">
 				<layout_stack name="bottom_panel">
 					<layout_panel name="options_gear_btn_panel">
-						<button name="friends_viewsort_btn" tool_tip="Pokaż opcje dodatkowe"/>
+						<menu_button name="friends_viewsort_btn" tool_tip="Pokaż opcje dodatkowe"/>
 					</layout_panel>
 					<layout_panel name="add_btn_panel">
 						<button name="add_btn" tool_tip="Dodaj wybranego Rezydenta do znajomych"/>
 					</layout_panel>
 					<layout_panel name="trash_btn_panel">
-						<dnd_button name="trash_btn" tool_tip="Usuń wybraną osobę ze swojej listy znajomych"/>
+						<dnd_button name="del_btn" tool_tip="Usuń zaznaczoną osobę ze swojej listy znajomych"/>
 					</layout_panel>
 				</layout_stack>
 			</panel>
 		</panel>
 		<panel label="GRUPY" name="groups_panel">
 			<panel label="bottom_panel" name="bottom_panel">
-				<button name="groups_viewsort_btn" tool_tip="Opcje"/>
+				<menu_button name="groups_viewsort_btn" tool_tip="Opcje"/>
 				<button name="plus_btn" tool_tip="Dołącz do grupy/Stwórz nową grupę"/>
 				<button name="activate_btn" tool_tip="Aktywuj wybraną grupę"/>
 			</panel>
 		</panel>
 		<panel label="OSTATNIE" name="recent_panel">
 			<panel label="bottom_panel" name="bottom_panel">
-				<button name="recent_viewsort_btn" tool_tip="Opcje"/>
+				<menu_button name="recent_viewsort_btn" tool_tip="Opcje"/>
 				<button name="add_friend_btn" tool_tip="Dodaj wybranego Rezydenta do znajomych"/>
 			</panel>
 		</panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_advanced.xml b/indra/newview/skins/default/xui/pl/panel_preferences_advanced.xml
index b267610d33..5e61f62691 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_advanced.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_advanced.xml
@@ -3,35 +3,16 @@
 	<panel.string name="aspect_ratio_text">
 		[NUM]:[DEN]
 	</panel.string>
-	<panel.string name="middle_mouse">
-		Środkowy klawisz myszki
-	</panel.string>
-	<slider label="Kąt widoku" name="camera_fov"/>
-	<slider label="Odległość" name="camera_offset_scale"/>
-	<text name="heading2">
-		Automatyczna pozycja dla:
-	</text>
-	<check_box label="Buduj/Edytuj" name="edit_camera_movement" tool_tip="Używaj automatycznego pozycjonowania kamery aktywując i deaktywując tryb edycji"/>
-	<check_box label="Wygląd" name="appearance_camera_movement" tool_tip="Używaj automatycznego pozycjonowania kamery podczas trybu edycji"/>
-	<check_box initial_value="prawda" label="Schowek" name="appearance_sidebar_positioning" tool_tip="Użyj automatycznego pozycjonowania kamery dla schowka"/>
-	<check_box label="Pokaż w trybie widoku panoramicznego" name="first_person_avatar_visible"/>
-	<check_box label="Aktywacja klawiszy strzałek do poruszania awatarem" name="arrow_keys_move_avatar_check"/>
-	<check_box label="Kliknij-kliknij-przytrzymaj, aby uruchomić" name="tap_tap_hold_to_run"/>
-	<check_box label="Poruszaj ustami awatara kiedy używana jest komunikacja głosowa" name="enable_lip_sync"/>
-	<check_box label="Czat chmurkowy" name="bubble_text_chat"/>
-	<slider label="Intensywność" name="bubble_chat_opacity"/>
-	<color_swatch name="background" tool_tip="Wybierz kolor czatu w chmurce"/>
 	<text name="UI Size:">
-		Rozmiar UI
+		rozmiar UI:
 	</text>
 	<check_box label="Pokaż błędy skryptu w:" name="show_script_errors"/>
 	<radio_group name="show_location">
 		<radio_item label="Czat Lokalny" name="0"/>
 		<radio_item label="Osobne okno:" name="1"/>
 	</radio_group>
-	<check_box label="Włącz/Wyłącz głos:" name="push_to_talk_toggle_check" tool_tip="Jeżeli jesteś w trybie mówienia, w celu aktywacji lub deaktywacji swojego mikrofonu wybierz i wyłącz przycisk Mów tylko raz. Jeżeli nie jesteś w trybie mówienia, mikrofon przesyła Twój głos tylko w momencie aktywacji pełnej przycisku Mów."/>
-	<line_editor label="Naciśnij Mów by rozpocząć komunikację głosową" name="modifier_combo"/>
-	<button label="Wybierz klawisz" name="set_voice_hotkey_button"/>
-	<button label="Środkowy przycisk myszki" name="set_voice_middlemouse_button" tool_tip="Zresetuj do środkowego przycisku myszy"/>
-	<button label="Inne urządzenia" name="joystick_setup_button"/>
+	<check_box label="Pozwól na wiele przeglądarek" name="allow_multiple_viewer_check"/>
+	<check_box label="Pokaż selekcję siatki przy logowaniu" name="show_grid_selection_check"/>
+	<check_box label="Pokaz menu Zaawansowane" name="show_advanced_menu_check"/>
+	<check_box label="Pokaz menu Rozwinięcie" name="show_develop_menu_check"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml b/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml
index 87894bb358..c7142c8419 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_chat.xml
@@ -8,44 +8,10 @@
 		<radio_item label="Średnia" name="radio2" value="1"/>
 		<radio_item label="Duża" name="radio3" value="2"/>
 	</radio_group>
-	<text name="font_colors">
-		Kolor czcionki:
-	</text>
-	<color_swatch label="Ty" name="user"/>
-	<text name="text_box1">
-		Ja
-	</text>
-	<color_swatch label="Inni" name="agent"/>
-	<text name="text_box2">
-		Inni
-	</text>
-	<color_swatch label="IM" name="im"/>
-	<text name="text_box3">
-		IM
-	</text>
-	<color_swatch label="System" name="system"/>
-	<text name="text_box4">
-		System
-	</text>
-	<color_swatch label="Błędy" name="script_error"/>
-	<text name="text_box5">
-		Błędy
-	</text>
-	<color_swatch label="Obiekty" name="objects"/>
-	<text name="text_box6">
-		Obiekty
-	</text>
-	<color_swatch label="Właściciel" name="owner"/>
-	<text name="text_box7">
-		Właściciel
-	</text>
-	<color_swatch label="Linki" name="links"/>
-	<text name="text_box9">
-		Linki
-	</text>
 	<check_box initial_value="true" label="Używaj animacji podczas pisania" name="play_typing_animation"/>
 	<check_box label="Wysyłaj wszystkie wiadomości (IM) na moją skrzynkę pocztową kiedy jestem niedostępny" name="send_im_to_email"/>
 	<check_box label="Zwykły tekst IM i historia czatu" name="plain_text_chat_history"/>
+	<check_box label="Czat chmurkowy" name="bubble_text_chat"/>
 	<text name="show_ims_in_label">
 		Pokaż wiadomości (IM) w:
 	</text>
@@ -56,6 +22,13 @@
 		<radio_item label="Osobne okna" name="radio" value="0"/>
 		<radio_item label="Etykiety" name="radio2" value="1"/>
 	</radio_group>
+	<text name="disable_toast_label">
+		Uaktywnij wyskakujące okienka rozpoczynających się rozmów:
+	</text>
+	<check_box label="Czat grupy" name="EnableGroupChatPopups" tool_tip="Zaznacz aby widzieć wyskakuące okienka kiedy czat grupy się pojawia"/>
+	<check_box label="Czat IM" name="EnableIMChatPopups" tool_tip="Zaznacz aby widzieć wyskakujące okienka kiedy IM się pojawia"/>
+	<spinner label="Czas widoczności czatu w pobliżu:" name="nearby_toasts_lifetime"/>
+	<spinner label="Czas znikania czatu w pobliżu:" name="nearby_toasts_fadingtime"/>
 	<check_box label="Używaj translatora podczas rozmowy (wspierany przez Google)" name="translate_chat_checkbox"/>
 	<text name="translate_language_text">
 		Przetłumacz czat na:
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_general.xml b/indra/newview/skins/default/xui/pl/panel_preferences_general.xml
index 00dc84dd7a..44dcb2112c 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_general.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_general.xml
@@ -48,13 +48,18 @@
 	<check_box label="Nazwy użytkowników" name="show_slids" tool_tip="Pokaż nazwy użytkowników, np. bobsmith123"/>
 	<check_box label="Wyświetl tytuł grupowy" name="show_all_title_checkbox1" tool_tip="Wyświetl tytuł grupowy np. oficer"/>
 	<check_box label="Zaznacz znajomych" name="show_friends" tool_tip="Zaznacz imiona swoich znajomych"/>
-	<text name="effects_color_textbox">
-		Kolor moich efektów:
+	<check_box label="Pokaż wyświetlane nazwy" name="display_names_check" tool_tip="Pokaż wyświetlane nazwy w czacie, IM, imionach, etc."/>
+	<check_box label="Uaktywnij wskazówki UI" name="viewer_hints_check"/>
+	<text name="inworld_typing_rg_label">
+		Wciśnięcie klawiszy liter:
 	</text>
+	<radio_group name="inworld_typing_preference">
+		<radio_item label="Włącza czat lokalny" name="radio_start_chat" value="1"/>
+		<radio_item label="Wpływ na ruch (WASD)" name="radio_move" value="0"/>
+	</radio_group>
 	<text name="title_afk_text">
 		Zasypiaj w czasie:
 	</text>
-	<color_swatch label="" name="effect_color_swatch" tool_tip="Selekcja koloru"/>
 	<combo_box label="Czas Trybu Oddalenia:" name="afk">
 		<combo_box.item label="2 minuty" name="item0"/>
 		<combo_box.item label="5 minut" name="item1"/>
@@ -62,7 +67,6 @@
 		<combo_box.item label="30 minut" name="item3"/>
 		<combo_box.item label="nigdy" name="item4"/>
 	</combo_box>
-	<check_box label="Pokaż wyświetlane nazwy" name="display_names_check" tool_tip="Pokaż wyświetlane nazwy w czacie, IM, imionach, etc."/>
 	<text name="text_box3">
 		Odpowiedź w trybie pracy:
 	</text>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml
index 1a9f59bbff..0f21aa9dd1 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_graphics1.xml
@@ -26,6 +26,7 @@
 		<text name="ShadersText">
 			Cieniowanie pixeli (shadery):
 		</text>
+		<check_box initial_value="prawda" label="Przeźroczystość wody" name="TransparentWater"/>
 		<check_box initial_value="true" label="Mapowanie wypukłości i połysk" name="BumpShiny"/>
 		<check_box initial_value="true" label="Podstawowe shadery" name="BasicShaders" tool_tip="Wyłączenie tej opcji może naprawić błędy niektórych sterowników graficznych."/>
 		<check_box initial_value="true" label="Shadery atmosfery" name="WindLightUseAtmosShaders"/>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/pl/panel_preferences_privacy.xml
index fd9cdd6ff0..a2f9b4176e 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_privacy.xml
@@ -7,19 +7,24 @@
 	<text name="cache_size_label_l">
 		(Miejsca, obrazy, przeglądarka internetowa, wyszukiwarka historii)
 	</text>
+	<check_box label="Pokaż mój profil w wynikach wyszukiwarki" name="online_searchresults"/>
 	<check_box label="Mój status online jest dostępny tylko dla znajomych i grup do których należę" name="online_visibility"/>
 	<check_box label="Możliwość wysyłania wiadomości prywatnej (IM) oraz rozmowy głosowej tylko dla znajomych i grup do których należę" name="voice_call_friends_only_check"/>
 	<check_box label="Wyłącz mikrofon po zakończeniu rozmowy głosowej" name="auto_disengage_mic_check"/>
-	<check_box label="Akceptuj ciasteczka" name="cookies_enabled"/>
+	<check_box label="Pokaż moje ulubione landmarki przy logowaniu (w rozwijanym menu &apos;Rozpocznij w&apos;)" name="favorites_on_login_check"/>
 	<text name="Logs:">
-		Logi:
+		Logi rozmów:
 	</text>
 	<check_box label="Zapisz logi rozmów ogólnych na moim komputerze" name="log_nearby_chat"/>
 	<check_box label="Zapisuj logi wiadomości prywatnych (IM) na moim komputerze" name="log_instant_messages"/>
-	<check_box label="Pokazuj czas" name="show_timestamps_check_im"/>
+	<check_box label="Dodaj znacznik czasu do każdej linii w logu rozmów." name="show_timestamps_check_im"/>
+	<check_box label="Dodaj znacznik czasu do nazwy pliku z zapisem rozmów." name="logfile_name_datestamp"/>
 	<text name="log_path_desc">
 		Lokalizacja zapisu:
 	</text>
 	<button label="Przeglądaj" label_selected="Przeglądaj" name="log_path_button"/>
 	<button label="Lista zablokowanych" name="block_list"/>
+	<text name="block_list_label">
+		(Ludzie i/lub obiekty zablokowane)
+	</text>
 </panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml b/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml
index 24e5c2b824..fa0a5981a8 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_setup.xml
@@ -1,13 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel label="Ustawienia" name="Input panel">
-	<text name="Mouselook:">
-		Widok panoramiczny:
-	</text>
-	<text name=" Mouse Sensitivity">
-		Czułość myszki
-	</text>
-	<slider name="mouse_sensitivity"/>
-	<check_box label="Zmień klawisze myszki" name="invert_mouse"/>
 	<text name="Network:">
 		Sieć:
 	</text>
@@ -47,4 +39,11 @@
 	</text>
 	<line_editor name="web_proxy_editor" tool_tip="Nazwa lub IP proxy, którego chcesz użyć"/>
 	<spinner label="Numer portu:" name="web_proxy_port"/>
+	<text name="Software updates:">
+		Aktualizaje oprogramowania:
+	</text>
+	<combo_box name="updater_service_combobox">
+		<combo_box.item label="Zainstauj automatycznie" name="Install_automatically"/>
+		<combo_box.item label="Pobierz i zainstaluj aktualizacje ręcznie" name="Install_manual"/>
+	</combo_box>
 </panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
index eaf9ae809b..c708cc0b99 100644
--- a/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_sound.xml
@@ -1,5 +1,8 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel label="Dźwięki" name="Preference Media panel">
+	<panel.string name="middle_mouse">
+		Środkowy przycisk myszy
+	</panel.string>
 	<slider label="Główny" name="System Volume"/>
 	<check_box initial_value="true" label="Wycisz podczas minimalizacji" name="mute_when_minimized"/>
 	<slider label="Interfejs" name="UI Volume"/>
@@ -23,6 +26,11 @@
 		<radio_item label="pozycji kamery" name="0"/>
 		<radio_item label="pozycji awatara" name="1"/>
 	</radio_group>
+	<check_box label="Poruszaj ustami awatara podczas mówienia" name="enable_lip_sync"/>
+	<check_box label="Włącz/wyłącz mikrofon kiedy naciskam:" name="push_to_talk_toggle_check" tool_tip="Kiedy aktywny jest tryb przełączania wciśnij i zwolnij przełącznik RAZ aby włączyć lub wyłączyć mikrofon. Kiedy tryb przełączania nie jest aktywny mikrofon nadaje głos tylko kiedy przełącznik jest wciśnięty."/>
+	<line_editor label="Przełącznik kliknij-aby-mówić" name="modifier_combo"/>
+	<button label="Ustaw klawisz" name="set_voice_hotkey_button"/>
+	<button name="set_voice_middlemouse_button" tool_tip="Zresetuj do środkowego przycisku myszy"/>
 	<button label="Wejściowe/Wyjściowe urządzenia" name="device_settings_btn"/>
 	<panel label="Ustawienia sprzętowe" name="device_settings_panel">
 		<panel.string name="default_text">
diff --git a/indra/newview/skins/default/xui/pl/panel_script_ed.xml b/indra/newview/skins/default/xui/pl/panel_script_ed.xml
index fa89a3f727..e18900af68 100644
--- a/indra/newview/skins/default/xui/pl/panel_script_ed.xml
+++ b/indra/newview/skins/default/xui/pl/panel_script_ed.xml
@@ -15,11 +15,6 @@
 	<panel.string name="Title">
 		Skrypt: [NAME]
 	</panel.string>
-	<text_editor name="Script Editor">
-		Ładowanie...
-	</text_editor>
-	<button label="Zapisz" label_selected="Zapisz" name="Save_btn"/>
-	<combo_box label="Wklej..." name="Insert..."/>
 	<menu_bar name="script_menu">
 		<menu label="Plik" name="File">
 			<menu_item_call label="Zapisz" name="Save"/>
@@ -40,4 +35,10 @@
 			<menu_item_call label="Pomoc..." name="Keyword Help..."/>
 		</menu>
 	</menu_bar>
+	<text_editor name="Script Editor">
+		Ładowanie...
+	</text_editor>
+	<combo_box label="Wklej..." name="Insert..."/>
+	<button label="Zapisz" label_selected="Zapisz" name="Save_btn"/>
+	<button label="Edytuj..." name="Edit_btn"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_status_bar.xml b/indra/newview/skins/default/xui/pl/panel_status_bar.xml
index 5e97dd8961..6aa0d27bb8 100644
--- a/indra/newview/skins/default/xui/pl/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/pl/panel_status_bar.xml
@@ -22,7 +22,7 @@
 		L$ [AMT]
 	</panel.string>
 	<panel name="balance_bg">
-		<text name="balance" tool_tip="Mój bilans" value="L$20"/>
+		<text name="balance" tool_tip="Kliknij aby odświeżyć bilans L$" value="L$20"/>
 		<button label="Kup L$" name="buyL" tool_tip="Kliknij aby kupić więcej L$"/>
 	</panel>
 	<text name="TimeText" tool_tip="Obecny czas (Pacyficzny)">
diff --git a/indra/newview/skins/default/xui/pl/strings.xml b/indra/newview/skins/default/xui/pl/strings.xml
index ea8bdd75b9..d1fb382a2d 100644
--- a/indra/newview/skins/default/xui/pl/strings.xml
+++ b/indra/newview/skins/default/xui/pl/strings.xml
@@ -1737,11 +1737,8 @@
 	<string name="InvOfferGaveYou">
 		oddany Tobie
 	</string>
-	<string name="InvOfferYouDecline">
-		Odrzucony przez Ciebie
-	</string>
-	<string name="InvOfferFrom">
-		od
+	<string name="InvOfferDecline">
+		Odrzucono [DESC] od &lt;nolink&gt;[NAME]&lt;/nolink&gt;.
 	</string>
 	<string name="GroupMoneyTotal">
 		Suma
diff --git a/indra/newview/skins/default/xui/pt/menu_login.xml b/indra/newview/skins/default/xui/pt/menu_login.xml
index a43ac271a9..3dff3d7c8a 100644
--- a/indra/newview/skins/default/xui/pt/menu_login.xml
+++ b/indra/newview/skins/default/xui/pt/menu_login.xml
@@ -16,7 +16,8 @@
 		<menu_item_call label="Definir tamanho da janela:" name="Set Window Size..."/>
 		<menu_item_call label="Mostrar TOS" name="TOS"/>
 		<menu_item_call label="Mostrar mensagem crítica" name="Critical"/>
-		<menu_item_call label="Teste de navegador web" name="Web Browser Test"/>
+		<menu_item_call label="Teste de mídia do navegador" name="Web Browser Test"/>
+		<menu_item_call label="Teste de conteúdo web" name="Web Content Floater Test"/>
 		<menu_item_check label="Exibir seletor da grade" name="Show Grid Picker"/>
 		<menu_item_call label="Exibir painel de notificações" name="Show Notifications Console"/>
 	</menu>
diff --git a/indra/newview/skins/default/xui/pt/menu_mini_map.xml b/indra/newview/skins/default/xui/pt/menu_mini_map.xml
index d742038e15..6a3fe55de5 100644
--- a/indra/newview/skins/default/xui/pt/menu_mini_map.xml
+++ b/indra/newview/skins/default/xui/pt/menu_mini_map.xml
@@ -3,6 +3,7 @@
 	<menu_item_call label="Zoom Perto" name="Zoom Close"/>
 	<menu_item_call label="Zoom Médio" name="Zoom Medium"/>
 	<menu_item_call label="Zoom Longe" name="Zoom Far"/>
+	<menu_item_call label="Zoom padrão" name="Zoom Default"/>
 	<menu_item_check label="Girar mapa" name="Rotate Map"/>
 	<menu_item_check label="Auto Center" name="Auto Center"/>
 	<menu_item_call label="Parar Acompanhamento" name="Stop Tracking"/>
diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml
index 95c37c53ca..3bbf2b66f2 100644
--- a/indra/newview/skins/default/xui/pt/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml
@@ -121,13 +121,15 @@
 			<menu_item_call label="Animação (L$[COST])..." name="Upload Animation"/>
 			<menu_item_call label="Volume (L$[COST] por arquivo)..." name="Bulk Upload"/>
 		</menu>
+		<menu_item_call label="Desfazer" name="Undo"/>
+		<menu_item_call label="Repetir" name="Redo"/>
 	</menu>
 	<menu label="Ajuda" name="Help">
 		<menu_item_call label="[SECOND_LIFE] Ajuda" name="Second Life Help"/>
+		<menu_item_check label="Ativar dicas" name="Enable Hints"/>
 		<menu_item_call label="Denunciar abuso" name="Report Abuse"/>
 		<menu_item_call label="Relatar bug" name="Report Bug"/>
 		<menu_item_call label="Sobre [APP_NAME]" name="About Second Life"/>
-		<menu_item_check label="Ativar dicas" name="Enable Hints"/>
 	</menu>
 	<menu label="Avançado" name="Advanced">
 		<menu_item_call label="Recarregar texturas" name="Rebake Texture"/>
@@ -268,7 +270,8 @@
 			<menu_item_call label="Dump Region Object Cache" name="Dump Region Object Cache"/>
 		</menu>
 		<menu label="Interface" name="UI">
-			<menu_item_call label="Teste de navegador web" name="Web Browser Test"/>
+			<menu_item_call label="Teste de mídia do navegador" name="Web Browser Test"/>
+			<menu_item_call label="Navegador de conteúdo web" name="Web Content Browser"/>
 			<menu_item_call label="Print Selected Object Info" name="Print Selected Object Info"/>
 			<menu_item_call label="Dados de memória" name="Memory Stats"/>
 			<menu_item_check label="Console de depuração de região" name="Region Debug Console"/>
diff --git a/indra/newview/skins/default/xui/pt/notifications.xml b/indra/newview/skins/default/xui/pt/notifications.xml
index dc38b740aa..5f09397ac5 100644
--- a/indra/newview/skins/default/xui/pt/notifications.xml
+++ b/indra/newview/skins/default/xui/pt/notifications.xml
@@ -108,6 +108,10 @@ Por favor, selecione apenas um objeto e tente novamente.
 		Residentes que não são amigos não veem que você decidiu ignorar ligações e MIs deles.
 		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
+	<notification name="FavoritesOnLogin">
+		Nota: Ao ativar esta opção, qualquer pessoa que utilizar este computador poderá ver a sua lista de lugares preferidos.
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
 	<notification name="GrantModifyRights">
 		Conceder direitos de modificação a outros residentes vai autorizá-los a mudar, apagar ou pegar TODOS os seus objetos. Seja MUITO cuidadoso ao conceder esta autorização.
 Deseja dar direitos de modificação a [NAME]?
@@ -938,7 +942,7 @@ Oferecer amizade para [NAME]?
 			<input name="message">
 				[DESC] (novo)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Cancelar"/>
 		</form>
 	</notification>
@@ -948,7 +952,7 @@ Oferecer amizade para [NAME]?
 			<input name="message">
 				[DESC] (novo)
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Cancelar"/>
 		</form>
 	</notification>
@@ -958,7 +962,7 @@ Oferecer amizade para [NAME]?
 			<input name="new_name">
 				[NAME]
 			</input>
-			<button name="Offer" text="OK"/>
+			<button name="OK" text="OK"/>
 			<button name="Cancel" text="Cancelar"/>
 		</form>
 	</notification>
@@ -1329,9 +1333,41 @@ Baixe e instale a versão mais recente do visualizador em
 http://secondlife.com/download.
 		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
-	<notification name="DownloadBackground">
-		Foi baixada uma nova versão do [APP_NAME]
-A nova versão será exibida quando o [APP_NAME] for reiniciado.
+	<notification name="FailedRequiredUpdateInstall">
+		Não foi possível instalar uma atualização necessária. 
+Não será possível acessar a sua conta até que você atualize o [APP_NAME].
+
+Baixe e instale a versão mais recente do visualizador em 
+http://secondlife.com/download.
+		<usetemplate name="okbutton" yestext="Sair"/>
+	</notification>
+	<notification name="UpdaterServiceNotRunning">
+		A instalação do Second Life requer uma atualização.
+
+Baixe a atualização em http://www.secondlife.com/downloads
+ou você pode instalar a instalação agora.
+		<usetemplate name="okcancelbuttons" notext="Sair do Second Life" yestext="Baixar e instalar agora"/>
+	</notification>
+	<notification name="DownloadBackgroundTip">
+		Baixamos uma atualização para a instalação do [APP_NAME].
+Versão [VERSION] [[RELEASE_NOTES_FULL_URL] sobre esta atualização]
+		<usetemplate name="okcancelbuttons" notext="Depois..." yestext="Instalar agora e reiniciar o [APP_NAME]"/>
+	</notification>
+	<notification name="DownloadBackgroundDialog">
+		Baixamos uma atualização para a instalação do [APP_NAME].
+Versão [VERSION] [[RELEASE_NOTES_FULL_URL] sobre esta atualização]
+		<usetemplate name="okcancelbuttons" notext="Depois..." yestext="Instalar agora e reiniciar o [APP_NAME]"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedVerboseDialog">
+		O software requer uma atualização que já foi baixada.
+Versão [VERSION]
+
+Para instalar a atualização, será preciso reiniciar o [APP_NAME].
+		<usetemplate name="okbutton" yestext="OK"/>
+	</notification>
+	<notification name="RequiredUpdateDownloadedDialog">
+		Para instalar a atualização, será preciso reiniciar o [APP_NAME].
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="DeedObjectToGroup">
 		Delegar este objeto causará ao grupo:
@@ -2198,14 +2234,6 @@ Selecione o residente da lista e clique em &apos;MI&apos; na parte de baixo do p
 	<notification name="NoContentToSearch">
 		Por favor, selecione ao menos um tipo de conteúdo para a busca (PG, Mature ou Adult).
 	</notification>
-	<notification name="GroupVote">
-		[NAME] propõe que você vote:
-[MESSAGE]
-		<form name="form">
-			<button name="VoteNow" text="Vote agora"/>
-			<button name="Later" text="Depois"/>
-		</form>
-	</notification>
 	<notification name="SystemMessage">
 		[MESSAGE]
 	</notification>
@@ -2763,9 +2791,7 @@ Avatar &apos;[NAME]&apos; sair do modo aparecer.
 	<notification name="NoConnect">
 		Detectamos um problema de conexão com [PROTOCOL] [HOSTID].
 Verifique a configuração da sua rede e firewall.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="NoVoiceConnect">
 		Estamos tendo problemas de conexão com o seu servidor de voz:
@@ -2774,9 +2800,7 @@ Verifique a configuração da sua rede e firewall.
 
 Talvez não seja possível se comunicar via voz.
 Verifique a configuração da sua rede e firewall.
-		<form name="form">
-			<button name="OK" text="OK"/>
-		</form>
+		<usetemplate name="okbutton" yestext="OK"/>
 	</notification>
 	<notification name="AvatarRezLeftNotification">
 		( [EXISTENCE] segundos de vida )
@@ -2811,6 +2835,9 @@ Silenciar todos?
 	<notification label="Explore o mundo" name="HintDestinationGuide">
 		O Guia de Destinos traz milhares de lugares novos para você explorar e conhecer. Selecione um lugar, clique em Teletransportar e comece suas descobertas.
 	</notification>
+	<notification label="Troque o visual" name="HintAvatarPicker">
+		Que tal mudar o visual? Clique o botão abaixo para ver Avatares diferentes.
+	</notification>
 	<notification label="Painel lateral" name="HintSidePanel">
 		Acesse rapidamente seu inventário, roupas, looks, perfis e mais no painel lateral.
 	</notification>
@@ -2820,6 +2847,12 @@ Silenciar todos?
 	<notification label="Nome de tela" name="HintDisplayName">
 		Defina seu nome de tela personalizável. O nome de tele é separado do seu nome de usuário, que não pode ser modificado. Você pode mudar a visualização dos nomes de outras pessoas nas suas preferências.
 	</notification>
+	<notification label="Movimentar" name="HintMoveArrows">
+		Para andar, use as setas do teclado. Para correr, pressione a seta para cima duas vezes.
+	</notification>
+	<notification label="Exibir" name="HintView">
+		Para mudar o ângulo de visualização, use os controles Órbita e Pan. Volte à visualização normal pressionando a tecla Escape ou começando a andar.
+	</notification>
 	<notification label="Inventário" name="HintInventory">
 		Você encontrará seus pertences no inventário.  Os itens mais novos também ficam na guia Itens recentes.
 	</notification>
@@ -2833,6 +2866,15 @@ Silenciar todos?
 			<button name="open" text="Abrir pop-up"/>
 		</form>
 	</notification>
+	<notification name="AuthRequest">
+		O site em &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; em &apos;[REALM]&apos; requer nome e senha.
+		<form name="form">
+			<input name="username" text="Nome de usuário"/>
+			<input name="password" text="Senha:"/>
+			<button name="ok" text="Enviar"/>
+			<button name="cancel" text="Cancelar"/>
+		</form>
+	</notification>
 	<global name="UnsupportedCPU">
 		- A velocidade da sua CPU não suporta os requisitos mínimos exigidos.
 	</global>
diff --git a/indra/newview/skins/default/xui/pt/panel_avatar_list_item.xml b/indra/newview/skins/default/xui/pt/panel_avatar_list_item.xml
index ca67125c65..b444593af8 100644
--- a/indra/newview/skins/default/xui/pt/panel_avatar_list_item.xml
+++ b/indra/newview/skins/default/xui/pt/panel_avatar_list_item.xml
@@ -21,7 +21,7 @@
 	<string name="FormatYears">
 		[COUNT]anos
 	</string>
-	<text name="avatar_name" value="Desconhecido"/>
+	<text name="avatar_name" value="(carregando)"/>
 	<icon name="permission_edit_theirs_icon" tool_tip="Você pode editar os pertences deste amigo"/>
 	<icon name="permission_edit_mine_icon" tool_tip="Este amigo pode editar, excluir ou pegar seus pertences"/>
 	<icon name="permission_map_icon" tool_tip="Este amigo pode localizar você no mapa"/>
diff --git a/indra/newview/skins/default/xui/pt/panel_edit_alpha.xml b/indra/newview/skins/default/xui/pt/panel_edit_alpha.xml
index f8be9daf1b..b274945dbd 100644
--- a/indra/newview/skins/default/xui/pt/panel_edit_alpha.xml
+++ b/indra/newview/skins/default/xui/pt/panel_edit_alpha.xml
@@ -1,10 +1,12 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <panel name="edit_alpha_panel">
-	<panel name="avatar_alpha_color_panel">
-		<texture_picker label="Alpha inferior" name="Lower Alpha" tool_tip="Selecionar imagem"/>
-		<texture_picker label="Alpha de cima" name="Upper Alpha" tool_tip="Selecionar imagem"/>
-		<texture_picker label="Cabeça Alpha" name="Head Alpha" tool_tip="Selecionar imagem"/>
-		<texture_picker label="Olhos Alpha" name="Eye Alpha" tool_tip="Selecionar imagem"/>
-		<texture_picker label="Cabelo alpha" name="Hair Alpha" tool_tip="Selecionar imagem"/>
-	</panel>
+	<scroll_container name="avatar_alpha_color_panel_scroll">
+		<panel name="avatar_alpha_color_panel">
+			<texture_picker label="Alpha inferior" name="Lower Alpha" tool_tip="Selecionar imagem"/>
+			<texture_picker label="Alpha de cima" name="Upper Alpha" tool_tip="Selecionar imagem"/>
+			<texture_picker label="Cabeça Alpha" name="Head Alpha" tool_tip="Selecionar imagem"/>
+			<texture_picker label="Olhos Alpha" name="Eye Alpha" tool_tip="Selecionar imagem"/>
+			<texture_picker label="Cabelo alpha" name="Hair Alpha" tool_tip="Selecionar imagem"/>
+		</panel>
+	</scroll_container>
 </panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_login.xml b/indra/newview/skins/default/xui/pt/panel_login.xml
index 9c8650e75e..42df93fd86 100644
--- a/indra/newview/skins/default/xui/pt/panel_login.xml
+++ b/indra/newview/skins/default/xui/pt/panel_login.xml
@@ -11,7 +11,7 @@
 			<text name="username_text">
 				Nome de usuário:
 			</text>
-			<line_editor label="zecazc12 or Magia Solar" name="username_edit" tool_tip="O nome de usuário que você escolheu ao fazer seu cadastro, como zecazc12 or Magia Solar"/>
+			<combo_box name="username_combo" tool_tip="O nome de usuário que você escolheu ao fazer seu cadastro, como zecazc12 or Magia Solar"/>
 			<text name="password_text">
 				Senha:
 			</text>
diff --git a/indra/newview/skins/default/xui/pt/panel_my_profile.xml b/indra/newview/skins/default/xui/pt/panel_my_profile.xml
index 1a28f61c2d..aa15a2445d 100644
--- a/indra/newview/skins/default/xui/pt/panel_my_profile.xml
+++ b/indra/newview/skins/default/xui/pt/panel_my_profile.xml
@@ -5,30 +5,27 @@
 	<string name="RegisterDateFormat">
 		[REG_DATE] ([AGE])
 	</string>
+	<string name="name_text_args">
+		[NAME]
+	</string>
+	<string name="display_name_text_args">
+		[DISPLAY_NAME]
+	</string>
 	<layout_stack name="layout">
 		<layout_panel name="profile_stack">
 			<scroll_container name="profile_scroll">
 				<panel name="scroll_content_panel">
 					<panel name="second_life_image_panel">
-						<icon label="" name="2nd_life_edit_icon" tool_tip="Clique no botão Editar para trocar a imagem"/>
-						<text name="title_sl_descr_text" value="[SECOND_LIFE]:"/>
-					</panel>
-					<panel name="first_life_image_panel">
-						<icon label="" name="real_world_edit_icon" tool_tip="Clique no botão Editar para trocar a imagem"/>
-						<text name="title_rw_descr_text" value="Mundo real:"/>
-					</panel>
-					<text name="title_member_text" value="Residente desde:"/>
-					<text name="title_acc_status_text" value="Conta:"/>
-					<text name="title_partner_text" value="Parceiro(a):"/>
-					<panel name="partner_data_panel">
-						<name_box initial_value="(pesquisando)" name="partner_text"/>
+						<text name="display_name_descr_text">
+							Nome de usuário
+						</text>
+						<text name="name_descr_text">
+							Nome de tela
+						</text>
+						<button label="Perfil" name="see_profile_btn" tool_tip="Ver o perfil deste avatar"/>
 					</panel>
-					<text name="title_groups_text" value="Grupos:"/>
 				</panel>
 			</scroll_container>
 		</layout_panel>
 	</layout_stack>
-	<panel name="profile_me_buttons_panel">
-		<button label="Editar perfil" name="edit_profile_btn" tool_tip="Editar dados pessoais"/>
-	</panel>
 </panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_notify_textbox.xml b/indra/newview/skins/default/xui/pt/panel_notify_textbox.xml
index d9614fe76b..dcd9ba1815 100644
--- a/indra/newview/skins/default/xui/pt/panel_notify_textbox.xml
+++ b/indra/newview/skins/default/xui/pt/panel_notify_textbox.xml
@@ -3,8 +3,9 @@
 	<string name="message_max_lines_count" value="7"/>
 	<panel label="info_panel" name="info_panel">
 		<text_editor name="message" value="mensagem"/>
-		parse_urls=&quot;false&quot;
+	</panel>
+	<panel label="control_panel" name="control_panel">
 		<button label="Enviar" name="btn_submit"/>
+		<button label="Ignorar" name="ignore_btn"/>
 	</panel>
-	<panel label="control_panel" name="control_panel"/>
 </panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_colors.xml b/indra/newview/skins/default/xui/pt/panel_preferences_colors.xml
index 3ca9da06c9..5f2f341e3f 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_colors.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_colors.xml
@@ -29,10 +29,10 @@
 		URLs
 	</text>
 	<text name="bubble_chat">
-		Fundo do balão:
+		Cor de fundo do nome (e do balão do bate-papo):
 	</text>
-	<color_swatch name="background" tool_tip="Escolha a cor do balão de bate-papo"/>
-	<slider label="Opacidade:" name="bubble_chat_opacity"/>
+	<color_swatch name="background" tool_tip="Selecionar cor do nome"/>
+	<slider label="Opacidade:" name="bubble_chat_opacity" tool_tip="Selecionar cor do nome"/>
 	<text name="floater_opacity">
 		Opacidade:
 	</text>
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_privacy.xml b/indra/newview/skins/default/xui/pt/panel_preferences_privacy.xml
index 5545dcda38..d7fb585e35 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_privacy.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_privacy.xml
@@ -7,9 +7,11 @@
 	<text name="cache_size_label_l">
 		(Locações, imagens, web, histórico de busca)
 	</text>
+	<check_box label="Mostrar nos resultados de busca" name="online_searchresults"/>
 	<check_box label="Apenas amigos e grupos sabem que estou online" name="online_visibility"/>
 	<check_box label="Apenas amigos e grupos podem me chamar ou enviar MI" name="voice_call_friends_only_check"/>
 	<check_box label="Desligar o microfone quando terminar chamadas" name="auto_disengage_mic_check"/>
+	<check_box label="Mostrar meus marcos preferidos na página de login (menu &apos;Começar em&apos;:)" name="favorites_on_login_check"/>
 	<text name="Logs:">
 		Registro de bate-papos:
 	</text>
diff --git a/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml b/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml
index 0c6fb68140..d8d4a8fc1c 100644
--- a/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml
+++ b/indra/newview/skins/default/xui/pt/panel_preferences_setup.xml
@@ -39,5 +39,11 @@
 	</text>
 	<line_editor name="web_proxy_editor" tool_tip="O nome ou endereço IP do proxy da sua preferência"/>
 	<spinner label="Porta:" name="web_proxy_port"/>
-	<check_box initial_value="verdadeiro" label="Baixar e instalar atualizações [APP_NAME] automaticamente" name="updater_service_active"/>
+	<text name="Software updates:">
+		Atualizações de software:
+	</text>
+	<combo_box name="updater_service_combobox">
+		<combo_box.item label="Instalar automaticamente" name="Install_automatically"/>
+		<combo_box.item label="Baixar e instalar atualizações manualmente" name="Install_manual"/>
+	</combo_box>
 </panel>
diff --git a/indra/newview/skins/default/xui/pt/panel_status_bar.xml b/indra/newview/skins/default/xui/pt/panel_status_bar.xml
index fbbcf0d1be..f7890ae57d 100644
--- a/indra/newview/skins/default/xui/pt/panel_status_bar.xml
+++ b/indra/newview/skins/default/xui/pt/panel_status_bar.xml
@@ -22,7 +22,7 @@
 		L$ [AMT]
 	</panel.string>
 	<panel name="balance_bg">
-		<text name="balance" tool_tip="Meu saldo" value="L$20"/>
+		<text name="balance" tool_tip="Atualizar saldo de L$" value="L$20"/>
 		<button label="Comprar L$" name="buyL" tool_tip="Comprar mais L$"/>
 	</panel>
 	<text name="TimeText" tool_tip="Hora atual (Pacífico)">
-- 
cgit v1.2.3


From b429ff8ec3e1aebc60ff7f4d3376cfc8b9f2e669 Mon Sep 17 00:00:00 2001
From: Eli Linden <eli@lindenlab.com>
Date: Fri, 21 Jan 2011 16:11:25 -0800
Subject: INTL-20,CT-635 WIP DE,FR,ES,PT,PL translation (new files) for Viewer
 2.5

---
 .../skins/default/xui/de/floater_web_content.xml   | 14 ++++++++
 .../skins/default/xui/es/floater_web_content.xml   | 14 ++++++++
 .../skins/default/xui/fr/floater_web_content.xml   | 14 ++++++++
 .../xui/pl/floater_region_debug_console.xml        |  2 ++
 .../skins/default/xui/pl/floater_web_content.xml   | 14 ++++++++
 .../skins/default/xui/pl/panel_notify_textbox.xml  | 11 ++++++
 .../default/xui/pl/panel_preferences_colors.xml    | 41 ++++++++++++++++++++++
 .../default/xui/pl/panel_preferences_move.xml      | 24 +++++++++++++
 .../skins/default/xui/pt/floater_web_content.xml   | 14 ++++++++
 9 files changed, 148 insertions(+)
 create mode 100644 indra/newview/skins/default/xui/de/floater_web_content.xml
 create mode 100644 indra/newview/skins/default/xui/es/floater_web_content.xml
 create mode 100644 indra/newview/skins/default/xui/fr/floater_web_content.xml
 create mode 100644 indra/newview/skins/default/xui/pl/floater_region_debug_console.xml
 create mode 100644 indra/newview/skins/default/xui/pl/floater_web_content.xml
 create mode 100644 indra/newview/skins/default/xui/pl/panel_notify_textbox.xml
 create mode 100644 indra/newview/skins/default/xui/pl/panel_preferences_colors.xml
 create mode 100644 indra/newview/skins/default/xui/pl/panel_preferences_move.xml
 create mode 100644 indra/newview/skins/default/xui/pt/floater_web_content.xml

diff --git a/indra/newview/skins/default/xui/de/floater_web_content.xml b/indra/newview/skins/default/xui/de/floater_web_content.xml
new file mode 100644
index 0000000000..6ab119eeab
--- /dev/null
+++ b/indra/newview/skins/default/xui/de/floater_web_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_web_content" title="">
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button name="back" tool_tip="Rückwärts"/>
+			<button name="forward" tool_tip="Vorwärts"/>
+			<button name="stop" tool_tip="Navigation stoppen"/>
+			<button name="reload" tool_tip="Seite neu laden"/>
+			<combo_box name="address" tool_tip="URL hier eingeben"/>
+			<icon name="media_secure_lock_flag" tool_tip="Sicheres Browsen"/>
+			<button name="popexternal" tool_tip="Aktuelle URL im Desktop-Browser öffnen"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/es/floater_web_content.xml b/indra/newview/skins/default/xui/es/floater_web_content.xml
new file mode 100644
index 0000000000..5e02fad2dd
--- /dev/null
+++ b/indra/newview/skins/default/xui/es/floater_web_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_web_content" title="">
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button name="back" tool_tip="Navegar hacia atrás"/>
+			<button name="forward" tool_tip="Navegar hacia adelante"/>
+			<button name="stop" tool_tip="Detener la navegación"/>
+			<button name="reload" tool_tip="Recargar página"/>
+			<combo_box name="address" tool_tip="Introducir URL aquí"/>
+			<icon name="media_secure_lock_flag" tool_tip="Navegación segura"/>
+			<button name="popexternal" tool_tip="Abrir URL actual en tu navegador de escritorio"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/fr/floater_web_content.xml b/indra/newview/skins/default/xui/fr/floater_web_content.xml
new file mode 100644
index 0000000000..65dfafe760
--- /dev/null
+++ b/indra/newview/skins/default/xui/fr/floater_web_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_web_content" title="">
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button name="back" tool_tip="Précédente"/>
+			<button name="forward" tool_tip="Suivante"/>
+			<button name="stop" tool_tip="Arrêt de la navigation"/>
+			<button name="reload" tool_tip="Recharger la page"/>
+			<combo_box name="address" tool_tip="Entrer une URL ici"/>
+			<icon name="media_secure_lock_flag" tool_tip="Navigation sécurisée"/>
+			<button name="popexternal" tool_tip="Ouvrir l&apos;URL actuelle dans votre navigateur de bureau"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/pl/floater_region_debug_console.xml b/indra/newview/skins/default/xui/pl/floater_region_debug_console.xml
new file mode 100644
index 0000000000..ce1f3c0ac7
--- /dev/null
+++ b/indra/newview/skins/default/xui/pl/floater_region_debug_console.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="region_debug_console" title="Debugowanie regionu"/>
diff --git a/indra/newview/skins/default/xui/pl/floater_web_content.xml b/indra/newview/skins/default/xui/pl/floater_web_content.xml
new file mode 100644
index 0000000000..4cc8d0b27b
--- /dev/null
+++ b/indra/newview/skins/default/xui/pl/floater_web_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_web_content" title="">
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button name="back" tool_tip="Do tyłu"/>
+			<button name="forward" tool_tip="Do przodu"/>
+			<button name="stop" tool_tip="Zatrzymaj"/>
+			<button name="reload" tool_tip="Odśwież stronę"/>
+			<combo_box name="address" tool_tip="Wprowadź URL tutaj"/>
+			<icon name="media_secure_lock_flag" tool_tip="Funkcja bezpiecznego przeglądania (Secured Browsing)"/>
+			<button name="popexternal" tool_tip="Otwórz bieżący URL w zewnętrznej przeglądarce"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
diff --git a/indra/newview/skins/default/xui/pl/panel_notify_textbox.xml b/indra/newview/skins/default/xui/pl/panel_notify_textbox.xml
new file mode 100644
index 0000000000..e1668e1ef1
--- /dev/null
+++ b/indra/newview/skins/default/xui/pl/panel_notify_textbox.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="instant_message" name="panel_notify_textbox">
+	<string name="message_max_lines_count" value="7"/>
+	<panel label="info_panel" name="info_panel">
+		<text_editor name="message" value="wiadomość"/>
+	</panel>
+	<panel label="control_panel" name="control_panel">
+		<button label="Wyślij" name="btn_submit"/>
+		<button label="Ignoruj" name="ignore_btn"/>
+	</panel>
+</panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_colors.xml b/indra/newview/skins/default/xui/pl/panel_preferences_colors.xml
new file mode 100644
index 0000000000..3d1160882b
--- /dev/null
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_colors.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Kolory" name="colors_panel">
+	<text name="effects_color_textbox">
+		Moje efekty (selection beam):
+	</text>
+	<color_swatch name="effect_color_swatch" tool_tip="Kliknij aby wybrać kolor"/>
+	<text name="font_colors">
+		Kolor czcionki czatu:
+	</text>
+	<text name="text_box1">
+		Ja
+	</text>
+	<text name="text_box2">
+		Inni
+	</text>
+	<text name="text_box3">
+		Obiekty
+	</text>
+	<text name="text_box4">
+		System
+	</text>
+	<text name="text_box5">
+		Błędy
+	</text>
+	<text name="text_box7">
+		Właściciel
+	</text>
+	<text name="text_box9">
+		URL
+	</text>
+	<text name="bubble_chat">
+		Kolor tła taga (dotyczy również czatu chmurkowego):
+	</text>
+	<color_swatch name="background" tool_tip="Wybierz kolor taga"/>
+	<slider label="Przeźroczystość:" name="bubble_chat_opacity" tool_tip="Wybierz przeźroczystość taga"/>
+	<text name="floater_opacity">
+		Przeźroczystość:
+	</text>
+	<slider label="Aktywny:" name="active"/>
+	<slider label="Niekatywny:" name="inactive"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pl/panel_preferences_move.xml b/indra/newview/skins/default/xui/pl/panel_preferences_move.xml
new file mode 100644
index 0000000000..4c2df2c1f3
--- /dev/null
+++ b/indra/newview/skins/default/xui/pl/panel_preferences_move.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel label="Ruch" name="move_panel">
+	<slider label="Kąt widoku kamery" name="camera_fov"/>
+	<slider label="Dystans kamery" name="camera_offset_scale"/>
+	<text name="heading2">
+		Automatyczna pozycja dla:
+	</text>
+	<check_box label="Budowanie/Edycja" name="edit_camera_movement" tool_tip="Używaj automatycznego pozycjonowania kamery podczas włączania i wyłączania trybu edycji."/>
+	<check_box label="Wygląd" name="appearance_camera_movement" tool_tip="Używaj automatycznego pozycjonowania kamery podczas trybu edycji"/>
+	<check_box initial_value="prawda" label="Schowek" name="appearance_sidebar_positioning" tool_tip="Używaj automatycznego pozycjonowania kamery dla panelu bocznego"/>
+	<check_box label="Awatar widoczny w trybie panoramicznym" name="first_person_avatar_visible"/>
+	<text name=" Mouse Sensitivity">
+		Czułość myszki w widoku panoramicznym:
+	</text>
+	<check_box label="Zmień klawisze myszki" name="invert_mouse"/>
+	<check_box label="Przyciski ze strzałkami zawsze poruszają awatarem" name="arrow_keys_move_avatar_check"/>
+	<check_box label="Wciśnij-wciśnij-przytrzymaj aby biec" name="tap_tap_hold_to_run"/>
+	<check_box label="Podwójnie kliknij aby:" name="double_click_chkbox"/>
+	<radio_group name="double_click_action">
+		<radio_item label="teleportować się" name="radio_teleport"/>
+		<radio_item label="włączyć auto-pilota" name="radio_autopilot"/>
+	</radio_group>
+	<button label="Inne urządzenia" name="joystick_setup_button"/>
+</panel>
diff --git a/indra/newview/skins/default/xui/pt/floater_web_content.xml b/indra/newview/skins/default/xui/pt/floater_web_content.xml
new file mode 100644
index 0000000000..5101579c6f
--- /dev/null
+++ b/indra/newview/skins/default/xui/pt/floater_web_content.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_web_content" title="">
+	<layout_stack name="stack1">
+		<layout_panel name="nav_controls">
+			<button name="back" tool_tip="Navegar para trás"/>
+			<button name="forward" tool_tip="Navegar para frente"/>
+			<button name="stop" tool_tip="Parar a navegação"/>
+			<button name="reload" tool_tip="Recarregar página"/>
+			<combo_box name="address" tool_tip="Digite a URL aqui"/>
+			<icon name="media_secure_lock_flag" tool_tip="Navegação segura"/>
+			<button name="popexternal" tool_tip="Abrir a URL atual no navegador do seu computador"/>
+		</layout_panel>
+	</layout_stack>
+</floater>
-- 
cgit v1.2.3


From 295536ae98cb88bfa551ac73ae2e19a8c2ddfc88 Mon Sep 17 00:00:00 2001
From: Aleric Inglewood <Aleric.Inglewood@gmail.com>
Date: Mon, 24 Jan 2011 09:35:41 -0500
Subject: VWR-24321: fix validation of textures that start with 00

---
 doc/contributions.txt            | 1 +
 indra/newview/lltexturecache.cpp | 2 +-
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 5255acc041..4e91bbdd36 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -83,6 +83,7 @@ Aleric Inglewood
 	VWR-24315
 	VWR-24317
 	VWR-24320
+    VWR-24321
  	VWR-24354
 	VWR-24519
 	SNOW-84
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 92080d1fd7..6ddbdbf783 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -1592,7 +1592,7 @@ void LLTextureCache::purgeTextures(bool validate)
 	if (validate)
 	{
 		validate_idx = gSavedSettings.getU32("CacheValidateCounter");
-		U32 next_idx = (++validate_idx) % 256;
+		U32 next_idx = (validate_idx + 1) % 256;
 		gSavedSettings.setU32("CacheValidateCounter", next_idx);
 		LL_DEBUGS("TextureCache") << "TEXTURE CACHE: Validating: " << validate_idx << LL_ENDL;
 	}
-- 
cgit v1.2.3


From 14042f631de03b0b6730fb8fdb89e7abc8202f4a Mon Sep 17 00:00:00 2001
From: "Andrew A. de Laix" <alain@lindenlab.com>
Date: Mon, 24 Jan 2011 10:54:08 -0800
Subject: fix CHOP-369: catch case of synchronous download failure.

---
 indra/viewer_components/updater/llupdaterservice.cpp | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp
index ea242f45cd..20534fdf3a 100644
--- a/indra/viewer_components/updater/llupdaterservice.cpp
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -375,7 +375,11 @@ void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion,
 	mIsDownloading = true;
 	mUpdateDownloader.download(uri, hash, newVersion, false);
 	
-	setState(LLUpdaterService::DOWNLOADING);
+	if(getState() != LLUpdaterService::FAILURE) {
+		setState(LLUpdaterService::DOWNLOADING);
+	} else {
+		; // Download failed snynchronously; we are done.
+	}
 }
 
 void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,
@@ -387,7 +391,11 @@ void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,
 	mIsDownloading = true;
 	mUpdateDownloader.download(uri, hash, newVersion, true);
 	
-	setState(LLUpdaterService::DOWNLOADING);
+	if(getState() != LLUpdaterService::FAILURE) {
+		setState(LLUpdaterService::DOWNLOADING);
+	} else {
+		; // Download failed snynchronously; we are done.
+	}
 }
 
 void LLUpdaterServiceImpl::upToDate(void)
-- 
cgit v1.2.3


From 5322021746582195df6b7ad5843a7da09e617917 Mon Sep 17 00:00:00 2001
From: Jonathan Yap <none@none>
Date: Mon, 24 Jan 2011 16:22:03 -0500
Subject: STORM-845 Icon for nearby chat and nearby voice now is a down arrow
 when floater is open

---
 doc/contributions.txt                                        |  1 +
 indra/newview/skins/default/textures/textures.xml            |  1 +
 indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml |  4 ++--
 indra/newview/skins/default/xui/en/widgets/talk_button.xml   | 10 +++++-----
 4 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 5255acc041..83d7e573a8 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -386,6 +386,7 @@ Jonathan Yap
 	VWR-17801
 	VWR-24347
 	STORM-844
+	STORM-845
 Kage Pixel
 	VWR-11
 Ken March
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 2c00120177..7b3cc7bdfa 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -107,6 +107,7 @@ with the same filename but different name
   <texture name="ComboButton_Selected" file_name="widgets/ComboButton_Selected.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
   <texture name="ComboButton_UpSelected" file_name="widgets/ComboButton_UpSelected.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
   <texture name="ComboButton_Up_On_Selected" file_name="widgets/ComboButton_Up_On_Selected.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
+  <texture name="ComboButton_On" file_name="widgets/ComboButton_On.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
   <texture name="ComboButton_Off" file_name="widgets/ComboButton_Off.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
   <texture name="ComboButton_UpOff" file_name="widgets/ComboButton_UpOff.png" preload="true" scale.left="2" scale.top="19" scale.right="18" scale.bottom="2" />
   <texture name="Container" file_name="containers/Container.png" preload="false" />
diff --git a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml
index 5871eb0654..21c627cdfb 100644
--- a/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml
+++ b/indra/newview/skins/default/xui/en/panel_nearby_chat_bar.xml
@@ -45,9 +45,9 @@
      left_pad="4"
      image_disabled="ComboButton_UpOff"
      image_unselected="ComboButton_UpOff"
-     image_selected="ComboButton_Up_On_Selected"
+     image_selected="ComboButton_On"
      image_pressed="ComboButton_UpSelected"
-     image_pressed_selected="ComboButton_Up_On_Selected"
+     image_pressed_selected="ComboButton_Selected"
      height="23"
      name="show_nearby_chat"
      tool_tip="Shows/hides nearby chat log">
diff --git a/indra/newview/skins/default/xui/en/widgets/talk_button.xml b/indra/newview/skins/default/xui/en/widgets/talk_button.xml
index a7e271a1ff..d792e9f29c 100644
--- a/indra/newview/skins/default/xui/en/widgets/talk_button.xml
+++ b/indra/newview/skins/default/xui/en/widgets/talk_button.xml
@@ -23,11 +23,11 @@
     bottom="0"
     tab_stop="false"
     is_toggle="true"
-                 image_selected="SegmentedBtn_Right_Selected_Press"
-                 image_unselected="SegmentedBtn_Right_Off"
-		 image_pressed="SegmentedBtn_Right_Press"
-		 image_pressed_selected="SegmentedBtn_Right_Selected_Press"
-		 image_overlay="Arrow_Small_Up"
+    image_disabled="ComboButton_UpOff"
+    image_unselected="ComboButton_UpOff"
+    image_selected="ComboButton_On"
+    image_pressed="ComboButton_UpSelected"
+    image_pressed_selected="ComboButton_Selected"
     />
   <monitor
     follows="right" 
-- 
cgit v1.2.3


From 2a14079563ce323452a8088cca994e4f5c0edcd4 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Mon, 24 Jan 2011 15:50:46 -0700
Subject: fix for SH-445: debug settings -> "CacheNumberOfRegionsForObjects"
 does not limit the number of object cache files

---
 indra/newview/app_settings/settings.xml |  2 +-
 indra/newview/llvocache.cpp             | 20 +++++++++++++-------
 indra/newview/llvocache.h               |  2 +-
 3 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 819808ec40..ced46c7294 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1179,7 +1179,7 @@
       <key>Type</key>
       <string>U32</string>
       <key>Value</key>
-      <integer>20000</integer>
+      <integer>128</integer>
     </map>
     <key>CacheSize</key>
     <map>
diff --git a/indra/newview/llvocache.cpp b/indra/newview/llvocache.cpp
index 1e2736f7d9..b3312db4a0 100644
--- a/indra/newview/llvocache.cpp
+++ b/indra/newview/llvocache.cpp
@@ -517,6 +517,11 @@ void LLVOCache::readCacheHeader()
 	{
 		removeCache() ; //failed to read header, clear the cache
 	}
+	else if(mNumEntries >= mCacheSize)
+	{
+		purgeEntries(mCacheSize) ;
+	}
+
 	return ;
 }
 
@@ -644,9 +649,9 @@ void LLVOCache::readFromCache(U64 handle, const LLUUID& id, LLVOCacheEntry::voca
 	return ;
 }
 	
-void LLVOCache::purgeEntries()
+void LLVOCache::purgeEntries(U32 size)
 {
-	while(mHeaderEntryQueue.size() >= mCacheSize)
+	while(mHeaderEntryQueue.size() >= size)
 	{
 		header_entry_queue_t::iterator iter = mHeaderEntryQueue.begin() ;
 		HeaderEntryInfo* entry = *iter ;			
@@ -671,16 +676,17 @@ void LLVOCache::writeToCache(U64 handle, const LLUUID& id, const LLVOCacheEntry:
 	{
 		llwarns << "Not writing cache for handle " << handle << "): Cache is currently in read-only mode." << llendl;
 		return ;
-	}
-	if(mNumEntries >= mCacheSize)
-	{
-		purgeEntries() ;
-	}
+	}	
 
 	HeaderEntryInfo* entry;
 	handle_entry_map_t::iterator iter = mHandleEntryMap.find(handle) ;
 	if(iter == mHandleEntryMap.end()) //new entry
 	{				
+		if(mNumEntries >= mCacheSize - 1)
+		{
+			purgeEntries(mCacheSize - 1) ;
+		}
+
 		entry = new HeaderEntryInfo();
 		entry->mHandle = handle ;
 		entry->mTime = time(NULL) ;
diff --git a/indra/newview/llvocache.h b/indra/newview/llvocache.h
index 1070fcaae9..14e3b4c793 100644
--- a/indra/newview/llvocache.h
+++ b/indra/newview/llvocache.h
@@ -130,7 +130,7 @@ private:
 	void clearCacheInMemory();
 	void removeCache() ;
 	void removeEntry(HeaderEntryInfo* entry) ;
-	void purgeEntries();
+	void purgeEntries(U32 size);
 	BOOL updateEntry(const HeaderEntryInfo* entry);
 	
 private:
-- 
cgit v1.2.3


From 9fa947ef741f6e63be1994e83fcf8f182e7eebed Mon Sep 17 00:00:00 2001
From: "Andrew A. de Laix" <alain@lindenlab.com>
Date: Mon, 24 Jan 2011 14:58:10 -0800
Subject: a less brain dead fix for CHOP-369

---
 indra/viewer_components/updater/llupdaterservice.cpp | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/indra/viewer_components/updater/llupdaterservice.cpp b/indra/viewer_components/updater/llupdaterservice.cpp
index 20534fdf3a..1888f191e2 100644
--- a/indra/viewer_components/updater/llupdaterservice.cpp
+++ b/indra/viewer_components/updater/llupdaterservice.cpp
@@ -373,13 +373,8 @@ void LLUpdaterServiceImpl::optionalUpdate(std::string const & newVersion,
 	stopTimer();
 	mNewVersion = newVersion;
 	mIsDownloading = true;
+	setState(LLUpdaterService::DOWNLOADING);
 	mUpdateDownloader.download(uri, hash, newVersion, false);
-	
-	if(getState() != LLUpdaterService::FAILURE) {
-		setState(LLUpdaterService::DOWNLOADING);
-	} else {
-		; // Download failed snynchronously; we are done.
-	}
 }
 
 void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,
@@ -389,13 +384,8 @@ void LLUpdaterServiceImpl::requiredUpdate(std::string const & newVersion,
 	stopTimer();
 	mNewVersion = newVersion;
 	mIsDownloading = true;
+	setState(LLUpdaterService::DOWNLOADING);
 	mUpdateDownloader.download(uri, hash, newVersion, true);
-	
-	if(getState() != LLUpdaterService::FAILURE) {
-		setState(LLUpdaterService::DOWNLOADING);
-	} else {
-		; // Download failed snynchronously; we are done.
-	}
 }
 
 void LLUpdaterServiceImpl::upToDate(void)
-- 
cgit v1.2.3


From 39a609a7ae04e2177e5dd522fe880e3aac9a685c Mon Sep 17 00:00:00 2001
From: Seth ProductEngine <slitovchuk@productengine.com>
Date: Tue, 25 Jan 2011 01:28:46 +0200
Subject: Fixed TestCapabilityProvider build issue.

---
 indra/newview/tests/llcapabilitylistener_test.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp
index 9da851ffc4..d691bb6c44 100644
--- a/indra/newview/tests/llcapabilitylistener_test.cpp
+++ b/indra/newview/tests/llcapabilitylistener_test.cpp
@@ -72,7 +72,7 @@ struct TestCapabilityProvider: public LLCapabilityProvider
     {
         mCaps[cap] = url;
     }
-    LLHost getHost() const { return mHost; }
+    const LLHost& getHost() const { return mHost; }
     std::string getDescription() const { return "TestCapabilityProvider"; }
 
     LLHost mHost;
-- 
cgit v1.2.3


From 358a091724d8df9a792c4aea73bd708b28400513 Mon Sep 17 00:00:00 2001
From: Seth ProductEngine <slitovchuk@productengine.com>
Date: Tue, 25 Jan 2011 01:13:39 +0200
Subject: STORM-843 FIXED incremental inventory search to use more restrictive
 or less restrictive filtering. Stored filter sub-string comparison with new
 string failed because of non-matching register of compared strings.
 Transforming the new search term to uppercase before comparing it with
 previous one allows to determine if filter became more or less restrictive
 and not to restart the search over. Used patch provided by Satomi Ahn.

---
 indra/newview/llinventoryfilter.cpp | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/indra/newview/llinventoryfilter.cpp b/indra/newview/llinventoryfilter.cpp
index ef4774a06d..e22363c2f6 100644
--- a/indra/newview/llinventoryfilter.cpp
+++ b/indra/newview/llinventoryfilter.cpp
@@ -393,18 +393,22 @@ void LLInventoryFilter::setFilterUUID(const LLUUID& object_id)
 
 void LLInventoryFilter::setFilterSubString(const std::string& string)
 {
-	if (mFilterSubString != string)
+	std::string filter_sub_string_new = string;
+	mFilterSubStringOrig = string;
+	LLStringUtil::trimHead(filter_sub_string_new);
+	LLStringUtil::toUpper(filter_sub_string_new);
+
+	if (mFilterSubString != filter_sub_string_new)
 	{
 		// hitting BACKSPACE, for example
-		const BOOL less_restrictive = mFilterSubString.size() >= string.size() && !mFilterSubString.substr(0, string.size()).compare(string);
+		const BOOL less_restrictive = mFilterSubString.size() >= filter_sub_string_new.size()
+			&& !mFilterSubString.substr(0, filter_sub_string_new.size()).compare(filter_sub_string_new);
 
 		// appending new characters
-		const BOOL more_restrictive = mFilterSubString.size() < string.size() && !string.substr(0, mFilterSubString.size()).compare(mFilterSubString);
+		const BOOL more_restrictive = mFilterSubString.size() < filter_sub_string_new.size()
+			&& !filter_sub_string_new.substr(0, mFilterSubString.size()).compare(mFilterSubString);
 
-		mFilterSubStringOrig = string;
-		LLStringUtil::trimHead(mFilterSubStringOrig);
-		mFilterSubString = mFilterSubStringOrig;
-		LLStringUtil::toUpper(mFilterSubString);
+		mFilterSubString = filter_sub_string_new;
 		if (less_restrictive)
 		{
 			setModified(FILTER_LESS_RESTRICTIVE);
-- 
cgit v1.2.3


From 78b7a9a88d19f901a2b90ec3f1211107ce63e283 Mon Sep 17 00:00:00 2001
From: Richard Linden <none@none>
Date: Mon, 24 Jan 2011 18:41:42 -0800
Subject: SOCIAL-473 FIX Add Kick, Freeze, Unfreeze and CSR to profile mini
 floater drop down Added Kick and CSR, made existing Freeze menu item use god
 mode freeze when in god mode (works across grid, not just with local avatars)

---
 indra/newview/llinspectavatar.cpp                  | 86 +++++++++++++++++++---
 .../default/xui/en/menu_inspect_avatar_gear.xml    | 20 ++++-
 2 files changed, 93 insertions(+), 13 deletions(-)

diff --git a/indra/newview/llinspectavatar.cpp b/indra/newview/llinspectavatar.cpp
index 91ede6d221..4ad1934264 100644
--- a/indra/newview/llinspectavatar.cpp
+++ b/indra/newview/llinspectavatar.cpp
@@ -47,6 +47,7 @@
 #include "llvoiceclient.h"
 #include "llviewerobjectlist.h"
 #include "lltransientfloatermgr.h"
+#include "llnotificationsutil.h"
 
 // Linden libraries
 #include "llfloater.h"
@@ -126,16 +127,20 @@ private:
 	void onClickReport();
 	void onClickFreeze();
 	void onClickEject();
+	void onClickKick();
+	void onClickCSR();
 	void onClickZoomIn();  
 	void onClickFindOnMap();
 	bool onVisibleFindOnMap();
-	bool onVisibleFreezeEject();
+	bool onVisibleEject();
+	bool onVisibleFreeze();
 	bool onVisibleZoomIn();
 	void onClickMuteVolume();
 	void onVolumeChange(const LLSD& data);
 	bool enableMute();
 	bool enableUnmute();
 	bool enableTeleportOffer();
+	bool godModeEnabled();
 
 	// Is used to determine if "Add friend" option should be enabled in gear menu
 	bool isNotFriend();
@@ -214,20 +219,21 @@ LLInspectAvatar::LLInspectAvatar(const LLSD& sd)
 	mCommitCallbackRegistrar.add("InspectAvatar.Pay",	boost::bind(&LLInspectAvatar::onClickPay, this));	
 	mCommitCallbackRegistrar.add("InspectAvatar.Share",	boost::bind(&LLInspectAvatar::onClickShare, this));
 	mCommitCallbackRegistrar.add("InspectAvatar.ToggleMute",	boost::bind(&LLInspectAvatar::onToggleMute, this));	
-	mCommitCallbackRegistrar.add("InspectAvatar.Freeze",
-		boost::bind(&LLInspectAvatar::onClickFreeze, this));	
-	mCommitCallbackRegistrar.add("InspectAvatar.Eject",
-		boost::bind(&LLInspectAvatar::onClickEject, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.Freeze", boost::bind(&LLInspectAvatar::onClickFreeze, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.Eject", boost::bind(&LLInspectAvatar::onClickEject, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.Kick", boost::bind(&LLInspectAvatar::onClickKick, this));	
+	mCommitCallbackRegistrar.add("InspectAvatar.CSR", boost::bind(&LLInspectAvatar::onClickCSR, this));	
 	mCommitCallbackRegistrar.add("InspectAvatar.Report",	boost::bind(&LLInspectAvatar::onClickReport, this));	
 	mCommitCallbackRegistrar.add("InspectAvatar.FindOnMap",	boost::bind(&LLInspectAvatar::onClickFindOnMap, this));	
 	mCommitCallbackRegistrar.add("InspectAvatar.ZoomIn", boost::bind(&LLInspectAvatar::onClickZoomIn, this));
 	mCommitCallbackRegistrar.add("InspectAvatar.DisableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, false));
 	mCommitCallbackRegistrar.add("InspectAvatar.EnableVoice", boost::bind(&LLInspectAvatar::toggleSelectedVoice, this, true));
+
+	mEnableCallbackRegistrar.add("InspectAvatar.EnableGod",	boost::bind(&LLInspectAvatar::godModeEnabled, this));	
 	mEnableCallbackRegistrar.add("InspectAvatar.VisibleFindOnMap",	boost::bind(&LLInspectAvatar::onVisibleFindOnMap, this));	
-	mEnableCallbackRegistrar.add("InspectAvatar.VisibleFreezeEject",	
-		boost::bind(&LLInspectAvatar::onVisibleFreezeEject, this));	
-	mEnableCallbackRegistrar.add("InspectAvatar.VisibleZoomIn", 
-		boost::bind(&LLInspectAvatar::onVisibleZoomIn, this));
+	mEnableCallbackRegistrar.add("InspectAvatar.VisibleEject",	boost::bind(&LLInspectAvatar::onVisibleEject, this));	
+	mEnableCallbackRegistrar.add("InspectAvatar.VisibleFreeze",	boost::bind(&LLInspectAvatar::onVisibleFreeze, this));	
+	mEnableCallbackRegistrar.add("InspectAvatar.VisibleZoomIn", boost::bind(&LLInspectAvatar::onVisibleZoomIn, this));
 	mEnableCallbackRegistrar.add("InspectAvatar.Gear.Enable", boost::bind(&LLInspectAvatar::isNotFriend, this));
 	mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableCall", boost::bind(&LLAvatarActions::canCall));
 	mEnableCallbackRegistrar.add("InspectAvatar.Gear.EnableTeleportOffer", boost::bind(&LLInspectAvatar::enableTeleportOffer, this));
@@ -656,11 +662,18 @@ bool LLInspectAvatar::onVisibleFindOnMap()
 	return gAgent.isGodlike() || is_agent_mappable(mAvatarID);
 }
 
-bool LLInspectAvatar::onVisibleFreezeEject()
+bool LLInspectAvatar::onVisibleEject()
 {
 	return enable_freeze_eject( LLSD(mAvatarID) );
 }
 
+bool LLInspectAvatar::onVisibleFreeze()
+{
+	// either user is a god and can do long distance freeze
+	// or check for target proximity and permissions
+	return gAgent.isGodlike() || enable_freeze_eject(LLSD(mAvatarID));
+}
+
 bool LLInspectAvatar::onVisibleZoomIn()
 {
 	return gObjectList.findObject(mAvatarID);
@@ -725,9 +738,41 @@ void LLInspectAvatar::onClickReport()
 	closeFloater();
 }
 
+bool godlike_freeze(const LLSD& notification, const LLSD& response)
+{
+	LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID();
+	S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+	switch (option)
+	{
+	case 0:
+		LLAvatarActions::freeze(avatar_id);
+		break;
+	case 1:
+		LLAvatarActions::unfreeze(avatar_id);
+		break;
+	default:
+		break;
+	}
+
+	return false;
+}
+
 void LLInspectAvatar::onClickFreeze()
 {
-	handle_avatar_freeze( LLSD(mAvatarID) );
+	if (gAgent.isGodlike())
+	{
+		// use godlike freeze-at-a-distance, with confirmation
+		LLNotificationsUtil::add("FreezeAvatar",
+			LLSD(),
+			LLSD().with("avatar_id", mAvatarID),
+			godlike_freeze);
+	}
+	else
+	{
+		// use default "local" version of freezing that requires avatar to be in range
+		handle_avatar_freeze( LLSD(mAvatarID) );
+	}
 	closeFloater();
 }
 
@@ -737,6 +782,20 @@ void LLInspectAvatar::onClickEject()
 	closeFloater();
 }
 
+void LLInspectAvatar::onClickKick()
+{
+	LLAvatarActions::kick(mAvatarID);
+	closeFloater();
+}
+
+void LLInspectAvatar::onClickCSR()
+{
+	std::string name;
+	gCacheName->getFullName(mAvatarID, name);
+	LLAvatarActions::csr(mAvatarID, name);
+	closeFloater();
+}
+
 void LLInspectAvatar::onClickZoomIn() 
 {
 	handle_zoom_to_object(mAvatarID);
@@ -785,6 +844,11 @@ bool LLInspectAvatar::enableTeleportOffer()
 	return LLAvatarActions::canOfferTeleport(mAvatarID);
 }
 
+bool LLInspectAvatar::godModeEnabled()
+{
+	return gAgent.isGodlike();
+}
+
 //////////////////////////////////////////////////////////////////////////////
 // LLInspectAvatarUtil
 //////////////////////////////////////////////////////////////////////////////
diff --git a/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml
index 58d58a6ca9..76b188220d 100644
--- a/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_inspect_avatar_gear.xml
@@ -78,7 +78,7 @@
     <menu_item_call.on_click
      function="InspectAvatar.Freeze"/>
     <menu_item_call.on_visible
-     function="InspectAvatar.VisibleFreezeEject"/>
+     function="InspectAvatar.VisibleFreeze"/>
   </menu_item_call>
   <menu_item_call
    label="Eject"
@@ -86,7 +86,23 @@
     <menu_item_call.on_click
      function="InspectAvatar.Eject"/>
     <menu_item_call.on_visible
-     function="InspectAvatar.VisibleFreezeEject"/>
+     function="InspectAvatar.VisibleEject"/>
+  </menu_item_call>
+  <menu_item_call
+   label="Kick"
+   name="kick">
+    <menu_item_call.on_click
+     function="InspectAvatar.Kick"/>
+    <menu_item_call.on_visible
+     function="InspectAvatar.EnableGod"/>
+  </menu_item_call>
+  <menu_item_call
+  label="CSR"
+  name="csr">
+    <menu_item_call.on_click
+     function="InspectAvatar.CSR" />
+    <menu_item_call.on_visible
+     function="InspectAvatar.EnableGod" />
   </menu_item_call>
   <menu_item_call
    label="Debug Textures"
-- 
cgit v1.2.3


From 714ba52df0397b58769e02ae9a7d9877a4505d34 Mon Sep 17 00:00:00 2001
From: Vadim ProductEngine <vsavchuk@productengine.com>
Date: Tue, 25 Jan 2011 17:10:23 -0500
Subject: correct build error

---
 indra/newview/tests/llcapabilitylistener_test.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/tests/llcapabilitylistener_test.cpp b/indra/newview/tests/llcapabilitylistener_test.cpp
index 9da851ffc4..d691bb6c44 100644
--- a/indra/newview/tests/llcapabilitylistener_test.cpp
+++ b/indra/newview/tests/llcapabilitylistener_test.cpp
@@ -72,7 +72,7 @@ struct TestCapabilityProvider: public LLCapabilityProvider
     {
         mCaps[cap] = url;
     }
-    LLHost getHost() const { return mHost; }
+    const LLHost& getHost() const { return mHost; }
     std::string getDescription() const { return "TestCapabilityProvider"; }
 
     LLHost mHost;
-- 
cgit v1.2.3


From 8f54dc2958e75587165623b0292940200fb49f59 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 26 Jan 2011 11:13:04 -0700
Subject: for SH-846: design and implement the debug code to locate memory
 leaking

---
 indra/llcommon/llmemory.cpp                        | 170 ++++++++++++++++++++-
 indra/llcommon/llmemory.h                          |  46 +++++-
 indra/llcommon/llmemtype.cpp                       |   1 +
 indra/newview/app_settings/settings.xml            |  11 ++
 indra/newview/llappviewer.cpp                      |  15 +-
 indra/newview/llmemoryview.cpp                     |  51 ++++++-
 indra/newview/llviewerwindow.cpp                   |   8 +
 indra/newview/skins/default/xui/en/menu_viewer.xml |  10 ++
 8 files changed, 304 insertions(+), 8 deletions(-)

diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index a502d1a7eb..e4ece78d53 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -26,6 +26,12 @@
 
 #include "linden_common.h"
 
+#include "llmemory.h"
+
+#if MEM_TRACK_MEM
+#include "llthread.h"
+#endif
+
 #if defined(LL_WINDOWS)
 # include <windows.h>
 # include <psapi.h>
@@ -37,8 +43,6 @@
 # include <unistd.h>
 #endif
 
-#include "llmemory.h"
-
 //----------------------------------------------------------------------------
 
 //static
@@ -105,6 +109,20 @@ U64 LLMemory::getCurrentRSS()
 	return counters.WorkingSetSize;
 }
 
+//static 
+U32 LLMemory::getWorkingSetSize()
+{
+    PROCESS_MEMORY_COUNTERS pmc ;
+	U32 ret = 0 ;
+
+    if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) )
+	{
+		ret = pmc.WorkingSetSize ;
+	}
+
+	return ret ;
+}
+
 #elif defined(LL_DARWIN)
 
 /* 
@@ -151,6 +169,11 @@ U64 LLMemory::getCurrentRSS()
 	return residentSize;
 }
 
+U32 LLMemory::getWorkingSetSize()
+{
+	return 0 ;
+}
+
 #elif defined(LL_LINUX)
 
 U64 LLMemory::getCurrentRSS()
@@ -185,6 +208,11 @@ bail:
 	return rss;
 }
 
+U32 LLMemory::getWorkingSetSize()
+{
+	return 0 ;
+}
+
 #elif LL_SOLARIS
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -213,6 +241,12 @@ U64 LLMemory::getCurrentRSS()
 
 	return((U64)proc_psinfo.pr_rssize * 1024);
 }
+
+U32 LLMemory::getWorkingSetSize()
+{
+	return 0 ;
+}
+
 #else
 
 U64 LLMemory::getCurrentRSS()
@@ -220,4 +254,136 @@ U64 LLMemory::getCurrentRSS()
 	return 0;
 }
 
+U32 LLMemory::getWorkingSetSize()
+{
+	return 0 ;
+}
+
 #endif
+
+//--------------------------------------------------------------------------------------------------
+#if MEM_TRACK_MEM
+#include "llframetimer.h"
+
+//static 
+LLMemTracker* LLMemTracker::sInstance = NULL ;
+
+LLMemTracker::LLMemTracker()
+{
+	mLastAllocatedMem = LLMemory::getWorkingSetSize() ;
+	mCapacity = 128 ;	
+	mCurIndex = 0 ;
+	mCounter = 0 ;
+	mDrawnIndex = 0 ;
+
+	mMutexp = new LLMutex(NULL) ;
+	mStringBuffer = new char*[128] ;
+	mStringBuffer[0] = new char[mCapacity * 128] ;
+	for(S32 i = 1 ; i < mCapacity ; i++)
+	{
+		mStringBuffer[i] = mStringBuffer[i-1] + 128 ;
+	}
+}
+
+LLMemTracker::~LLMemTracker()
+{
+	delete[] mStringBuffer[0] ;
+	delete[] mStringBuffer;
+	delete mMutexp ;
+}
+
+//static 
+LLMemTracker* LLMemTracker::getInstance()
+{
+	if(!sInstance)
+	{
+		sInstance = new LLMemTracker() ;
+	}
+	return sInstance ;
+}
+
+//static 
+void LLMemTracker::release() 
+{
+	if(sInstance)
+	{
+		delete sInstance ;
+		sInstance = NULL ;
+	}
+}
+
+//static
+void LLMemTracker::track(const char* function, const int line)
+{
+	static const S32 MIN_ALLOCATION = 1024 ; //1KB
+
+	U32 allocated_mem = LLMemory::getWorkingSetSize() ;
+
+	LLMutexLock lock(mMutexp) ;
+
+	if(allocated_mem <= mLastAllocatedMem)
+	{
+		return ; //occupied memory does not grow
+	}
+
+	S32 delta_mem = allocated_mem - mLastAllocatedMem ;
+	mLastAllocatedMem = allocated_mem ;
+	if(delta_mem < MIN_ALLOCATION)
+	{
+		return ;
+	}
+		
+	char* buffer = mStringBuffer[mCurIndex++] ;
+	F32 time = (F32)LLFrameTimer::getElapsedSeconds() ;
+	S32 hours = (S32)(time / (60*60));
+	S32 mins = (S32)((time - hours*(60*60)) / 60);
+	S32 secs = (S32)((time - hours*(60*60) - mins*60));
+	strcpy(buffer, function) ;
+	sprintf(buffer + strlen(function), " line: %d DeltaMem: %d (bytes) Time: %d:%02d:%02d", line, delta_mem, hours,mins,secs) ;
+
+	if(mCounter < mCapacity)
+	{
+		mCounter++ ;
+	}
+	if(mCurIndex >= mCapacity)
+	{
+		mCurIndex = 0 ;		
+	}
+}
+
+
+//static 
+void LLMemTracker::preDraw() 
+{
+	mMutexp->lock() ;
+
+	mDrawnIndex = mCurIndex - 1;
+	mNumOfDrawn = 0 ;
+}
+	
+//static 
+void LLMemTracker::postDraw() 
+{
+	mMutexp->unlock() ;
+}
+
+//static 
+const char* LLMemTracker::getNextLine() 
+{
+	if(mNumOfDrawn >= mCounter)
+	{
+		return NULL ;
+	}
+	mNumOfDrawn++;
+
+	if(mDrawnIndex < 0)
+	{
+		mDrawnIndex = mCapacity - 1 ;
+	}
+
+	return mStringBuffer[mDrawnIndex--] ;
+}
+
+#endif //MEM_TRACK_MEM
+//--------------------------------------------------------------------------------------------------
+
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 9bf4248bb7..e6a6a8c3da 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -26,7 +26,7 @@
 #ifndef LLMEMORY_H
 #define LLMEMORY_H
 
-
+#include "llmemtype.h"
 
 extern S32 gTotalDAlloc;
 extern S32 gTotalDAUse;
@@ -44,10 +44,54 @@ public:
 	// Return the resident set size of the current process, in bytes.
 	// Return value is zero if not known.
 	static U64 getCurrentRSS();
+	static U32 getWorkingSetSize();
 private:
 	static char* reserveMem;
 };
 
+//----------------------------------------------------------------------------
+#if MEM_TRACK_MEM
+class LLMutex ;
+class LL_COMMON_API LLMemTracker
+{
+private:
+	LLMemTracker() ;
+	~LLMemTracker() ;
+
+public:
+	static void release() ;
+	static LLMemTracker* getInstance() ;
+
+	void track(const char* function, const int line) ;
+	void preDraw() ;
+	void postDraw() ;
+	const char* getNextLine() ;
+
+private:
+	static LLMemTracker* sInstance ;
+	
+	char**     mStringBuffer ;
+	S32        mCapacity ;
+	U32        mLastAllocatedMem ;
+	S32        mCurIndex ;
+	S32        mCounter;
+	S32        mDrawnIndex;
+	S32        mNumOfDrawn;
+	LLMutex*   mMutexp ;
+};
+
+#define MEM_TRACK_RELEASE LLMemTracker::release() ;
+#define MEM_TRACK         LLMemTracker::getInstance()->track(__FUNCTION__, __LINE__) ;
+
+#else // MEM_TRACK_MEM
+
+#define MEM_TRACK_RELEASE
+#define MEM_TRACK
+
+#endif // MEM_TRACK_MEM
+
+//----------------------------------------------------------------------------
+
 // LLRefCount moved to llrefcount.h
 
 // LLPointer moved to llpointer.h
diff --git a/indra/llcommon/llmemtype.cpp b/indra/llcommon/llmemtype.cpp
index fe83f87d4b..6290a7158f 100644
--- a/indra/llcommon/llmemtype.cpp
+++ b/indra/llcommon/llmemtype.cpp
@@ -229,3 +229,4 @@ char const * LLMemType::getNameFromID(S32 id)
 	return DeclareMemType::mNameList[id];
 }
 
+//--------------------------------------------------------------------------------------------------
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index ced46c7294..72d83ad024 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1852,6 +1852,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+   <key>DebugShowMemory</key>
+    <map>
+      <key>Comment</key>
+      <string>Show Total Allocated Memory</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>DebugShowRenderInfo</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 6a9dfaf21b..87c0085226 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1057,6 +1057,8 @@ bool LLAppViewer::mainLoop()
 		//clear call stack records
 		llclearcallstacks;
 
+		MEM_TRACK
+
 		//check memory availability information
 		{
 			if(memory_check_interval < memCheckTimer.getElapsedTimeF32())
@@ -1101,6 +1103,8 @@ bool LLAppViewer::mainLoop()
 			}
 			
 #endif
+			MEM_TRACK
+
 			//memory leaking simulation
 			LLFloaterMemLeak* mem_leak_instance =
 				LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
@@ -1162,6 +1166,8 @@ bool LLAppViewer::mainLoop()
 					resumeMainloopTimeout();
 				}
  
+				MEM_TRACK
+
 				if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
 				{
 					pauseMainloopTimeout();
@@ -1183,6 +1189,8 @@ bool LLAppViewer::mainLoop()
 
 			}
 
+			MEM_TRACK
+
 			pingMainloopTimeout("Main:Sleep");
 			
 			pauseMainloopTimeout();
@@ -1296,7 +1304,10 @@ bool LLAppViewer::mainLoop()
 				resumeMainloopTimeout();
 	
 				pingMainloopTimeout("Main:End");
-			}			
+			}	
+
+			MEM_TRACK
+
 		}
 		catch(std::bad_alloc)
 		{			
@@ -1779,6 +1790,8 @@ bool LLAppViewer::cleanup()
 
 	ll_close_fail_log();
 
+	MEM_TRACK_RELEASE
+
     llinfos << "Goodbye!" << llendflush;
 
 	// return 0;
diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp
index 9a244e2562..397a77c4e3 100644
--- a/indra/newview/llmemoryview.cpp
+++ b/indra/newview/llmemoryview.cpp
@@ -37,6 +37,7 @@
 #include <sstream>
 #include <boost/algorithm/string/split.hpp>
 
+#include "llmemory.h"
 
 LLMemoryView::LLMemoryView(const LLMemoryView::Params& p)
 :	LLView(p),
@@ -148,13 +149,14 @@ void LLMemoryView::draw()
 
 	// cut off lines on bottom
 	U32 max_lines = U32((height - 2 * line_height) / line_height);
-    std::vector<LLWString>::const_iterator end = mLines.end();
+	y_pos = height - MARGIN_AMT - line_height;
+    y_off = 0.f;
+
+#if !MEM_TRACK_MEM
+	std::vector<LLWString>::const_iterator end = mLines.end();
     if(mLines.size() > max_lines) {
         end = mLines.begin() + max_lines;
     }
-
-	y_pos = height - MARGIN_AMT - line_height;
-    y_off = 0.f;
     for (std::vector<LLWString>::const_iterator i = mLines.begin(); i != end; ++i)
 	{
 		font->render(*i, 0, MARGIN_AMT, y_pos -  y_off,
@@ -169,6 +171,47 @@ void LLMemoryView::draw()
 		y_off += line_height;
 	}
 
+#else
+	LLMemTracker::getInstance()->preDraw() ;
+
+	{
+		F32 x_pos = MARGIN_AMT ;
+		U32 lines = 0 ;
+		const char* str = LLMemTracker::getInstance()->getNextLine() ;
+		while(str != NULL)
+		{
+			lines++ ;
+			font->renderUTF8(str, 0, x_pos, y_pos -  y_off,
+				LLColor4::white,
+				LLFontGL::LEFT, 
+				LLFontGL::BASELINE,
+				LLFontGL::NORMAL,
+				LLFontGL::DROP_SHADOW,
+				S32_MAX,
+				target_width,
+				NULL, FALSE);
+		
+			str = LLMemTracker::getInstance()->getNextLine() ;
+			y_off += line_height;
+
+			if(lines >= max_lines)
+			{
+				lines = 0 ;
+				x_pos += 512.f ;
+				if(x_pos + 512.f > target_width)
+				{
+					break ;
+				}
+
+				y_pos = height - MARGIN_AMT - line_height;
+				y_off = 0.f;
+			}
+		}
+	}
+
+	LLMemTracker::getInstance()->postDraw() ;
+#endif
+
 #if MEM_TRACK_TYPE
 
 	S32 left, top, right, bottom;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 166b110412..ca0478ee0c 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -351,6 +351,14 @@ public:
 			addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
 		}
 		
+#if LL_WINDOWS
+		if (gSavedSettings.getBOOL("DebugShowMemory"))
+		{
+			addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024)); 
+			ypos += y_inc;
+		}
+#endif
+
 		if (gDisplayCameraPos)
 		{
 			std::string camera_view_text;
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index c2735c85e4..08ae0c233e 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1990,6 +1990,16 @@
                  function="ToggleControl"
                  parameter="DebugShowColor" />
             </menu_item_check>
+            <menu_item_check
+               label="Show Memory"
+               name="Show Memory">
+              <menu_item_check.on_check
+               function="CheckControl"
+               parameter="DebugShowMemory" />
+              <menu_item_check.on_click
+               function="ToggleControl"
+               parameter="DebugShowMemory" />
+            </menu_item_check>
 
             <menu_item_separator/>
 
-- 
cgit v1.2.3


From 5e6b4b5ad0dc56869430bcd31a942bdc7f8a2899 Mon Sep 17 00:00:00 2001
From: paul_productengine <none@none>
Date: Wed, 26 Jan 2011 20:24:49 +0200
Subject: STORM-351 FIXED Scrolling flat list by mouse wheel changes zoom level
 in-world

- Prevent passing scroll event to in-world
---
 indra/newview/llsidetray.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index 19d1bdee86..eb537c7d7b 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -141,6 +141,8 @@ public:
 	
 	void			toggleTabDocked();
 
+	BOOL			handleScrollWheel(S32 x, S32 y, S32 clicks);
+
 	LLPanel *getPanel();
 private:
 	std::string mTabTitle;
@@ -269,6 +271,15 @@ void LLSideTrayTab::toggleTabDocked()
 	LLFloaterReg::toggleInstance("side_bar_tab", tab_name);
 }
 
+BOOL LLSideTrayTab::handleScrollWheel(S32 x, S32 y, S32 clicks)
+{
+	// Let children handle the event
+	LLUICtrl::handleScrollWheel(x, y, clicks);
+
+	// and then eat it to prevent in-world scrolling (STORM-351).
+	return TRUE;
+}
+
 void LLSideTrayTab::dock(LLFloater* floater_tab)
 {
 	LLSideTray* side_tray = getSideTray();
-- 
cgit v1.2.3


From 3eba59e963d87f54e1b33b0a34de3fe37e67ebe1 Mon Sep 17 00:00:00 2001
From: David Kaprielian <sabin@lindenlab.com>
Date: Wed, 26 Jan 2011 15:07:54 -0800
Subject: Adding run_tests buildparam and setting to false for coverity builds
 so coverity can run. Reviewed by CG.

---
 BuildParams | 1 +
 build.sh    | 3 ++-
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/BuildParams b/BuildParams
index 0a4271f7a8..8e036ab56b 100644
--- a/BuildParams
+++ b/BuildParams
@@ -26,6 +26,7 @@ viewer-development.show_changes_since = last_sprint
 
 # Build Settings
 viewer-development_coverity.coverity_product = viewer
+viewer-development_coverity.run_tests = false
 viewer-development.build_debug_release_separately = true
 
 # Notifications - to configure email notices, add a setting like this:
diff --git a/build.sh b/build.sh
index cd1d9df6f3..1c28f5a255 100755
--- a/build.sh
+++ b/build.sh
@@ -66,7 +66,8 @@ pre_build()
     -DRELEASE_CRASH_REPORTING:BOOL=ON \
     -DLOCALIZESETUP:BOOL=ON \
     -DPACKAGE:BOOL=ON \
-    -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE
+    -DCMAKE_VERBOSE_MAKEFILE:BOOL=TRUE \
+    -DLL_TESTS:BOOL="$run_tests"
   end_section "Pre$variant"
 }
 
-- 
cgit v1.2.3


From 89f49d53d5e057c4fa2aaffa0e12a91e1b36e11a Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Wed, 26 Jan 2011 16:00:46 -0800
Subject: Added tag DRTVWR-33--2.5.0beta2 for changeset 54d772d8687c

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 0e0898afb0..1e2e10eb97 100644
--- a/.hgtags
+++ b/.hgtags
@@ -51,3 +51,4 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
 345b17e7cf630db77e840b4fe3451bd476d750a3 2.5.0-beta1
 345b17e7cf630db77e840b4fe3451bd476d750a3 76f586a8e22b
 0000000000000000000000000000000000000000 76f586a8e22b
+54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f DRTVWR-33--2.5.0beta2
-- 
cgit v1.2.3


From 6531eed04e24239233f79624572219e88017f476 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Wed, 26 Jan 2011 17:03:30 -0700
Subject: add "pause" function for SH-846: design and implement the debug code
 to locate memory leaking

---
 indra/llcommon/llmemory.cpp    | 18 +++++++++++++-----
 indra/llcommon/llmemory.h      |  3 ++-
 indra/newview/llmemoryview.cpp |  4 +++-
 indra/newview/llmemoryview.h   |  1 +
 4 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index e4ece78d53..f340105f57 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -275,6 +275,7 @@ LLMemTracker::LLMemTracker()
 	mCurIndex = 0 ;
 	mCounter = 0 ;
 	mDrawnIndex = 0 ;
+	mPaused = FALSE ;
 
 	mMutexp = new LLMutex(NULL) ;
 	mStringBuffer = new char*[128] ;
@@ -315,19 +316,25 @@ void LLMemTracker::release()
 //static
 void LLMemTracker::track(const char* function, const int line)
 {
-	static const S32 MIN_ALLOCATION = 1024 ; //1KB
+	static const S32 MIN_ALLOCATION = 0 ; //1KB
+
+	if(mPaused)
+	{
+		return ;
+	}
 
 	U32 allocated_mem = LLMemory::getWorkingSetSize() ;
 
 	LLMutexLock lock(mMutexp) ;
 
-	if(allocated_mem <= mLastAllocatedMem)
+	S32 delta_mem = allocated_mem - mLastAllocatedMem ;
+	mLastAllocatedMem = allocated_mem ;
+
+	if(delta_mem <= 0)
 	{
 		return ; //occupied memory does not grow
 	}
 
-	S32 delta_mem = allocated_mem - mLastAllocatedMem ;
-	mLastAllocatedMem = allocated_mem ;
 	if(delta_mem < MIN_ALLOCATION)
 	{
 		return ;
@@ -353,10 +360,11 @@ void LLMemTracker::track(const char* function, const int line)
 
 
 //static 
-void LLMemTracker::preDraw() 
+void LLMemTracker::preDraw(BOOL pause) 
 {
 	mMutexp->lock() ;
 
+	mPaused = pause ;
 	mDrawnIndex = mCurIndex - 1;
 	mNumOfDrawn = 0 ;
 }
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index e6a6a8c3da..11406f59b0 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -63,7 +63,7 @@ public:
 	static LLMemTracker* getInstance() ;
 
 	void track(const char* function, const int line) ;
-	void preDraw() ;
+	void preDraw(BOOL pause) ;
 	void postDraw() ;
 	const char* getNextLine() ;
 
@@ -77,6 +77,7 @@ private:
 	S32        mCounter;
 	S32        mDrawnIndex;
 	S32        mNumOfDrawn;
+	BOOL       mPaused;
 	LLMutex*   mMutexp ;
 };
 
diff --git a/indra/newview/llmemoryview.cpp b/indra/newview/llmemoryview.cpp
index 397a77c4e3..7e9c3c84a7 100644
--- a/indra/newview/llmemoryview.cpp
+++ b/indra/newview/llmemoryview.cpp
@@ -41,6 +41,7 @@
 
 LLMemoryView::LLMemoryView(const LLMemoryView::Params& p)
 :	LLView(p),
+	mPaused(FALSE),
 	//mDelay(120),
     mAlloc(NULL)
 {
@@ -60,6 +61,7 @@ BOOL LLMemoryView::handleMouseDown(S32 x, S32 y, MASK mask)
 	}
 	else
 	{
+		mPaused = !mPaused;
 	}
 	return TRUE;
 }
@@ -172,7 +174,7 @@ void LLMemoryView::draw()
 	}
 
 #else
-	LLMemTracker::getInstance()->preDraw() ;
+	LLMemTracker::getInstance()->preDraw(mPaused) ;
 
 	{
 		F32 x_pos = MARGIN_AMT ;
diff --git a/indra/newview/llmemoryview.h b/indra/newview/llmemoryview.h
index 24ea058279..9bdc59ab10 100644
--- a/indra/newview/llmemoryview.h
+++ b/indra/newview/llmemoryview.h
@@ -55,6 +55,7 @@ public:
 private:
     std::vector<LLWString> mLines;
 	LLAllocator* mAlloc;
+	BOOL mPaused ;
 
 };
 
-- 
cgit v1.2.3


From 0d5b0cad146d2ce4a24256845b36c4eee847f7ad Mon Sep 17 00:00:00 2001
From: Twisted Laws <none@none>
Date: Wed, 26 Jan 2011 19:22:42 -0500
Subject: Embed Minimap into the Nearby list of the People Sidebar

---
 doc/contributions.txt                              |   2 +
 indra/newview/llfloatermap.cpp                     |   3 +-
 indra/newview/llnetmap.cpp                         | 149 ++++++++++++++++++++-
 indra/newview/llnetmap.h                           |  18 ++-
 indra/newview/llpanelpeople.cpp                    |  13 +-
 indra/newview/llpanelpeople.h                      |   1 +
 indra/newview/skins/default/xui/en/floater_map.xml |   6 +-
 .../newview/skins/default/xui/en/panel_people.xml  |  26 +++-
 8 files changed, 205 insertions(+), 13 deletions(-)

diff --git a/doc/contributions.txt b/doc/contributions.txt
index 4e91bbdd36..3ac9da3e65 100644
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -387,6 +387,7 @@ Jonathan Yap
 	VWR-17801
 	VWR-24347
 	STORM-844
+	STORM-643
 Kage Pixel
 	VWR-11
 Ken March
@@ -769,6 +770,7 @@ Twisted Laws
 	STORM-466
 	STORM-467
 	STORM-844
+	STORM-643
 Vadim Bigbear
 	VWR-2681
 Vector Hastings
diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp
index 1b94d8cbcd..80920c80d6 100644
--- a/indra/newview/llfloatermap.cpp
+++ b/indra/newview/llfloatermap.cpp
@@ -83,7 +83,8 @@ LLFloaterMap::~LLFloaterMap()
 BOOL LLFloaterMap::postBuild()
 {
 	mMap = getChild<LLNetMap>("Net Map");
-	mMap->setToolTipMsg(getString("ToolTipMsg"));	
+	mMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? 
+		getString("AltToolTipMsg") : getString("ToolTipMsg"));
 	sendChildToBack(mMap);
 	
 	mTextBoxNorth = getChild<LLTextBox> ("floater_map_north");
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 1a8ec4991d..93039d935d 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -47,6 +47,7 @@
 #include "llagentcamera.h"
 #include "llappviewer.h" // for gDisconnected
 #include "llcallingcard.h" // LLAvatarTracker
+#include "llfloaterworldmap.h"
 #include "lltracker.h"
 #include "llsurface.h"
 #include "llviewercamera.h"
@@ -91,7 +92,8 @@ LLNetMap::LLNetMap (const Params & p)
 	mObjectImagep(),
 	mClosestAgentToCursor(),
 	mClosestAgentAtLastRightClick(),
-	mToolTipMsg()
+	mToolTipMsg(),
+	mPopupMenu(NULL)
 {
 	mDotRadius = llmax(DOT_SCALE * mPixelsPerMeter, MIN_DOT_RADIUS);
 	setScale(gSavedSettings.getF32("MiniMapScale"));
@@ -102,6 +104,21 @@ LLNetMap::~LLNetMap()
 	gSavedSettings.setF32("MiniMapScale", mScale);
 }
 
+BOOL LLNetMap::postBuild()
+{
+	LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar;
+	
+	registrar.add("Minimap.Zoom", boost::bind(&LLNetMap::handleZoom, this, _2));
+	registrar.add("Minimap.Tracker", boost::bind(&LLNetMap::handleStopTracking, this, _2));
+
+	mPopupMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_mini_map.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+	if (mPopupMenu && !LLTracker::isTracking(0))
+	{
+		mPopupMenu->setItemEnabled ("Stop Tracking", false);
+	}
+	return TRUE;
+}
+
 void LLNetMap::setScale( F32 scale )
 {
 	scale = llclamp(scale, MAP_SCALE_MIN, MAP_SCALE_MAX);
@@ -354,16 +371,49 @@ void LLNetMap::draw()
 
 				pos_map = globalPosToView(pos_global);
 
+				LLUUID uuid(NULL);
 				BOOL show_as_friend = FALSE;
 				if( i < regionp->mMapAvatarIDs.count())
 				{
-					show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(regionp->mMapAvatarIDs.get(i)) != NULL);
+					uuid = regionp->mMapAvatarIDs.get(i);
+					show_as_friend = (LLAvatarTracker::instance().getBuddyInfo(uuid) != NULL);
 				}
+
+				LLColor4 color = show_as_friend ? map_avatar_friend_color : map_avatar_color;
 				LLWorldMapView::drawAvatar(
 					pos_map.mV[VX], pos_map.mV[VY], 
-					show_as_friend ? map_avatar_friend_color : map_avatar_color, 
+					color, 
 					pos_map.mV[VZ], mDotRadius);
 
+				if(uuid.notNull())
+				{
+					bool selected = false;
+					uuid_vec_t::iterator sel_iter = gmSelected.begin();
+					for (; sel_iter != gmSelected.end(); sel_iter++)
+					{
+						if(*sel_iter == uuid)
+						{
+							selected = true;
+							break;
+						}
+					}
+					if(selected)
+					{
+						if( (pos_map.mV[VX] < 0) ||
+							(pos_map.mV[VY] < 0) ||
+							(pos_map.mV[VX] >= getRect().getWidth()) ||
+							(pos_map.mV[VY] >= getRect().getHeight()) )
+						{
+							S32 x = llround( pos_map.mV[VX] );
+							S32 y = llround( pos_map.mV[VY] );
+							LLWorldMapView::drawTrackingCircle( getRect(), x, y, color, 1, 10);
+						} else
+						{
+							LLWorldMapView::drawTrackingDot(pos_map.mV[VX],pos_map.mV[VY],color,0.f);
+						}
+					}
+				}
+
 				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 < min_pick_dist && dist_to_cursor < closest_dist)
@@ -460,6 +510,13 @@ void LLNetMap::draw()
 	gGL.popUIMatrix();
 
 	LLUICtrl::draw();
+
+	if (LLTracker::isTracking(0))
+	{
+		mPopupMenu->setItemEnabled ("Stop Tracking", true);
+	}
+	
+
 }
 
 void LLNetMap::reshape(S32 width, S32 height, BOOL called_from_parent)
@@ -600,7 +657,6 @@ BOOL LLNetMap::handleToolTip( S32 x, S32 y, MASK mask )
 	args["[REGION]"] = region_name;
 	std::string msg = mToolTipMsg;
 	LLStringUtil::format(msg, args);
-
 	LLToolTipMgr::instance().show(LLToolTip::Params()
 		.message(msg)
 		.sticky_rect(sticky_rect));
@@ -793,6 +849,9 @@ BOOL LLNetMap::handleMouseDown( S32 x, S32 y, MASK mask )
 
 BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask )
 {
+	if(abs(mMouseDown.mX-x)<3 && abs(mMouseDown.mY-y)<3)
+		handleClick(x,y,mask);
+
 	if (hasMouseCapture())
 	{
 		if (mPanning)
@@ -821,6 +880,53 @@ BOOL LLNetMap::handleMouseUp( S32 x, S32 y, MASK mask )
 	return FALSE;
 }
 
+BOOL LLNetMap::handleRightMouseDown(S32 x, S32 y, MASK mask)
+{
+	if (mPopupMenu)
+	{
+		mPopupMenu->buildDrawLabels();
+		mPopupMenu->updateParent(LLMenuGL::sMenuContainer);
+		LLMenuGL::showPopup(this, mPopupMenu, x, y);
+	}
+	return TRUE;
+}
+
+BOOL LLNetMap::handleClick(S32 x, S32 y, MASK mask)
+{
+	// TODO: allow clicking an avatar on minimap to select avatar in the nearby avatar list
+	// if(mClosestAgentToCursor.notNull())
+	//     mNearbyList->selectUser(mClosestAgentToCursor);
+	// Needs a registered observer i guess to accomplish this without using
+	// globals to tell the mNearbyList in llpeoplepanel to select the user
+	return TRUE;
+}
+
+BOOL LLNetMap::handleDoubleClick(S32 x, S32 y, MASK mask)
+{
+	LLVector3d pos_global = viewPosToGlobal(x, y);
+	
+	// If we're not tracking a beacon already, double-click will set one 
+	if (!LLTracker::isTracking(NULL))
+	{
+		LLFloaterWorldMap* world_map = LLFloaterWorldMap::getInstance();
+		if (world_map)
+		{
+			world_map->trackLocation(pos_global);
+		}
+	}
+	
+	if (gSavedSettings.getBOOL("DoubleClickTeleport"))
+	{
+		// If DoubleClickTeleport is on, double clicking the minimap will teleport there
+		gAgent.teleportViaLocationLookAt(pos_global);
+	}
+	else 
+	{
+		LLFloaterReg::showInstance("world_map");
+	}
+	return TRUE;
+}
+
 // static
 bool LLNetMap::outsideSlop( S32 x, S32 y, S32 start_x, S32 start_y, S32 slop )
 {
@@ -871,3 +977,38 @@ BOOL LLNetMap::handleHover( S32 x, S32 y, MASK mask )
 
 	return TRUE;
 }
+
+void LLNetMap::handleZoom(const LLSD& userdata)
+{
+	std::string level = userdata.asString();
+	
+	F32 scale = 0.0f;
+	if (level == std::string("default"))
+	{
+		LLControlVariable *pvar = gSavedSettings.getControl("MiniMapScale");
+		if(pvar)
+		{
+			pvar->resetToDefault();
+			scale = gSavedSettings.getF32("MiniMapScale");
+		}
+	}
+	else if (level == std::string("close"))
+		scale = LLNetMap::MAP_SCALE_MAX;
+	else if (level == std::string("medium"))
+		scale = LLNetMap::MAP_SCALE_MID;
+	else if (level == std::string("far"))
+		scale = LLNetMap::MAP_SCALE_MIN;
+	if (scale != 0.0f)
+	{
+		setScale(scale);
+	}
+}
+
+void LLNetMap::handleStopTracking (const LLSD& userdata)
+{
+	if (mPopupMenu)
+	{
+		mPopupMenu->setItemEnabled ("Stop Tracking", false);
+		LLTracker::stopTracking ((void*)LLTracker::isTracking(NULL));
+	}
+}
diff --git a/indra/newview/llnetmap.h b/indra/newview/llnetmap.h
index e053b1c177..20fcee0814 100644
--- a/indra/newview/llnetmap.h
+++ b/indra/newview/llnetmap.h
@@ -39,6 +39,7 @@ class LLCoordGL;
 class LLImageRaw;
 class LLViewerTexture;
 class LLFloaterMap;
+class LLMenuGL;
 
 class LLNetMap : public LLUICtrl
 {
@@ -72,7 +73,12 @@ public:
 	/*virtual*/ BOOL	handleHover( S32 x, S32 y, MASK mask );
 	/*virtual*/ BOOL	handleToolTip( S32 x, S32 y, MASK mask);
 	/*virtual*/ void	reshape(S32 width, S32 height, BOOL called_from_parent = TRUE);
-	
+
+	/*virtual*/ BOOL 	postBuild();
+	/*virtual*/ BOOL	handleRightMouseDown( S32 x, S32 y, MASK mask );
+	/*virtual*/ BOOL	handleClick(S32 x, S32 y, MASK mask);
+	/*virtual*/ BOOL	handleDoubleClick( S32 x, S32 y, MASK mask );
+
 	void			setScale( F32 scale );
 	void			setToolTipMsg(const std::string& msg) { mToolTipMsg = msg; }
 	void			renderScaledPointGlobal( const LLVector3d& pos, const LLColor4U &color, F32 radius );
@@ -120,6 +126,16 @@ private:
 	LLUUID			mClosestAgentAtLastRightClick;
 
 	std::string		mToolTipMsg;
+
+public:
+	void			setSelected(uuid_vec_t uuids) { gmSelected=uuids; };
+
+private:
+	void handleZoom(const LLSD& userdata);
+	void handleStopTracking (const LLSD& userdata);
+
+	LLMenuGL*		mPopupMenu;
+	uuid_vec_t		gmSelected;
 };
 
 
diff --git a/indra/newview/llpanelpeople.cpp b/indra/newview/llpanelpeople.cpp
index 54198d6aa4..b07a46a222 100644
--- a/indra/newview/llpanelpeople.cpp
+++ b/indra/newview/llpanelpeople.cpp
@@ -54,6 +54,7 @@
 #include "llgroupactions.h"
 #include "llgrouplist.h"
 #include "llinventoryobserver.h"
+#include "llnetmap.h"
 #include "llpanelpeoplemenus.h"
 #include "llsidetray.h"
 #include "llsidetraypanelcontainer.h"
@@ -494,7 +495,8 @@ LLPanelPeople::LLPanelPeople()
 		mNearbyGearButton(NULL),
 		mFriendsGearButton(NULL),
 		mGroupsGearButton(NULL),
-		mRecentGearButton(NULL)
+		mRecentGearButton(NULL),
+		mMiniMap(NULL)
 {
 	mFriendListUpdater = new LLFriendListUpdater(boost::bind(&LLPanelPeople::updateFriendList,	this));
 	mNearbyListUpdater = new LLNearbyListUpdater(boost::bind(&LLPanelPeople::updateNearbyList,	this));
@@ -567,6 +569,9 @@ BOOL LLPanelPeople::postBuild()
 	mNearbyList->setNoItemsMsg(getString("no_one_near"));
 	mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near"));
 	mNearbyList->setShowIcons("NearbyListShowIcons");
+	mMiniMap = (LLNetMap*)getChildView("Net Map",true);
+	mMiniMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ? 
+		getString("AltMiniMapToolTipMsg") :	getString("MiniMapToolTipMsg"));
 
 	mRecentList = getChild<LLPanel>(RECENT_TAB_NAME)->getChild<LLAvatarList>("avatar_list");
 	mRecentList->setNoItemsCommentText(getString("no_recent_people"));
@@ -1088,6 +1093,12 @@ void LLPanelPeople::onAvatarListDoubleClicked(LLUICtrl* ctrl)
 
 void LLPanelPeople::onAvatarListCommitted(LLAvatarList* list)
 {
+	if (getActiveTabName() == NEARBY_TAB_NAME)
+	{
+		uuid_vec_t selected_uuids;
+		getCurrentItemIDs(selected_uuids);
+		mMiniMap->setSelected(selected_uuids);
+	} else
 	// Make sure only one of the friends lists (online/all) has selection.
 	if (getActiveTabName() == FRIENDS_TAB_NAME)
 	{
diff --git a/indra/newview/llpanelpeople.h b/indra/newview/llpanelpeople.h
index b496bb3779..46c58cd139 100644
--- a/indra/newview/llpanelpeople.h
+++ b/indra/newview/llpanelpeople.h
@@ -142,6 +142,7 @@ private:
 	LLAvatarList*			mNearbyList;
 	LLAvatarList*			mRecentList;
 	LLGroupList*			mGroupList;
+	LLNetMap*				mMiniMap;
 
 	LLHandle<LLView>		mGroupPlusMenuHandle;
 	LLHandle<LLView>		mNearbyViewSortMenuHandle;
diff --git a/indra/newview/skins/default/xui/en/floater_map.xml b/indra/newview/skins/default/xui/en/floater_map.xml
index 6370ff9243..ae99fa8dd5 100644
--- a/indra/newview/skins/default/xui/en/floater_map.xml
+++ b/indra/newview/skins/default/xui/en/floater_map.xml
@@ -22,7 +22,11 @@
      name="ToolTipMsg">
         [REGION](Double-click to open Map, shift-drag to pan)
     </floater.string>
-    <floater.string name="mini_map_caption">
+	<floater.string
+     name="AltToolTipMsg">
+		[REGION](Double-click to teleport, shift-drag to pan)
+	</floater.string>
+	<floater.string name="mini_map_caption">
 	MINIMAP
     </floater.string>
     <net_map
diff --git a/indra/newview/skins/default/xui/en/panel_people.xml b/indra/newview/skins/default/xui/en/panel_people.xml
index 6a8bf87bc5..43431ea7c1 100644
--- a/indra/newview/skins/default/xui/en/panel_people.xml
+++ b/indra/newview/skins/default/xui/en/panel_people.xml
@@ -54,7 +54,13 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
     <string
      name="no_groups_msg"
      value="Looking for Groups to join? Try [secondlife:///app/search/groups Search]." />
-    <filter_editor
+	<string
+	 name="MiniMapToolTipMsg"
+	 value="[REGION](Double-click to open Map, shift-drag to pan)"/>
+	<string
+	 name="AltMiniMapToolTipMsg"
+	 value="[REGION](Double-click to teleport, shift-drag to pan)"/>
+	<filter_editor
      follows="left|top|right"
      height="23"
      layout="topleft"
@@ -93,16 +99,26 @@ Looking for people to hang out with? Try the [secondlife:///app/worldmap World M
          name="nearby_panel"
          top="0"
          width="313">
-            <avatar_list
+			<net_map
+			 bg_color="NetMapBackgroundColor"
+			 follows="top|left|right"
+			 layout="topleft"
+			 left="3"
+			 mouse_opaque="false"
+			 name="Net Map"
+			 width="307"
+			 height="140"
+			 top="0"/>
+			<avatar_list
              allow_select="true"
-             follows="all"
-             height="356"
+             follows="top|left|bottom|right"
+             height="216"
              ignore_online_status="true"
              layout="topleft"
              left="3"
              multi_select="true"
              name="avatar_list"
-             top="0"
+             top="145"
              width="307" />
             <panel
              background_visible="true"
-- 
cgit v1.2.3


From 60696ae986c90068faa0191db737431493796dc1 Mon Sep 17 00:00:00 2001
From: "Andrew A. de Laix" <alain@lindenlab.com>
Date: Wed, 26 Jan 2011 16:31:15 -0800
Subject: fix for STORM-940: don't show manditory update dialog if already
 logged in.

---
 indra/newview/llappviewer.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index e92042bcd4..ace1de6131 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2474,10 +2474,14 @@ namespace {
 				// The user never saw the progress bar.
 				notification_name = "RequiredUpdateDownloadedVerboseDialog";
 			}
-			else
+			else if(LLStartUp::getStartupState() < STATE_WORLD_INIT)
 			{
 				notification_name = "RequiredUpdateDownloadedDialog";
 			}
+			else
+			{
+				; // Do nothing because user is already logged in.
+			}
 		}
 		else
 		{
-- 
cgit v1.2.3


From 9653c41d3d0532a323122b0cd1b6399721bf8be8 Mon Sep 17 00:00:00 2001
From: "Andrew A. de Laix" <alain@lindenlab.com>
Date: Thu, 27 Jan 2011 11:37:00 -0800
Subject: more for storm 940: treat the manditory download after login like an
 optional one.

---
 indra/newview/llappviewer.cpp | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index ace1de6131..9cc0ab377c 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2468,19 +2468,23 @@ namespace {
 
 		if(data["required"].asBoolean())
 		{
-			apply_callback = &apply_update_ok_callback;
 			if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT)
 			{
 				// The user never saw the progress bar.
+				apply_callback = &apply_update_ok_callback;
 				notification_name = "RequiredUpdateDownloadedVerboseDialog";
 			}
 			else if(LLStartUp::getStartupState() < STATE_WORLD_INIT)
 			{
+				// The user is logging in but blocked.
+				apply_callback = &apply_update_ok_callback;
 				notification_name = "RequiredUpdateDownloadedDialog";
 			}
 			else
 			{
-				; // Do nothing because user is already logged in.
+				// The user is already logged in; treat like an optional update.
+				apply_callback = &apply_update_callback;
+				notification_name = "DownloadBackgroundDialog";
 			}
 		}
 		else
-- 
cgit v1.2.3


From f18bfd446b5b9a9cf91bf8b615c651074ebe8596 Mon Sep 17 00:00:00 2001
From: "Andrew A. de Laix" <alain@lindenlab.com>
Date: Thu, 27 Jan 2011 11:37:59 -0800
Subject: STORM-940: use the tip, not the dialog.

---
 indra/newview/llappviewer.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 9cc0ab377c..9361ae20cf 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -2484,7 +2484,7 @@ namespace {
 			{
 				// The user is already logged in; treat like an optional update.
 				apply_callback = &apply_update_callback;
-				notification_name = "DownloadBackgroundDialog";
+				notification_name = "DownloadBackgroundTip";
 			}
 		}
 		else
-- 
cgit v1.2.3


From 055d79417482776bb7b1bfffe7468e2fc5fd92e1 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 11:43:08 -0800
Subject: Removed DRTVWR from 2.5.0-beta2 tag

---
 .hgtags | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.hgtags b/.hgtags
index 1e2e10eb97..5e831e278c 100644
--- a/.hgtags
+++ b/.hgtags
@@ -51,4 +51,4 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
 345b17e7cf630db77e840b4fe3451bd476d750a3 2.5.0-beta1
 345b17e7cf630db77e840b4fe3451bd476d750a3 76f586a8e22b
 0000000000000000000000000000000000000000 76f586a8e22b
-54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f DRTVWR-33--2.5.0beta2
+54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f 2.5.0-beta2
-- 
cgit v1.2.3


From 106c9124741afd50c3aaa5671743d5a939f1ad48 Mon Sep 17 00:00:00 2001
From: Eli Linden <eli@lindenlab.com>
Date: Thu, 27 Jan 2011 13:33:26 -0800
Subject: STORM-634 FIX missing Danish translation

---
 indra/newview/skins/default/xui/da/panel_people.xml | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/indra/newview/skins/default/xui/da/panel_people.xml b/indra/newview/skins/default/xui/da/panel_people.xml
index 599686d360..b85a33279a 100644
--- a/indra/newview/skins/default/xui/da/panel_people.xml
+++ b/indra/newview/skins/default/xui/da/panel_people.xml
@@ -1,23 +1,23 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
 <!-- Side tray panel -->
 <panel label="Personer" name="people_panel">
-	<string name="no_recent_people" value="Ingen tidligere personer. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Search] eller [secondlife:///app/worldmap World Map]."/>
-	<string name="no_filtered_recent_people" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Search]."/>
-	<string name="no_one_near" value="Ingen i nærheden. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Search] eller [secondlife:///app/worldmap World Map]."/>
-	<string name="no_one_filtered_near" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Search]."/>
+	<string name="no_recent_people" value="Ingen tidligere personer. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Søg] eller [secondlife:///app/worldmap Verdenskort]."/>
+	<string name="no_filtered_recent_people" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Søg]."/>
+	<string name="no_one_near" value="Ingen i nærheden. Leder du efter nogen at være sammen med? Prøv [secondlife:///app/search/people Søg] eller [secondlife:///app/worldmap Verdenskort]."/>
+	<string name="no_one_filtered_near" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Søg]."/>
 	<string name="no_friends_online" value="Ingen venner online"/>
 	<string name="no_friends" value="Ingen venner"/>
 	<string name="no_friends_msg">
-		Find venner via [secondlife:///app/search/people Search] eller højre-klik på en beboer og tilføj dem som venner.
-Leder du efter nogen at være sammen med? Prøv [secondlife:///app/worldmap World Map].
+		Find venner via [secondlife:///app/search/people Søg] eller højre-klik på en beboer og tilføj dem som venner.
+Leder du efter nogen at være sammen med? Prøv [secondlife:///app/worldmap Verdenskort].
 	</string>
 	<string name="no_filtered_friends_msg">
-		Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Search].
+		Fandt du ikke det du søgte? Prøv [secondlife:///app/search/people/[SEARCH_TERM] Søg].
 	</string>
 	<string name="people_filter_label" value="Filtrér personer"/>
 	<string name="groups_filter_label" value="Filtrér grupper"/>
-	<string name="no_filtered_groups_msg" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/groups/[SEARCH_TERM] Search]."/>
-	<string name="no_groups_msg" value="Leder du efter grupper at være med i? Prøv [secondlife:///app/search/groups Search]."/>
+	<string name="no_filtered_groups_msg" value="Fandt du ikke det du søgte? Prøv [secondlife:///app/search/groups/[SEARCH_TERM] Søg]."/>
+	<string name="no_groups_msg" value="Leder du efter grupper at være med i? Prøv [secondlife:///app/search/groups Søg]."/>
 	<filter_editor label="Filtrér" name="filter_input"/>
 	<tab_container name="tabs">
 		<panel label="TÆT PÅ" name="nearby_panel">
-- 
cgit v1.2.3


From 5b4aa6914473d331626eedeaa0b8c7b05be79231 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:40:14 -0800
Subject: Added tag DRTVWR-5_2.2.0-beta1 for changeset 7076e22f9f43

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 5e831e278c..4b29436ec5 100644
--- a/.hgtags
+++ b/.hgtags
@@ -52,3 +52,4 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
 345b17e7cf630db77e840b4fe3451bd476d750a3 76f586a8e22b
 0000000000000000000000000000000000000000 76f586a8e22b
 54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f 2.5.0-beta2
+7076e22f9f43f479a4ea75eac447a36364bead5a DRTVWR-5_2.2.0-beta1
-- 
cgit v1.2.3


From fd1b76d889b670b606e1c9f1c46404bc07aaf504 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:41:21 -0800
Subject: Added tag DRTVWR-3_2.2.0-beta2 for changeset 9822eb3e25f7

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 4b29436ec5..11bab1793d 100644
--- a/.hgtags
+++ b/.hgtags
@@ -53,3 +53,4 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
 0000000000000000000000000000000000000000 76f586a8e22b
 54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f 2.5.0-beta2
 7076e22f9f43f479a4ea75eac447a36364bead5a DRTVWR-5_2.2.0-beta1
+9822eb3e25f7fe0c28ffd8aba45c507caa383cbc DRTVWR-3_2.2.0-beta2
-- 
cgit v1.2.3


From 678234b01c1378858b753c8662428095355547d8 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:41:46 -0800
Subject: Added tag DRTVWR-7_2.2.0-beta3 for changeset b0cd7e150009

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 11bab1793d..18140976c9 100644
--- a/.hgtags
+++ b/.hgtags
@@ -54,3 +54,4 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
 54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f 2.5.0-beta2
 7076e22f9f43f479a4ea75eac447a36364bead5a DRTVWR-5_2.2.0-beta1
 9822eb3e25f7fe0c28ffd8aba45c507caa383cbc DRTVWR-3_2.2.0-beta2
+b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3
-- 
cgit v1.2.3


From 2b50e197aff420e2fcbeff94ee1baa4ce5c31d56 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:42:03 -0800
Subject: Added tag DRTVWR-8_2.2.0-release for changeset 1415e6538d54

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 18140976c9..614caa912f 100644
--- a/.hgtags
+++ b/.hgtags
@@ -55,3 +55,4 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
 7076e22f9f43f479a4ea75eac447a36364bead5a DRTVWR-5_2.2.0-beta1
 9822eb3e25f7fe0c28ffd8aba45c507caa383cbc DRTVWR-3_2.2.0-beta2
 b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3
+1415e6538d54fd5d568ee88343424d57c6803c2c DRTVWR-8_2.2.0-release
-- 
cgit v1.2.3


From 8a930fd6eb3cc4bd8f6ece49f145981c4b21d5cc Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:42:32 -0800
Subject: Added tag DRTVWR-14_2.3.0-beta1 for changeset a3c12342b1af

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 614caa912f..496527158e 100644
--- a/.hgtags
+++ b/.hgtags
@@ -56,3 +56,4 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
 9822eb3e25f7fe0c28ffd8aba45c507caa383cbc DRTVWR-3_2.2.0-beta2
 b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3
 1415e6538d54fd5d568ee88343424d57c6803c2c DRTVWR-8_2.2.0-release
+a3c12342b1af0951b8aa3b828aacef17fcea8178 DRTVWR-14_2.3.0-beta1
-- 
cgit v1.2.3


From c4ab18dfc308e94ef31e102da6304b956f4473c1 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:43:10 -0800
Subject: Added tag DRTVWR-17_2.3.0-beta2 for changeset db0fe9bb6518

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 496527158e..f92c7f9075 100644
--- a/.hgtags
+++ b/.hgtags
@@ -57,3 +57,4 @@ a82e5b1e22c7f90e3c7977d146b80588f004ed0d 2.5.0-start
 b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3
 1415e6538d54fd5d568ee88343424d57c6803c2c DRTVWR-8_2.2.0-release
 a3c12342b1af0951b8aa3b828aacef17fcea8178 DRTVWR-14_2.3.0-beta1
+db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2
-- 
cgit v1.2.3


From b017a54858b6174e4068407bedf969d253b63ed2 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:43:49 -0800
Subject: Added tag DRTVWR-20_2.3.0-beta3 for changeset 6ad3d6fa35a4

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index f92c7f9075..dd94e69458 100644
--- a/.hgtags
+++ b/.hgtags
@@ -58,3 +58,4 @@ b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3
 1415e6538d54fd5d568ee88343424d57c6803c2c DRTVWR-8_2.2.0-release
 a3c12342b1af0951b8aa3b828aacef17fcea8178 DRTVWR-14_2.3.0-beta1
 db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2
+6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-20_2.3.0-beta3
-- 
cgit v1.2.3


From 75978a3c84bd47d2e5f65f5f83f4a5f09e2d5fd0 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:44:05 -0800
Subject: Added tag DRTVWR-13_2.3.0-release for changeset 6ad3d6fa35a4

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index dd94e69458..6ec535cb1b 100644
--- a/.hgtags
+++ b/.hgtags
@@ -59,3 +59,4 @@ b0cd7e150009809a0b5b0a9d5785cd4bb230413a DRTVWR-7_2.2.0-beta3
 a3c12342b1af0951b8aa3b828aacef17fcea8178 DRTVWR-14_2.3.0-beta1
 db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2
 6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-20_2.3.0-beta3
+6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-13_2.3.0-release
-- 
cgit v1.2.3


From 9ff19020bbbdad7a1647b7c0d1268a4d3c697212 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:44:23 -0800
Subject: Added tag DRTVWR-26_2.4.0-beta1 for changeset 3bc1f50a72e1

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 6ec535cb1b..16a967bbe3 100644
--- a/.hgtags
+++ b/.hgtags
@@ -60,3 +60,4 @@ a3c12342b1af0951b8aa3b828aacef17fcea8178 DRTVWR-14_2.3.0-beta1
 db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2
 6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-20_2.3.0-beta3
 6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-13_2.3.0-release
+3bc1f50a72e117f4d4ad8d555f0c785ea8cc201e DRTVWR-26_2.4.0-beta1
-- 
cgit v1.2.3


From 8f7bc74e0ef1b5e428cdc4bef0d075b0bd00bded Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:44:40 -0800
Subject: Added tag DRTVWR-27_2.4.0-beta2 for changeset 25bd6007e3d2

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 16a967bbe3..4947c11ae0 100644
--- a/.hgtags
+++ b/.hgtags
@@ -61,3 +61,4 @@ db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2
 6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-20_2.3.0-beta3
 6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-13_2.3.0-release
 3bc1f50a72e117f4d4ad8d555f0c785ea8cc201e DRTVWR-26_2.4.0-beta1
+25bd6007e3d2fc15db9326ed4b18a24a5969a46a DRTVWR-27_2.4.0-beta2
-- 
cgit v1.2.3


From b356c9f0e5b3da0ab5e7f46425ea8d40cad076d2 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:44:57 -0800
Subject: Added tag DRTVWR-25_2.4.0-release for changeset 1ed382c6a08b

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 4947c11ae0..072d066e29 100644
--- a/.hgtags
+++ b/.hgtags
@@ -62,3 +62,4 @@ db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2
 6ad3d6fa35a4e320e9ce442fce2bf9c7fc852556 DRTVWR-13_2.3.0-release
 3bc1f50a72e117f4d4ad8d555f0c785ea8cc201e DRTVWR-26_2.4.0-beta1
 25bd6007e3d2fc15db9326ed4b18a24a5969a46a DRTVWR-27_2.4.0-beta2
+1ed382c6a08ba3850b6ce9061bc551ddece0ea07 DRTVWR-25_2.4.0-release
-- 
cgit v1.2.3


From 17232a83b1ea13bd4c4ab39e166587c09d529e6a Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:45:14 -0800
Subject: Added tag DRTVWR-32_2.5.0-beta1 for changeset 345b17e7cf63

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index 072d066e29..a1b00f252c 100644
--- a/.hgtags
+++ b/.hgtags
@@ -63,3 +63,4 @@ db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2
 3bc1f50a72e117f4d4ad8d555f0c785ea8cc201e DRTVWR-26_2.4.0-beta1
 25bd6007e3d2fc15db9326ed4b18a24a5969a46a DRTVWR-27_2.4.0-beta2
 1ed382c6a08ba3850b6ce9061bc551ddece0ea07 DRTVWR-25_2.4.0-release
+345b17e7cf630db77e840b4fe3451bd476d750a3 DRTVWR-32_2.5.0-beta1
-- 
cgit v1.2.3


From 7b7e9b0d0bd9c35acb346ae359f9a08a48b248a2 Mon Sep 17 00:00:00 2001
From: Dessie Linden <dessie@lindenlab.com>
Date: Thu, 27 Jan 2011 14:45:42 -0800
Subject: Added tag DRTVWR-33_2.5.0-beta2 for changeset 54d772d8687c

---
 .hgtags | 1 +
 1 file changed, 1 insertion(+)

diff --git a/.hgtags b/.hgtags
index a1b00f252c..a3eee211fc 100644
--- a/.hgtags
+++ b/.hgtags
@@ -64,3 +64,4 @@ db0fe9bb65187f365e58a717dd23d0f4754a9c1d DRTVWR-17_2.3.0-beta2
 25bd6007e3d2fc15db9326ed4b18a24a5969a46a DRTVWR-27_2.4.0-beta2
 1ed382c6a08ba3850b6ce9061bc551ddece0ea07 DRTVWR-25_2.4.0-release
 345b17e7cf630db77e840b4fe3451bd476d750a3 DRTVWR-32_2.5.0-beta1
+54d772d8687c69b1d773f6ce14bbc7bdc9d6c05f DRTVWR-33_2.5.0-beta2
-- 
cgit v1.2.3


From 38dceba9b4a1faa386d377a20080a590ea20cbdb Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Fri, 28 Jan 2011 11:17:18 -0800
Subject: STORM-927 - FIX - [VWR-24426] SSL Handshake Failed Error when
 accessing web-based content on development viewers using recent Webkit 4.7
 Also removed refs to debug vars used to specify location of pem file

---
 indra/newview/app_settings/settings.xml | 22 ----------------------
 indra/newview/llviewermedia.cpp         | 21 +++++++++++----------
 2 files changed, 11 insertions(+), 32 deletions(-)

diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index ef6f8fd3ee..ca587302b2 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -697,28 +697,6 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>BrowserUseDefaultCAFile</key>
-    <map>
-      <key>Comment</key>
-      <string>Tell the built-in web browser to use the CA.pem file shipped with the client.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
-    <key>BrowserCAFilePath</key>
-    <map>
-      <key>Comment</key>
-      <string>Tell the built-in web browser the path to an alternative CA.pem file (only used if BrowserUseDefaultCAFile is false).</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>String</string>
-      <key>Value</key>
-      <string></string>
-    </map>  
     <key>BlockAvatarAppearanceMessages</key>
         <map>
         <key>Comment</key>
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index d3b6dcd86f..433151860c 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -1828,16 +1828,17 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
 			media_source->ignore_ssl_cert_errors(true);
 		}
 
-		// start by assuming the default CA file will be used
-		std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "lindenlab.pem" );
-	
-		// default turned off so pick up the user specified path
-		if( ! gSavedSettings.getBOOL("BrowserUseDefaultCAFile"))
-		{
-			ca_path = gSavedSettings.getString("BrowserCAFilePath");
-		}
-		// set the path to the CA.pem file
-		media_source->addCertificateFilePath( ca_path );
+		// NOTE: Removed as per STORM-927 - SSL handshake failed - setting local self-signed certs like this 
+		//       seems to screw things up big time. For now, devs will need to add these certs locally and Qt will pick them up.
+//		// start by assuming the default CA file will be used
+//		std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "lindenlab.pem" );
+//		// default turned off so pick up the user specified path
+//		if( ! gSavedSettings.getBOOL("BrowserUseDefaultCAFile"))
+//		{
+//			ca_path = gSavedSettings.getString("BrowserCAFilePath");
+//		}
+//		// set the path to the CA.pem file
+//		media_source->addCertificateFilePath( ca_path );
 
 		media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));
 		
-- 
cgit v1.2.3


From ac7d7fea8288b1d6f5dec65f9dee5053d097fff5 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Fri, 28 Jan 2011 11:18:11 -0800
Subject: SOCIAL-452 FIX Default size of Web content floater is wrong - needs
 to be optimized for Web profile display

---
 .../newview/skins/default/xui/en/floater_web_content.xml | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/indra/newview/skins/default/xui/en/floater_web_content.xml b/indra/newview/skins/default/xui/en/floater_web_content.xml
index 1c64a5eb44..456b2d4421 100644
--- a/indra/newview/skins/default/xui/en/floater_web_content.xml
+++ b/indra/newview/skins/default/xui/en/floater_web_content.xml
@@ -12,7 +12,7 @@
   auto_tile="true"
   title=""
   initial_mime_type="text/html"
-  width="735">
+  width="780">
   <layout_stack
     bottom="775"
     follows="left|right|top|bottom"
@@ -21,7 +21,7 @@
     name="stack1"
     orientation="vertical"
     top="20"
-    width="725">
+    width="770">
     <layout_panel
       auto_resize="false"
       default_tab_group="1"
@@ -32,7 +32,7 @@
       name="nav_controls"
       top="400"
       user_resize="false"
-      width="725">
+      width="770">
       <button
         image_overlay="Arrow_Left_Off"
 		    image_disabled="PushButton_Disabled"
@@ -115,7 +115,7 @@
         combo_editor.select_on_focus="true"
         tool_tip="Enter URL here"
         top_delta="0"
-        width="627">
+        width="672">
         <combo_box.commit_callback
           function="WebContent.EnterAddress" />
       </combo_box>
@@ -125,7 +125,7 @@
         follows="top|right"
         image_name="Lock2"
         layout="topleft"
-        left_delta="575"
+        left_delta="620"
         top_delta="2"
         visible="false" 
         tool_tip="Secured Browsing"
@@ -142,7 +142,7 @@
         height="22"
         layout="topleft"
         name="popexternal"
-        right="725"
+        right="770"
         top_delta="-2"
         width="22">
         <button.commit_callback
@@ -156,7 +156,7 @@
       name="external_controls"
       top_delta="0"
       user_resize="false"
-      width="540">
+      width="585">
       <web_browser
         bottom="-22"
         follows="all"
@@ -175,7 +175,7 @@
         parse_urls="false"
         text_color="0.4 0.4 0.4 1"
         top_pad="5"
-        width="520"/>
+        width="495"/>
       <progress_bar
         color_bar="0.3 1.0 0.3 1"
         follows="bottom|right"
-- 
cgit v1.2.3


From d2b13de633b4719bf61e2905699dd1bb67ae0c36 Mon Sep 17 00:00:00 2001
From: callum <none@none>
Date: Fri, 28 Jan 2011 15:57:42 -0800
Subject: STORM-934 POSSIBLE FIX [crashhunters] crash at [2]
 LLPanelAvatarProfile::got_full_name_callback(LLUUID const
 &,std::basic_string,std::allocator > const &,bool) [secondlife-bin
 llpanelavatar.cpp]

---
 indra/newview/llpanelavatar.cpp                      | 20 +++++++++++++-------
 indra/newview/llpanelavatar.h                        |  1 -
 indra/newview/skins/default/xui/en/panel_profile.xml |  8 ++++++++
 3 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 94b2340c93..8a917a082c 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -625,8 +625,13 @@ void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_g
 	getChild<LLUICtrl>("sl_groups")->setValue(groups);
 }
 
-void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group )
-{
+static void got_full_name_callback( LLHandle<LLPanel> profile_panel_handle, const std::string& full_name )
+{
+	if (profile_panel_handle.isDead() ) return;
+
+	LLPanelAvatarProfile* profile_panel = dynamic_cast<LLPanelAvatarProfile*>(profile_panel_handle.get());
+	if ( ! profile_panel ) return;
+
 	LLStringUtil::format_map_t args;
 
 	std::string name;
@@ -641,9 +646,9 @@ void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std::
 
 	args["[NAME]"] = name;
 
-	std::string linden_name = getString("name_text_args", args);
-	getChild<LLUICtrl>("name_descr_text")->setValue(linden_name);
-}
+	std::string linden_name = profile_panel->getString("name_text_args", args);
+	profile_panel->getChild<LLUICtrl>("name_descr_text")->setValue(linden_name);
+}
 
 void LLPanelAvatarProfile::onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
 {
@@ -667,16 +672,17 @@ void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data)
 	}
 
 	// ask (asynchronously) for the avatar name
+	LLHandle<LLPanel> profile_panel_handle = getHandle();
 	std::string full_name;
 	if (gCacheName->getFullName(avatar_data->agent_id, full_name))
 	{
 		// name in cache, call callback directly
-		got_full_name_callback( avatar_data->agent_id, full_name, false );
+		got_full_name_callback( profile_panel_handle, full_name );
 	}
 	else
 	{
 		// not in cache, lookup name 
-		gCacheName->get(avatar_data->agent_id, false, boost::bind( &LLPanelAvatarProfile::got_full_name_callback, this, _1, _2, _3 ));
+		gCacheName->get(avatar_data->agent_id, false, boost::bind( got_full_name_callback, profile_panel_handle, _2 ));
 	}
 
 	// get display name
diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h
index 070fe4579a..b8cb62db43 100644
--- a/indra/newview/llpanelavatar.h
+++ b/indra/newview/llpanelavatar.h
@@ -209,7 +209,6 @@ protected:
 	void onShareButtonClick();
 
 private:
-	void got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group );
 	void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
 
 	typedef std::map< std::string,LLUUID>	group_map_t;
diff --git a/indra/newview/skins/default/xui/en/panel_profile.xml b/indra/newview/skins/default/xui/en/panel_profile.xml
index 61e3bb354f..d36220385d 100644
--- a/indra/newview/skins/default/xui/en/panel_profile.xml
+++ b/indra/newview/skins/default/xui/en/panel_profile.xml
@@ -34,6 +34,14 @@
 	 name="RegisterDateFormat">
 	 [REG_DATE] ([AGE])
 	</string>
+  <string
+  name="name_text_args">
+    [NAME]
+  </string>
+  <string
+    name="display_name_text_args">
+    [DISPLAY_NAME]
+  </string>
     <layout_stack
      name="layout"
      orientation="vertical"
-- 
cgit v1.2.3


From 2ca05d499633ab75aec84405314c1afda23512e2 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Fri, 28 Jan 2011 17:01:18 -0700
Subject: trivial: convert to "unix return"

---
 indra/llcommon/llmemory.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp
index f340105f57..51fcd5b717 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -114,7 +114,7 @@ U32 LLMemory::getWorkingSetSize()
 {
     PROCESS_MEMORY_COUNTERS pmc ;
 	U32 ret = 0 ;
-
+
     if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) )
 	{
 		ret = pmc.WorkingSetSize ;
-- 
cgit v1.2.3


From c111288a23825de8e00d252f98652c362a054251 Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Fri, 28 Jan 2011 17:19:42 -0700
Subject: fixed the major memory leaking for SH-723/SH-847: memoy leaking

---
 indra/newview/llfirstuse.cpp | 58 +++++++++++++++++++++++++-------------------
 indra/newview/llfirstuse.h   |  9 ++++---
 2 files changed, 38 insertions(+), 29 deletions(-)

diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index 4c17199895..4d252dc662 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -41,35 +41,36 @@
 
 
 // static
-std::set<std::string> LLFirstUse::sConfigVariables;
+//std::set<std::string> LLFirstUse::sConfigVariables;
+std::set<std::string> LLFirstUse::sConfigVariablesEnabled;
 
 // static
-void LLFirstUse::addConfigVariable(const std::string& var)
-{
-	sConfigVariables.insert(var);
-}
+//void LLFirstUse::addConfigVariable(const std::string& var)
+//{
+//	sConfigVariables.insert(var);
+//}
 
 // static
-void LLFirstUse::disableFirstUse()
-{
-	// Set all first-use warnings to disabled
-	for (std::set<std::string>::iterator iter = sConfigVariables.begin();
-		 iter != sConfigVariables.end(); ++iter)
-	{
-		gWarningSettings.setBOOL(*iter, FALSE);
-	}
-}
+//void LLFirstUse::disableFirstUse()
+//{
+//	// Set all first-use warnings to disabled
+//	for (std::set<std::string>::iterator iter = sConfigVariables.begin();
+//		 iter != sConfigVariables.end(); ++iter)
+//	{
+//		gWarningSettings.setBOOL(*iter, FALSE);
+//	}
+//}
 
 // static
-void LLFirstUse::resetFirstUse()
-{
-	// Set all first-use warnings to disabled
-	for (std::set<std::string>::iterator iter = sConfigVariables.begin();
-		 iter != sConfigVariables.end(); ++iter)
-	{
-		gWarningSettings.setBOOL(*iter, TRUE);
-	}
-}
+//void LLFirstUse::resetFirstUse()
+//{
+//	// Set all first-use warnings to disabled
+//	for (std::set<std::string>::iterator iter = sConfigVariables.begin();
+//		 iter != sConfigVariables.end(); ++iter)
+//	{
+//		gWarningSettings.setBOOL(*iter, TRUE);
+//	}
+//}
 
 // static
 void LLFirstUse::otherAvatarChatFirst(bool enable)
@@ -151,13 +152,21 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl
 
 	if (enable)
 	{
+		if(sConfigVariablesEnabled.find(control_var) != sConfigVariablesEnabled.end())
+		{
+			return ; //already added
+		}
+
 		if (gSavedSettings.getBOOL("EnableUIHints"))
 		{
 			LL_DEBUGS("LLFirstUse") << "Trigger first use notification " << notification_name << LL_ENDL;
 
 			// if notification doesn't already exist and this notification hasn't been disabled...
 			if (gWarningSettings.getBOOL(control_var))
-			{ // create new notification
+			{ 
+				sConfigVariablesEnabled.insert(control_var) ;
+
+				// create new notification
 				LLNotifications::instance().add(LLNotification::Params().name(notification_name).substitutions(args).payload(payload.with("control_var", control_var)));
 			}
 		}
@@ -169,7 +178,6 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl
 		// redundantly clear settings var here, in case there are no notifications to cancel
 		gWarningSettings.setBOOL(control_var, FALSE);
 	}
-
 }
 
 // static
diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h
index 81659988e6..489f58626a 100644
--- a/indra/newview/llfirstuse.h
+++ b/indra/newview/llfirstuse.h
@@ -78,11 +78,11 @@ class LLFirstUse
 public:
 
 	// Add a config variable to be reset on resetFirstUse()
-	static void addConfigVariable(const std::string& var);
+	//static void addConfigVariable(const std::string& var);
 	
 	// Sets all controls back to show the dialogs.
-	static void disableFirstUse();
-	static void resetFirstUse();
+	//static void disableFirstUse();
+	//static void resetFirstUse();
 
 	static void otherAvatarChatFirst(bool enable = true);
 	static void sit(bool enable = true);
@@ -98,7 +98,8 @@ public:
 	
 protected:
 	static void firstUseNotification(const std::string& control_var, bool enable, const std::string& notification_name, LLSD args = LLSD(), LLSD payload = LLSD());
-	static std::set<std::string> sConfigVariables;
+	//static std::set<std::string> sConfigVariables;
+	static std::set<std::string> sConfigVariablesEnabled;
 
 	static void init();
 	static bool processNotification(const LLSD& notify);
-- 
cgit v1.2.3


From 948afb8ef436f661dd84e3c343e22934f92570ec Mon Sep 17 00:00:00 2001
From: Xiaohong Bao <bao@lindenlab.com>
Date: Fri, 28 Jan 2011 21:23:19 -0700
Subject: trivial: remove some debug code.

---
 indra/newview/llappviewer.cpp | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 87c0085226..69333ff4a3 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1057,8 +1057,6 @@ bool LLAppViewer::mainLoop()
 		//clear call stack records
 		llclearcallstacks;
 
-		MEM_TRACK
-
 		//check memory availability information
 		{
 			if(memory_check_interval < memCheckTimer.getElapsedTimeF32())
@@ -1103,8 +1101,6 @@ bool LLAppViewer::mainLoop()
 			}
 			
 #endif
-			MEM_TRACK
-
 			//memory leaking simulation
 			LLFloaterMemLeak* mem_leak_instance =
 				LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
@@ -1166,8 +1162,6 @@ bool LLAppViewer::mainLoop()
 					resumeMainloopTimeout();
 				}
  
-				MEM_TRACK
-
 				if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
 				{
 					pauseMainloopTimeout();
@@ -1189,8 +1183,6 @@ bool LLAppViewer::mainLoop()
 
 			}
 
-			MEM_TRACK
-
 			pingMainloopTimeout("Main:Sleep");
 			
 			pauseMainloopTimeout();
@@ -1305,9 +1297,6 @@ bool LLAppViewer::mainLoop()
 	
 				pingMainloopTimeout("Main:End");
 			}	
-
-			MEM_TRACK
-
 		}
 		catch(std::bad_alloc)
 		{			
-- 
cgit v1.2.3


From 2e2d990eb10d101982b4f1915780a49615b55d6e Mon Sep 17 00:00:00 2001
From: Oz Linden <oz@lindenlab.com>
Date: Sat, 29 Jan 2011 13:09:55 -0500
Subject: correct DOS line endings

---
 indra/newview/llpanelavatar.cpp  |   62 +-
 indra/newview/llpanelavatar.h    |  596 ++--
 indra/newview/lltexturefetch.cpp | 6022 +++++++++++++++++++-------------------
 3 files changed, 3340 insertions(+), 3340 deletions(-)

diff --git a/indra/newview/llpanelavatar.cpp b/indra/newview/llpanelavatar.cpp
index 94b2340c93..53529b9f8b 100644
--- a/indra/newview/llpanelavatar.cpp
+++ b/indra/newview/llpanelavatar.cpp
@@ -625,10 +625,10 @@ void LLPanelAvatarProfile::processGroupProperties(const LLAvatarGroups* avatar_g
 	getChild<LLUICtrl>("sl_groups")->setValue(groups);
 }
 
-void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group )
-{
-	LLStringUtil::format_map_t args;
-
+void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group )
+{
+	LLStringUtil::format_map_t args;
+
 	std::string name;
 	if (LLAvatarNameCache::useDisplayNames())
 	{
@@ -637,21 +637,21 @@ void LLPanelAvatarProfile::got_full_name_callback( const LLUUID& id, const std::
 	else
 	{
 		name = full_name;
-	}
-
-	args["[NAME]"] = name;
-
-	std::string linden_name = getString("name_text_args", args);
-	getChild<LLUICtrl>("name_descr_text")->setValue(linden_name);
-}
+	}
+
+	args["[NAME]"] = name;
+
+	std::string linden_name = getString("name_text_args", args);
+	getChild<LLUICtrl>("name_descr_text")->setValue(linden_name);
+}
 
 void LLPanelAvatarProfile::onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name)
 {
-	LLStringUtil::format_map_t args;
-	args["[DISPLAY_NAME]"] = av_name.mDisplayName;
-
-	std::string display_name = getString("display_name_text_args", args);
-	getChild<LLUICtrl>("display_name_descr_text")->setValue(display_name);
+	LLStringUtil::format_map_t args;
+	args["[DISPLAY_NAME]"] = av_name.mDisplayName;
+
+	std::string display_name = getString("display_name_text_args", args);
+	getChild<LLUICtrl>("display_name_descr_text")->setValue(display_name);
 }
 
 void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data)
@@ -667,22 +667,22 @@ void LLPanelAvatarProfile::fillCommonData(const LLAvatarData* avatar_data)
 	}
 
 	// ask (asynchronously) for the avatar name
-	std::string full_name;
-	if (gCacheName->getFullName(avatar_data->agent_id, full_name))
-	{
-		// name in cache, call callback directly
-		got_full_name_callback( avatar_data->agent_id, full_name, false );
-	}
-	else
-	{
-		// not in cache, lookup name 
-		gCacheName->get(avatar_data->agent_id, false, boost::bind( &LLPanelAvatarProfile::got_full_name_callback, this, _1, _2, _3 ));
-	}
-
-	// get display name
+	std::string full_name;
+	if (gCacheName->getFullName(avatar_data->agent_id, full_name))
+	{
+		// name in cache, call callback directly
+		got_full_name_callback( avatar_data->agent_id, full_name, false );
+	}
+	else
+	{
+		// not in cache, lookup name 
+		gCacheName->get(avatar_data->agent_id, false, boost::bind( &LLPanelAvatarProfile::got_full_name_callback, this, _1, _2, _3 ));
+	}
+
+	// get display name
 	LLAvatarNameCache::get(avatar_data->avatar_id,
-		boost::bind(&LLPanelAvatarProfile::onNameCache, this, _1, _2));
-
+		boost::bind(&LLPanelAvatarProfile::onNameCache, this, _1, _2));
+
 	args["[AGE]"] = LLDateUtil::ageFromDate( avatar_data->born_on, LLDate::now());
 	std::string register_date = getString("RegisterDateFormat", args);
 	getChild<LLUICtrl>("register_date")->setValue(register_date );
diff --git a/indra/newview/llpanelavatar.h b/indra/newview/llpanelavatar.h
index 070fe4579a..5f36d1026f 100644
--- a/indra/newview/llpanelavatar.h
+++ b/indra/newview/llpanelavatar.h
@@ -1,298 +1,298 @@
-/** 
- * @file llpanelavatar.h
- * @brief LLPanelAvatar and related class definitions
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPANELAVATAR_H
-#define LL_LLPANELAVATAR_H
-
-#include "llpanel.h"
-#include "llavatarpropertiesprocessor.h"
-#include "llcallingcard.h"
-#include "llvoiceclient.h"
-#include "llavatarnamecache.h"
-
-class LLComboBox;
-class LLLineEditor;
-
-enum EOnlineStatus
-{
-	ONLINE_STATUS_NO      = 0,
-	ONLINE_STATUS_YES     = 1
-};
-
-/**
-* Base class for any Profile View or My Profile Panel.
-*/
-class LLPanelProfileTab
-	: public LLPanel
-	, public LLAvatarPropertiesObserver
-{
-public:
-
-	/**
-	 * Sets avatar ID, sets panel as observer of avatar related info replies from server.
-	 */
-	virtual void setAvatarId(const LLUUID& id);
-
-	/**
-	 * Returns avatar ID.
-	 */
-	virtual const LLUUID& getAvatarId() { return mAvatarId; }
-
-	/**
-	 * Sends update data request to server.
-	 */
-	virtual void updateData() = 0;
-
-	/**
-	 * Clears panel data if viewing avatar info for first time and sends update data request.
-	 */
-	virtual void onOpen(const LLSD& key);
-
-	/**
-	 * Profile tabs should close any opened panels here.
-	 *
-	 * Called from LLPanelProfile::onOpen() before opening new profile.
-	 * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel
-	 * before new profile is displayed, otherwise new profile will 
-	 * be hidden behind picture info panel.
-	 */
-	virtual void onClosePanel() {}
-
-	/**
-	 * Resets controls visibility, state, etc.
-	 */
-	virtual void resetControls(){};
-
-	/**
-	 * Clears all data received from server.
-	 */
-	virtual void resetData(){};
-
-	/*virtual*/ ~LLPanelProfileTab();
-
-protected:
-
-	LLPanelProfileTab();
-
-	/**
-	 * Scrolls panel to top when viewing avatar info for first time.
-	 */
-	void scrollToTop();
-
-	virtual void onMapButtonClick();
-
-	virtual void updateButtons();
-
-private:
-
-	LLUUID mAvatarId;
-};
-
-/**
-* Panel for displaying Avatar's first and second life related info.
-*/
-class LLPanelAvatarProfile
-	: public LLPanelProfileTab
-	, public LLFriendObserver
-	, public LLVoiceClientStatusObserver
-{
-public:
-	LLPanelAvatarProfile();
-	/*virtual*/ ~LLPanelAvatarProfile();
-
-	/*virtual*/ void onOpen(const LLSD& key);
-
-	/**
-	 * LLFriendObserver trigger
-	 */
-	virtual void changed(U32 mask);
-
-	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
-	// button when voice is available
-	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
-
-	/*virtual*/ void setAvatarId(const LLUUID& id);
-
-	/**
-	 * Processes data received from server.
-	 */
-	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
-
-	/*virtual*/ BOOL postBuild();
-
-	/*virtual*/ void updateData();
-
-	/*virtual*/ void resetControls();
-
-	/*virtual*/ void resetData();
-
-protected:
-
-	/**
-	 * Process profile related data received from server.
-	 */
-	virtual void processProfileProperties(const LLAvatarData* avatar_data);
-
-	/**
-	 * Processes group related data received from server.
-	 */
-	virtual void processGroupProperties(const LLAvatarGroups* avatar_groups);
-
-	/**
-	 * Fills common for Avatar profile and My Profile fields.
-	 */
-	virtual void fillCommonData(const LLAvatarData* avatar_data);
-
-	/**
-	 * Fills partner data.
-	 */
-	virtual void fillPartnerData(const LLAvatarData* avatar_data);
-
-	/**
-	 * Fills account status.
-	 */
-	virtual void fillAccountStatus(const LLAvatarData* avatar_data);
-
-	/**
-	 * Opens "Pay Resident" dialog.
-	 */
-	void pay();
-
-	/**
-	 * opens inventory and IM for sharing items
-	 */
-	void share();
-
-	/**
-	 * Add/remove resident to/from your block list.
-	 */
-	void toggleBlock();
-
-	void kick();
-	void freeze();
-	void unfreeze();
-	void csr();
-	
-	bool enableShowOnMap();
-	bool enableBlock();
-	bool enableUnblock();
-	bool enableGod();
-
-	void onSeeProfileBtnClick();
-	void onAddFriendButtonClick();
-	void onIMButtonClick();
-	void onCallButtonClick();
-	void onTeleportButtonClick();
-	void onShareButtonClick();
-
-private:
-	void got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group );
-	void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
-
-	typedef std::map< std::string,LLUUID>	group_map_t;
-	group_map_t 			mGroups;
-};
-
-/**
- * Panel for displaying own first and second life related info.
- */
-class LLPanelMyProfile
-	: public LLPanelAvatarProfile
-{
-public:
-	LLPanelMyProfile();
-
-	/*virtual*/ BOOL postBuild();
-
-protected:
-
-	/*virtual*/ void onOpen(const LLSD& key);
-
-	/*virtual*/ void processProfileProperties(const LLAvatarData* avatar_data);
-
-	/*virtual*/ void resetControls();
-
-protected:
-	void onStatusMessageChanged();
-};
-
-/**
- * Panel for displaying Avatar's notes and modifying friend's rights.
- */
-class LLPanelAvatarNotes 
-	: public LLPanelProfileTab
-	, public LLFriendObserver
-	, public LLVoiceClientStatusObserver
-{
-public:
-	LLPanelAvatarNotes();
-	/*virtual*/ ~LLPanelAvatarNotes();
-
-	virtual void setAvatarId(const LLUUID& id);
-
-	/** 
-	 * LLFriendObserver trigger
-	 */
-	virtual void changed(U32 mask);
-
-	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
-	// button when voice is available
-	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
-
-	/*virtual*/ void onOpen(const LLSD& key);
-
-	/*virtual*/ BOOL postBuild();
-
-	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
-
-	/*virtual*/ void updateData();
-
-protected:
-
-	/*virtual*/ void resetControls();
-
-	/*virtual*/ void resetData();
-
-	/**
-	 * Fills rights data for friends.
-	 */
-	void fillRightsData();
-
-	void rightsConfirmationCallback(const LLSD& notification,
-			const LLSD& response, S32 rights);
-	void confirmModifyRights(bool grant, S32 rights);
-	void onCommitRights();
-	void onCommitNotes();
-
-	void onAddFriendButtonClick();
-	void onIMButtonClick();
-	void onCallButtonClick();
-	void onTeleportButtonClick();
-	void onShareButtonClick();
-	void enableCheckboxes(bool enable);
-};
-
-#endif // LL_LLPANELAVATAR_H
+/** 
+ * @file llpanelavatar.h
+ * @brief LLPanelAvatar and related class definitions
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPANELAVATAR_H
+#define LL_LLPANELAVATAR_H
+
+#include "llpanel.h"
+#include "llavatarpropertiesprocessor.h"
+#include "llcallingcard.h"
+#include "llvoiceclient.h"
+#include "llavatarnamecache.h"
+
+class LLComboBox;
+class LLLineEditor;
+
+enum EOnlineStatus
+{
+	ONLINE_STATUS_NO      = 0,
+	ONLINE_STATUS_YES     = 1
+};
+
+/**
+* Base class for any Profile View or My Profile Panel.
+*/
+class LLPanelProfileTab
+	: public LLPanel
+	, public LLAvatarPropertiesObserver
+{
+public:
+
+	/**
+	 * Sets avatar ID, sets panel as observer of avatar related info replies from server.
+	 */
+	virtual void setAvatarId(const LLUUID& id);
+
+	/**
+	 * Returns avatar ID.
+	 */
+	virtual const LLUUID& getAvatarId() { return mAvatarId; }
+
+	/**
+	 * Sends update data request to server.
+	 */
+	virtual void updateData() = 0;
+
+	/**
+	 * Clears panel data if viewing avatar info for first time and sends update data request.
+	 */
+	virtual void onOpen(const LLSD& key);
+
+	/**
+	 * Profile tabs should close any opened panels here.
+	 *
+	 * Called from LLPanelProfile::onOpen() before opening new profile.
+	 * See LLPanelPicks::onClosePanel for example. LLPanelPicks closes picture info panel
+	 * before new profile is displayed, otherwise new profile will 
+	 * be hidden behind picture info panel.
+	 */
+	virtual void onClosePanel() {}
+
+	/**
+	 * Resets controls visibility, state, etc.
+	 */
+	virtual void resetControls(){};
+
+	/**
+	 * Clears all data received from server.
+	 */
+	virtual void resetData(){};
+
+	/*virtual*/ ~LLPanelProfileTab();
+
+protected:
+
+	LLPanelProfileTab();
+
+	/**
+	 * Scrolls panel to top when viewing avatar info for first time.
+	 */
+	void scrollToTop();
+
+	virtual void onMapButtonClick();
+
+	virtual void updateButtons();
+
+private:
+
+	LLUUID mAvatarId;
+};
+
+/**
+* Panel for displaying Avatar's first and second life related info.
+*/
+class LLPanelAvatarProfile
+	: public LLPanelProfileTab
+	, public LLFriendObserver
+	, public LLVoiceClientStatusObserver
+{
+public:
+	LLPanelAvatarProfile();
+	/*virtual*/ ~LLPanelAvatarProfile();
+
+	/*virtual*/ void onOpen(const LLSD& key);
+
+	/**
+	 * LLFriendObserver trigger
+	 */
+	virtual void changed(U32 mask);
+
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
+	/*virtual*/ void setAvatarId(const LLUUID& id);
+
+	/**
+	 * Processes data received from server.
+	 */
+	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
+
+	/*virtual*/ BOOL postBuild();
+
+	/*virtual*/ void updateData();
+
+	/*virtual*/ void resetControls();
+
+	/*virtual*/ void resetData();
+
+protected:
+
+	/**
+	 * Process profile related data received from server.
+	 */
+	virtual void processProfileProperties(const LLAvatarData* avatar_data);
+
+	/**
+	 * Processes group related data received from server.
+	 */
+	virtual void processGroupProperties(const LLAvatarGroups* avatar_groups);
+
+	/**
+	 * Fills common for Avatar profile and My Profile fields.
+	 */
+	virtual void fillCommonData(const LLAvatarData* avatar_data);
+
+	/**
+	 * Fills partner data.
+	 */
+	virtual void fillPartnerData(const LLAvatarData* avatar_data);
+
+	/**
+	 * Fills account status.
+	 */
+	virtual void fillAccountStatus(const LLAvatarData* avatar_data);
+
+	/**
+	 * Opens "Pay Resident" dialog.
+	 */
+	void pay();
+
+	/**
+	 * opens inventory and IM for sharing items
+	 */
+	void share();
+
+	/**
+	 * Add/remove resident to/from your block list.
+	 */
+	void toggleBlock();
+
+	void kick();
+	void freeze();
+	void unfreeze();
+	void csr();
+	
+	bool enableShowOnMap();
+	bool enableBlock();
+	bool enableUnblock();
+	bool enableGod();
+
+	void onSeeProfileBtnClick();
+	void onAddFriendButtonClick();
+	void onIMButtonClick();
+	void onCallButtonClick();
+	void onTeleportButtonClick();
+	void onShareButtonClick();
+
+private:
+	void got_full_name_callback( const LLUUID& id, const std::string& full_name, bool is_group );
+	void onNameCache(const LLUUID& agent_id, const LLAvatarName& av_name);
+
+	typedef std::map< std::string,LLUUID>	group_map_t;
+	group_map_t 			mGroups;
+};
+
+/**
+ * Panel for displaying own first and second life related info.
+ */
+class LLPanelMyProfile
+	: public LLPanelAvatarProfile
+{
+public:
+	LLPanelMyProfile();
+
+	/*virtual*/ BOOL postBuild();
+
+protected:
+
+	/*virtual*/ void onOpen(const LLSD& key);
+
+	/*virtual*/ void processProfileProperties(const LLAvatarData* avatar_data);
+
+	/*virtual*/ void resetControls();
+
+protected:
+	void onStatusMessageChanged();
+};
+
+/**
+ * Panel for displaying Avatar's notes and modifying friend's rights.
+ */
+class LLPanelAvatarNotes 
+	: public LLPanelProfileTab
+	, public LLFriendObserver
+	, public LLVoiceClientStatusObserver
+{
+public:
+	LLPanelAvatarNotes();
+	/*virtual*/ ~LLPanelAvatarNotes();
+
+	virtual void setAvatarId(const LLUUID& id);
+
+	/** 
+	 * LLFriendObserver trigger
+	 */
+	virtual void changed(U32 mask);
+
+	// Implements LLVoiceClientStatusObserver::onChange() to enable the call
+	// button when voice is available
+	/*virtual*/ void onChange(EStatusType status, const std::string &channelURI, bool proximal);
+
+	/*virtual*/ void onOpen(const LLSD& key);
+
+	/*virtual*/ BOOL postBuild();
+
+	/*virtual*/ void processProperties(void* data, EAvatarProcessorType type);
+
+	/*virtual*/ void updateData();
+
+protected:
+
+	/*virtual*/ void resetControls();
+
+	/*virtual*/ void resetData();
+
+	/**
+	 * Fills rights data for friends.
+	 */
+	void fillRightsData();
+
+	void rightsConfirmationCallback(const LLSD& notification,
+			const LLSD& response, S32 rights);
+	void confirmModifyRights(bool grant, S32 rights);
+	void onCommitRights();
+	void onCommitNotes();
+
+	void onAddFriendButtonClick();
+	void onIMButtonClick();
+	void onCallButtonClick();
+	void onTeleportButtonClick();
+	void onShareButtonClick();
+	void enableCheckboxes(bool enable);
+};
+
+#endif // LL_LLPANELAVATAR_H
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index 5cdf1706e6..18c3a3b87d 100644
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1,3011 +1,3011 @@
-/** 
- * @file lltexturefetch.cpp
- * @brief Object which fetches textures from the cache and/or network
- *
- * $LicenseInfo:firstyear=2000&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include <iostream>
-#include <map>
-
-#include "llstl.h"
-
-#include "lltexturefetch.h"
-
-#include "llcurl.h"
-#include "lldir.h"
-#include "llhttpclient.h"
-#include "llhttpstatuscodes.h"
-#include "llimage.h"
-#include "llimagej2c.h"
-#include "llimageworker.h"
-#include "llworkerthread.h"
-#include "message.h"
-
-#include "llagent.h"
-#include "lltexturecache.h"
-#include "llviewercontrol.h"
-#include "llviewertexturelist.h"
-#include "llviewertexture.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llviewerassetstats.h"
-#include "llworld.h"
-
-//////////////////////////////////////////////////////////////////////////////
-class LLTextureFetchWorker : public LLWorkerClass
-{
-	friend class LLTextureFetch;
-	friend class HTTPGetResponder;
-	
-private:
-	class CacheReadResponder : public LLTextureCache::ReadResponder
-	{
-	public:
-		CacheReadResponder(LLTextureFetch* fetcher, const LLUUID& id, LLImageFormatted* image)
-			: mFetcher(fetcher), mID(id)
-		{
-			setImage(image);
-		}
-		virtual void completed(bool success)
-		{
-			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
-			if (worker)
-			{
- 				worker->callbackCacheRead(success, mFormattedImage, mImageSize, mImageLocal);
-			}
-		}
-	private:
-		LLTextureFetch* mFetcher;
-		LLUUID mID;
-	};
-
-	class CacheWriteResponder : public LLTextureCache::WriteResponder
-	{
-	public:
-		CacheWriteResponder(LLTextureFetch* fetcher, const LLUUID& id)
-			: mFetcher(fetcher), mID(id)
-		{
-		}
-		virtual void completed(bool success)
-		{
-			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
-			if (worker)
-			{
-				worker->callbackCacheWrite(success);
-			}
-		}
-	private:
-		LLTextureFetch* mFetcher;
-		LLUUID mID;
-	};
-	
-	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, LLImageRaw* raw, LLImageRaw* aux)
-		{
-			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
-			if (worker)
-			{
- 				worker->callbackDecoded(success, raw, aux);
-			}
-		}
-	private:
-		LLTextureFetch* mFetcher;
-		LLUUID mID;
-		LLTextureFetchWorker* mWorker; // debug only (may get deleted from under us, use mFetcher/mID)
-	};
-
-	struct Compare
-	{
-		// lhs < rhs
-		bool operator()(const LLTextureFetchWorker* lhs, const LLTextureFetchWorker* rhs) const
-		{
-			// greater priority is "less"
-			const F32 lpriority = lhs->mImagePriority;
-			const F32 rpriority = rhs->mImagePriority;
-			if (lpriority > rpriority) // higher priority
-				return true;
-			else if (lpriority < rpriority)
-				return false;
-			else
-				return lhs < rhs;
-		}
-	};
-	
-public:
-	/*virtual*/ bool doWork(S32 param); // Called from LLWorkerThread::processRequest()
-	/*virtual*/ void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
-	/*virtual*/ bool deleteOK(); // called from update() (WORK THREAD)
-
-	~LLTextureFetchWorker();
-	// void relese() { --mActiveCount; }
-
-	S32 callbackHttpGet(const LLChannelDescriptors& channels,
-						 const LLIOPipe::buffer_ptr_t& buffer,
-						 bool partial, 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)
-	{
-		LLMutexLock lock(&mWorkMutex);
-
-		mGetStatus = status;
-		mGetReason = reason;
-	}
-
-	void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; }
-	bool getCanUseHTTP() const { return mCanUseHTTP; }
-
-	LLTextureFetch & getFetcher() { return *mFetcher; }
-	
-protected:
-	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)
-
-	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 writeToCacheComplete();
-	
-	void lockWorkMutex() { mWorkMutex.lock(); }
-	void unlockWorkMutex() { mWorkMutex.unlock(); }
-
-private:
-	enum e_state // mState
-	{
-		// NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack)
-		INVALID = 0,
-		INIT,
-		LOAD_FROM_TEXTURE_CACHE,
-		CACHE_POST,
-		LOAD_FROM_NETWORK,
-		LOAD_FROM_SIMULATOR,
-		SEND_HTTP_REQ,
-		WAIT_HTTP_REQ,
-		DECODE_IMAGE,
-		DECODE_IMAGE_UPDATE,
-		WRITE_TO_CACHE,
-		WAIT_ON_WRITE,
-		DONE
-	};
-	enum e_request_state // mSentRequest
-	{
-		UNSENT = 0,
-		QUEUED = 1,
-		SENT_SIM = 2
-	};
-	enum e_write_to_cache_state //mWriteToCacheState
-	{
-		NOT_WRITE = 0,
-		CAN_WRITE = 1,
-		SHOULD_WRITE = 2
-	};
-	static const char* sStateDescs[];
-	e_state mState;
-	e_write_to_cache_state mWriteToCacheState;
-	LLTextureFetch* mFetcher;
-	LLPointer<LLImageFormatted> mFormattedImage;
-	LLPointer<LLImageRaw> mRawImage;
-	LLPointer<LLImageRaw> mAuxImage;
-	LLUUID mID;
-	LLHost mHost;
-	std::string mUrl;
-	U8 mType;
-	F32 mImagePriority;
-	U32 mWorkPriority;
-	F32 mRequestedPriority;
-	S32 mDesiredDiscard;
-	S32 mSimRequestedDiscard;
-	S32 mRequestedDiscard;
-	S32 mLoadedDiscard;
-	S32 mDecodedDiscard;
-	LLFrameTimer mRequestedTimer;
-	LLFrameTimer mFetchTimer;
-	LLTextureCache::handle_t mCacheReadHandle;
-	LLTextureCache::handle_t mCacheWriteHandle;
-	U8* mBuffer;
-	S32 mBufferSize;
-	S32 mRequestedSize;
-	S32 mDesiredSize;
-	S32 mFileSize;
-	S32 mCachedSize;	
-	e_request_state mSentRequest;
-	handle_t mDecodeHandle;
-	BOOL mLoaded;
-	BOOL mDecoded;
-	BOOL mWritten;
-	BOOL mNeedsAux;
-	BOOL mHaveAllData;
-	BOOL mInLocalCache;
-	bool mCanUseHTTP ;
-	bool mCanUseNET ; //can get from asset server.
-	S32 mHTTPFailCount;
-	S32 mRetryAttempt;
-	S32 mActiveCount;
-	U32 mGetStatus;
-	std::string mGetReason;
-	
-	// Work Data
-	LLMutex mWorkMutex;
-	struct PacketData
-	{
-		PacketData(U8* data, S32 size) { mData = data; mSize = size; }
-		~PacketData() { clearData(); }
-		void clearData() { delete[] mData; mData = NULL; }
-		U8* mData;
-		U32 mSize;
-	};
-	std::vector<PacketData*> mPackets;
-	S32 mFirstPacket;
-	S32 mLastPacket;
-	U16 mTotalPackets;
-	U8 mImageCodec;
-
-	LLViewerAssetStats::duration_t mMetricsStartTime;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-class HTTPGetResponder : public LLCurl::Responder
-{
-	LOG_CLASS(HTTPGetResponder);
-public:
-	HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset, bool redir)
-		: mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset), mFollowRedir(redir)
-	{
-	}
-	~HTTPGetResponder()
-	{
-	}
-
-	virtual void completedRaw(U32 status, const std::string& reason,
-							  const LLChannelDescriptors& channels,
-							  const LLIOPipe::buffer_ptr_t& buffer)
-	{
-		static LLCachedControl<bool> log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog");
-		static LLCachedControl<bool> log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator");
-		static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
-
-		if (log_to_viewer_log || log_to_sim)
-		{
-			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;
-		LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
-		if (worker)
-		{
-			bool success = false;
-			bool partial = false;
-			if (HTTP_OK <= status &&  status < HTTP_MULTIPLE_CHOICES)
-			{
-				success = true;
-				if (HTTP_PARTIAL_CONTENT == status) // partial information
-				{
-					partial = true;
-				}
-			}
-
-			if (!success)
-			{
-				worker->setGetStatus(status, reason);
-// 				llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
-			}
-			
-			S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success);
-			
-			if(log_texture_traffic && data_size > 0)
-			{
-				LLViewerTexture* tex = LLViewerTextureManager::findTexture(mID) ;
-				if(tex)
-				{
-					gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size ;
-				}
-			}
-
-			mFetcher->removeFromHTTPQueue(mID, data_size);
-
-			if (worker->mMetricsStartTime)
-			{
-				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
-															  true,
-															  LLImageBase::TYPE_AVATAR_BAKE == worker->mType,
-															  LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime);
-				worker->mMetricsStartTime = 0;
-			}
-			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
-														 true,
-														 LLImageBase::TYPE_AVATAR_BAKE == worker->mType);
-		}
-		else
-		{
-			mFetcher->removeFromHTTPQueue(mID);
- 			llwarns << "Worker not found: " << mID << llendl;
-		}
-	}
-
-	virtual bool followRedir()
-	{
-		return mFollowRedir;
-	}
-	
-private:
-	LLTextureFetch* mFetcher;
-	LLUUID mID;
-	U64 mStartTime;
-	S32 mRequestedSize;
-	U32 mOffset;
-	bool mFollowRedir;
-};
-
-//////////////////////////////////////////////////////////////////////////////
-
-// Cross-thread messaging for asset metrics.
-
-/**
- * @brief Base class for cross-thread requests made of the fetcher
- *
- * I believe the intent of the LLQueuedThread class was to
- * have these operations derived from LLQueuedThread::QueuedRequest
- * but the texture fetcher has elected to manage the queue
- * in its own manner.  So these are free-standing objects which are
- * managed in simple FIFO order on the mCommands queue of the
- * LLTextureFetch object.
- *
- * What each represents is a simple command sent from an
- * outside thread into the TextureFetch thread to be processed
- * in order and in a timely fashion (though not an absolute
- * higher priority than other operations of the thread).
- * Each operation derives a new class from the base customizing
- * members, constructors and the doWork() method to effect
- * the command.
- *
- * The flow is one-directional.  There are two global instances
- * of the LLViewerAssetStats collector, one for the main program's
- * thread pointed to by gViewerAssetStatsMain and one for the
- * TextureFetch thread pointed to by gViewerAssetStatsThread1.
- * Common operations has each thread recording metrics events
- * into the respective collector unconcerned with locking and
- * the state of any other thread.  But when the agent moves into
- * a different region or the metrics timer expires and a report
- * needs to be sent back to the grid, messaging across threads
- * is required to distribute data and perform global actions.
- * In pseudo-UML, it looks like:
- *
- *                       Main                 Thread1
- *                        .                      .
- *                        .                      .
- *                     +-----+                   .
- *                     | AM  |                   .
- *                     +--+--+                   .
- *      +-------+         |                      .
- *      | Main  |      +--+--+                   .
- *      |       |      | SRE |---.               .
- *      | Stats |      +-----+    \              .
- *      |       |         |        \  (uuid)  +-----+
- *      | Coll. |      +--+--+      `-------->| SR  |
- *      +-------+      | MSC |                +--+--+
- *         | ^         +-----+                   |
- *         | |  (uuid)  / .                   +-----+ (uuid)
- *         |  `--------'  .                   | MSC |---------.
- *         |              .                   +-----+         |
- *         |           +-----+                   .            v
- *         |           | TE  |                   .        +-------+
- *         |           +--+--+                   .        | Thd1  |
- *         |              |                      .        |       |
- *         |           +-----+                   .        | Stats |
- *          `--------->| RSC |                   .        |       |
- *                     +--+--+                   .        | Coll. |
- *                        |                      .        +-------+
- *                     +--+--+                   .            |
- *                     | SME |---.               .            |
- *                     +-----+    \              .            |
- *                        .        \ (clone)  +-----+         |
- *                        .         `-------->| SM  |         |
- *                        .                   +--+--+         |
- *                        .                      |            |
- *                        .                   +-----+         |
- *                        .                   | RSC |<--------'
- *                        .                   +-----+
- *                        .                      |
- *                        .                   +-----+
- *                        .                   | CP  |--> HTTP POST
- *                        .                   +-----+
- *                        .                      .
- *                        .                      .
- *
- *
- * Key:
- *
- * SRE - Set Region Enqueued.  Enqueue a 'Set Region' command in
- *       the other thread providing the new UUID of the region.
- *       TFReqSetRegion carries the data.
- * SR  - Set Region.  New region UUID is sent to the thread-local
- *       collector.
- * SME - Send Metrics Enqueued.  Enqueue a 'Send Metrics' command
- *       including an ownership transfer of a cloned LLViewerAssetStats.
- *       TFReqSendMetrics carries the data.
- * SM  - Send Metrics.  Global metrics reporting operation.  Takes
- *       the cloned stats from the command, merges it with the
- *       thread's local stats, converts to LLSD and sends it on
- *       to the grid.
- * AM  - Agent Moved.  Agent has completed some sort of move to a
- *       new region.
- * TE  - Timer Expired.  Metrics timer has expired (on the order
- *       of 10 minutes).
- * CP  - CURL Post
- * MSC - Modify Stats Collector.  State change in the thread-local
- *       collector.  Typically a region change which affects the
- *       global pointers used to find the 'current stats'.
- * RSC - Read Stats Collector.  Extract collector data cloning it
- *       (i.e. deep copy) when necessary.
- *
- */
-class LLTextureFetch::TFRequest // : public LLQueuedThread::QueuedRequest
-{
-public:
-	// Default ctors and assignment operator are correct.
-
-	virtual ~TFRequest()
-		{}
-
-	// Patterned after QueuedRequest's method but expected behavior
-	// is different.  Always expected to complete on the first call
-	// and work dispatcher will assume the same and delete the
-	// request after invocation.
-	virtual bool doWork(LLTextureFetch * fetcher) = 0;
-};
-
-namespace 
-{
-
-/**
- * @brief Implements a 'Set Region' cross-thread command.
- *
- * When an agent moves to a new region, subsequent metrics need
- * to be binned into a new or existing stats collection in 1:1
- * relationship with the region.  We communicate this region
- * change across the threads involved in the communication with
- * this message.
- *
- * Corresponds to LLTextureFetch::commandSetRegion()
- */
-class TFReqSetRegion : public LLTextureFetch::TFRequest
-{
-public:
-	TFReqSetRegion(U64 region_handle)
-		: LLTextureFetch::TFRequest(),
-		  mRegionHandle(region_handle)
-		{}
-	TFReqSetRegion & operator=(const TFReqSetRegion &);	// Not defined
-
-	virtual ~TFReqSetRegion()
-		{}
-
-	virtual bool doWork(LLTextureFetch * fetcher);
-		
-public:
-	const U64 mRegionHandle;
-};
-
-
-/**
- * @brief Implements a 'Send Metrics' cross-thread command.
- *
- * This is the big operation.  The main thread gathers metrics
- * for a period of minutes into LLViewerAssetStats and other
- * objects then makes a snapshot of the data by cloning the
- * collector.  This command transfers the clone, along with a few
- * additional arguments (UUIDs), handing ownership to the
- * TextureFetch thread.  It then merges its own data into the
- * cloned copy, converts to LLSD and kicks off an HTTP POST of
- * the resulting data to the currently active metrics collector.
- *
- * Corresponds to LLTextureFetch::commandSendMetrics()
- */
-class TFReqSendMetrics : public LLTextureFetch::TFRequest
-{
-public:
-    /**
-	 * Construct the 'Send Metrics' command to have the TextureFetch
-	 * thread add and log metrics data.
-	 *
-	 * @param	caps_url		URL of a "ViewerMetrics" Caps target
-	 *							to receive the data.  Does not have to
-	 *							be associated with a particular region.
-	 *
-	 * @param	session_id		UUID of the agent's session.
-	 *
-	 * @param	agent_id		UUID of the agent.  (Being pure here...)
-	 *
-	 * @param	main_stats		Pointer to a clone of the main thread's
-	 *							LLViewerAssetStats data.  Thread1 takes
-	 *							ownership of the copy and disposes of it
-	 *							when done.
-	 */
-	TFReqSendMetrics(const std::string & caps_url,
-					 const LLUUID & session_id,
-					 const LLUUID & agent_id,
-					 LLViewerAssetStats * main_stats)
-		: LLTextureFetch::TFRequest(),
-		  mCapsURL(caps_url),
-		  mSessionID(session_id),
-		  mAgentID(agent_id),
-		  mMainStats(main_stats)
-		{}
-	TFReqSendMetrics & operator=(const TFReqSendMetrics &);	// Not defined
-
-	virtual ~TFReqSendMetrics();
-
-	virtual bool doWork(LLTextureFetch * fetcher);
-		
-public:
-	const std::string mCapsURL;
-	const LLUUID mSessionID;
-	const LLUUID mAgentID;
-	LLViewerAssetStats * mMainStats;
-};
-
-/*
- * Examines the merged viewer metrics report and if found to be too long,
- * will attempt to truncate it in some reasonable fashion.
- *
- * @param		max_regions		Limit of regions allowed in report.
- *
- * @param		metrics			Full, merged viewer metrics report.
- *
- * @returns		If data was truncated, returns true.
- */
-bool truncate_viewer_metrics(int max_regions, LLSD & metrics);
-
-} // end of anonymous namespace
-
-
-//////////////////////////////////////////////////////////////////////////////
-
-//static
-const char* LLTextureFetchWorker::sStateDescs[] = {
-	"INVALID",
-	"INIT",
-	"LOAD_FROM_TEXTURE_CACHE",
-	"CACHE_POST",
-	"LOAD_FROM_NETWORK",
-	"LOAD_FROM_SIMULATOR",
-	"SEND_HTTP_REQ",
-	"WAIT_HTTP_REQ",
-	"DECODE_IMAGE",
-	"DECODE_IMAGE_UPDATE",
-	"WRITE_TO_CACHE",
-	"WAIT_ON_WRITE",
-	"DONE",
-};
-
-// static
-volatile bool LLTextureFetch::svMetricsDataBreak(true);	// Start with a data break
-
-// 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
-										   S32 discard,			// Desired discard
-										   S32 size)			// Desired size
-	: LLWorkerClass(fetcher, "TextureFetch"),
-	  mState(INIT),
-	  mWriteToCacheState(NOT_WRITE),
-	  mFetcher(fetcher),
-	  mID(id),
-	  mHost(host),
-	  mUrl(url),
-	  mImagePriority(priority),
-	  mWorkPriority(0),
-	  mRequestedPriority(0.f),
-	  mDesiredDiscard(-1),
-	  mSimRequestedDiscard(-1),
-	  mRequestedDiscard(-1),
-	  mLoadedDiscard(-1),
-	  mDecodedDiscard(-1),
-	  mCacheReadHandle(LLTextureCache::nullHandle()),
-	  mCacheWriteHandle(LLTextureCache::nullHandle()),
-	  mBuffer(NULL),
-	  mBufferSize(0),
-	  mRequestedSize(0),
-	  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),
-	  mCanUseHTTP(true),
-	  mHTTPFailCount(0),
-	  mRetryAttempt(0),
-	  mActiveCount(0),
-	  mGetStatus(0),
-	  mWorkMutex(NULL),
-	  mFirstPacket(0),
-	  mLastPacket(-1),
-	  mTotalPackets(0),
-	  mImageCodec(IMG_CODEC_INVALID),
-	  mMetricsStartTime(0)
-{
-	mCanUseNET = mUrl.empty() ;
-
-	calcWorkPriority();
-	mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
-// 	llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl;
-	if (!mFetcher->mDebugPause)
-	{
-		U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
-		addWork(0, work_priority );
-	}
-	setDesiredDiscard(discard, size);
-}
-
-LLTextureFetchWorker::~LLTextureFetchWorker()
-{
-// 	llinfos << "Destroy: " << mID
-// 			<< " Decoded=" << mDecodedDiscard
-// 			<< " Requested=" << mRequestedDiscard
-// 			<< " Desired=" << mDesiredDiscard << llendl;
-	llassert_always(!haveWork());
-	lockWorkMutex();
-	if (mCacheReadHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache)
-	{
-		mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
-	}
-	if (mCacheWriteHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache)
-	{
-		mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
-	}
-	mFormattedImage = NULL;
-	clearPackets();
-	unlockWorkMutex();
-	mFetcher->removeFromHTTPQueue(mID);
-}
-
-void LLTextureFetchWorker::clearPackets()
-{
-	for_each(mPackets.begin(), mPackets.end(), DeletePointer());
-	mPackets.clear();
-	mTotalPackets = 0;
-	mLastPacket = -1;
-	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 <= LLViewerFetchedTexture::maxDecodePriority());
-	static const F32 PRIORITY_SCALE = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerFetchedTexture::maxDecodePriority();
-
-	mWorkPriority = llmin((U32)LLWorkerThread::PRIORITY_LOWBITS, (U32)(mImagePriority * PRIORITY_SCALE));
-	return mWorkPriority;
-}
-
-// mWorkMutex is locked
-void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size)
-{
-	bool prioritize = false;
-	if (mDesiredDiscard != discard)
-	{
-		if (!haveWork())
-		{
-			calcWorkPriority();
-			if (!mFetcher->mDebugPause)
-			{
-				U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
-				addWork(0, work_priority);
-			}
-		}
-		else if (mDesiredDiscard < discard)
-		{
-			prioritize = true;
-		}
-		mDesiredDiscard = discard;
-		mDesiredSize = size;
-	}
-	else if (size > mDesiredSize)
-	{
-		mDesiredSize = size;
-		prioritize = true;
-	}
-	mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE);
-	if ((prioritize && mState == INIT) || mState == DONE)
-	{
-		mState = INIT;
-		U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
-		setPriority(work_priority);
-	}
-}
-
-void LLTextureFetchWorker::setImagePriority(F32 priority)
-{
-// 	llassert_always(priority >= 0 && priority <= LLViewerTexture::maxDecodePriority());
-	F32 delta = fabs(priority - mImagePriority);
-	if (delta > (mImagePriority * .05f) || mState == DONE)
-	{
-		mImagePriority = priority;
-		calcWorkPriority();
-		U32 work_priority = mWorkPriority | (getPriority() & LLWorkerThread::PRIORITY_HIGHBITS);
-		setPriority(work_priority);
-	}
-}
-
-void LLTextureFetchWorker::resetFormattedData()
-{
-	delete[] mBuffer;
-	mBuffer = NULL;
-	mBufferSize = 0;
-	if (mFormattedImage.notNull())
-	{
-		mFormattedImage->deleteData();
-	}
-	mHaveAllData = FALSE;
-}
-
-// Called from MAIN thread
-void LLTextureFetchWorker::startWork(S32 param)
-{
-	llassert(mFormattedImage.isNull());
-}
-
-#include "llviewertexturelist.h" // debug
-
-// Called from LLWorkerThread::processRequest()
-bool LLTextureFetchWorker::doWork(S32 param)
-{
-	LLMutexLock lock(&mWorkMutex);
-
-	if ((mFetcher->isQuitting() || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)))
-	{
-		if (mState < DECODE_IMAGE)
-		{
-			return true; // abort
-		}
-	}
-
-	if(mImagePriority < F_ALMOST_ZERO)
-	{
-		if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR)
-		{
-			return true; // abort
-		}
-	}
-	if(mState > CACHE_POST && !mCanUseNET && !mCanUseHTTP)
-	{
-		//nowhere to get data, abort.
-		return true ;
-	}
-
-	if (mFetcher->mDebugPause)
-	{
-		return false; // debug: don't do any work
-	}
-	if (mID == mFetcher->mDebugID)
-	{
-		mFetcher->mDebugCount++; // for setting breakpoints
-	}
-
-	if (mState != DONE)
-	{
-		mFetchTimer.reset();
-	}
-
-	if (mState == INIT)
-	{		
-		mRawImage = NULL ;
-		mRequestedDiscard = -1;
-		mLoadedDiscard = -1;
-		mDecodedDiscard = -1;
-		mRequestedSize = 0;
-		mFileSize = 0;
-		mCachedSize = 0;
-		mLoaded = FALSE;
-		mSentRequest = UNSENT;
-		mDecoded  = FALSE;
-		mWritten  = FALSE;
-		delete[] mBuffer;
-		mBuffer = NULL;
-		mBufferSize = 0;
-		mHaveAllData = FALSE;
-		clearPackets(); // TODO: Shouldn't be necessary
-		mCacheReadHandle = LLTextureCache::nullHandle();
-		mCacheWriteHandle = LLTextureCache::nullHandle();
-		mState = LOAD_FROM_TEXTURE_CACHE;
-		mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE
-		LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority)
-							 << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
-		// fall through
-	}
-
-	if (mState == LOAD_FROM_TEXTURE_CACHE)
-	{
-		if (mCacheReadHandle == LLTextureCache::nullHandle())
-		{
-			U32 cache_priority = mWorkPriority;
-			S32 offset = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
-			S32 size = mDesiredSize - offset;
-			if (size <= 0)
-			{
-				mState = CACHE_POST;
-				return false;
-			}
-			mFileSize = 0;
-			mLoaded = FALSE;			
-			
-			if (mUrl.compare(0, 7, "file://") == 0)
-			{
-				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
-
-				// read file from local disk
-				std::string filename = mUrl.substr(7, std::string::npos);
-				CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
-				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
-																		  offset, size, responder);
-			}
-			else if (mUrl.empty())
-			{
-				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
-
-				CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
-				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
-																		  offset, size, responder);
-			}
-			else if(mCanUseHTTP)
-			{
-				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;
-			}
-			else
-			{
-				setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-				mState = LOAD_FROM_NETWORK;
-			}
-		}
-
-		if (mLoaded)
-		{
-			// Make sure request is complete. *TODO: make this auto-complete
-			if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, false))
-			{
-				mCacheReadHandle = LLTextureCache::nullHandle();
-				mState = CACHE_POST;
-				// fall through
-			}
-			else
-			{
-				return false;
-			}
-		}
-		else
-		{
-			return false;
-		}
-	}
-
-	if (mState == CACHE_POST)
-	{
-		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;
-			mWriteToCacheState = NOT_WRITE ;
-			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 (mUrl.compare(0, 7, "file://") == 0)
-			{
-				// failed to load local file, we're done.
-				return true;
-			}
-			// need more data
-			else
-			{
-				LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL;
-				mState = LOAD_FROM_NETWORK;
-			}
-			// fall through
-		}
-	}
-
-	if (mState == LOAD_FROM_NETWORK)
-	{
-		static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP");
-
-// 		if (mHost != LLHost::invalid) get_url = false;
-		if ( use_http && mCanUseHTTP && mUrl.empty())//get http url.
-		{
-			LLViewerRegion* region = NULL;
-			if (mHost == LLHost::invalid)
-				region = gAgent.getRegion();
-			else
-				region = LLWorld::getInstance()->getRegion(mHost);
-
-			if (region)
-			{
-				std::string http_url = region->getHttpUrl() ;
-				if (!http_url.empty())
-				{
-					mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
-					mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.
-				}
-				else
-				{
-					mCanUseHTTP = false ;
-				}
-			}
-			else
-			{
-				// This will happen if not logged in or if a region deoes not have HTTP Texture enabled
-				//llwarns << "Region not found for host: " << mHost << llendl;
-				mCanUseHTTP = false;
-			}
-		}
-		if (mCanUseHTTP && !mUrl.empty())
-		{
-			mState = LLTextureFetchWorker::SEND_HTTP_REQ;
-			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-			if(mWriteToCacheState != NOT_WRITE)
-			{
-				mWriteToCacheState = CAN_WRITE ;
-			}
-			// don't return, fall through to next state
-		}
-		else if (mSentRequest == UNSENT && mCanUseNET)
-		{
-			// Add this to the network queue and sit here.
-			// LLTextureFetch::update() will send off a request which will change our state
-			mWriteToCacheState = CAN_WRITE ;
-			mRequestedSize = mDesiredSize;
-			mRequestedDiscard = mDesiredDiscard;
-			mSentRequest = QUEUED;
-			mFetcher->addToNetworkQueue(this);
-			if (! mMetricsStartTime)
-			{
-				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
-			}
-			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
-														 false,
-														 LLImageBase::TYPE_AVATAR_BAKE == mType);
-			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);
-			//if (! mMetricsStartTime)
-			//{
-			//   mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
-			//}
-			//LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false,
-			//                                             LLImageBase::TYPE_AVATAR_BAKE == mType);
-			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-			return false;
-		}
-	}
-	
-	if (mState == LOAD_FROM_SIMULATOR)
-	{
-		if (mFormattedImage.isNull())
-		{
-			mFormattedImage = new LLImageJ2C;
-		}
-		if (processSimulatorPackets())
-		{
-			LL_DEBUGS("Texture") << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL;
-			mFetcher->removeFromNetworkQueue(this, false);
-			if (mFormattedImage.isNull() || !mFormattedImage->getDataSize())
-			{
-				// processSimulatorPackets() failed
-// 				llwarns << "processSimulatorPackets() failed to load buffer" << llendl;
-				return true; // failed
-			}
-			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-			mState = DECODE_IMAGE;
-			mWriteToCacheState = SHOULD_WRITE;
-
-			if (mMetricsStartTime)
-			{
-				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
-															  false,
-															  LLImageBase::TYPE_AVATAR_BAKE == mType,
-															  LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
-				mMetricsStartTime = 0;
-			}
-			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
-														 false,
-														 LLImageBase::TYPE_AVATAR_BAKE == mType);
-		}
-		else
-		{
-			mFetcher->addToNetworkQueue(this); // failsafe
-			if (! mMetricsStartTime)
-			{
-				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
-			}
-			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
-														 false,
-														 LLImageBase::TYPE_AVATAR_BAKE == mType);
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-		}
-		return false;
-	}
-	
-	if (mState == SEND_HTTP_REQ)
-	{
-		if(mCanUseHTTP)
-		{
-			//NOTE:
-			//control the number of the http requests issued for:
-			//1, not openning too many file descriptors at the same time;
-			//2, control the traffic of http so udp gets bandwidth.
-			//
-			static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ;
-			if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE)
-			{
-				return false ; //wait.
-			}
-
-			mFetcher->removeFromNetworkQueue(this, false);
-			
-			S32 cur_size = 0;
-			if (mFormattedImage.notNull())
-			{
-				cur_size = mFormattedImage->getDataSize(); // amount of data we already have
-				if (mFormattedImage->getDiscardLevel() == 0)
-				{
-					if(cur_size > 0)
-					{
-						// We already have all the data, just decode it
-						mLoadedDiscard = mFormattedImage->getDiscardLevel();
-						mState = DECODE_IMAGE;
-						return false;
-					}
-					else
-					{
-						return true ; //abort.
-					}
-				}
-			}
-			mRequestedSize = mDesiredSize;
-			mRequestedDiscard = mDesiredDiscard;
-			mRequestedSize -= cur_size;
-			S32 offset = cur_size;
-			mBufferSize = cur_size; // This will get modified by callbackHttpGet()
-			
-			bool res = false;
-			if (!mUrl.empty())
-			{
-				mLoaded = FALSE;
-				mGetStatus = 0;
-				mGetReason.clear();
-				LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << offset
-									 << " Bytes: " << mRequestedSize
-									 << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << mFetcher->mMaxBandwidth
-									 << LL_ENDL;
-				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-				mState = WAIT_HTTP_REQ;	
-
-				mFetcher->addToHTTPQueue(mID);
-				if (! mMetricsStartTime)
-				{
-					mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
-				}
-				LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
-															 true,
-															 LLImageBase::TYPE_AVATAR_BAKE == mType);
-
-				// 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, true));
-			}
-			if (!res)
-			{
-				llwarns << "HTTP GET request failed for " << mID << llendl;
-				resetFormattedData();
-				++mHTTPFailCount;
-				return true; // failed
-			}
-			// fall through
-		}
-		else //can not use http fetch.
-		{
-			return true ; //abort
-		}
-	}
-	
-	if (mState == WAIT_HTTP_REQ)
-	{
-		if (mLoaded)
-		{
-			S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
-			if (mRequestedSize < 0)
-			{
-				S32 max_attempts;
-				if (mGetStatus == HTTP_NOT_FOUND)
-				{
-					mHTTPFailCount = max_attempts = 1; // Don't retry
-					llwarns << "Texture missing from server (404): " << mUrl << llendl;
-
-					//roll back to try UDP
-					if(mCanUseNET)
-					{
-						mState = INIT ;
-						mCanUseHTTP = false ;
-						setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-						return false ;
-					}
-				}
-				else if (mGetStatus == HTTP_SERVICE_UNAVAILABLE)
-				{
-					// *TODO: Should probably introduce a timer here to delay future HTTP requsts
-					// for a short time (~1s) to ease server load? Ideally the server would queue
-					// requests instead of returning 503... we already limit the number pending.
-					++mHTTPFailCount;
-					max_attempts = mHTTPFailCount+1; // Keep retrying
-					LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL;
-				}
-				else
-				{
-					const S32 HTTP_MAX_RETRY_COUNT = 3;
-					max_attempts = HTTP_MAX_RETRY_COUNT + 1;
-					++mHTTPFailCount;
-					llinfos << "HTTP GET failed for: " << mUrl
-							<< " Status: " << mGetStatus << " Reason: '" << mGetReason << "'"
-							<< " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl;
-				}
-
-				if (mHTTPFailCount >= max_attempts)
-				{
-					if (cur_size > 0)
-					{
-						// Use available data
-						mLoadedDiscard = mFormattedImage->getDiscardLevel();
-						mState = DECODE_IMAGE;
-						return false; 
-					}
-					else
-					{
-						resetFormattedData();
-						mState = DONE;
-						return true; // failed
-					}
-				}
-				else
-				{
-					mState = SEND_HTTP_REQ;
-					return false; // retry
-				}
-			}
-			
-			llassert_always(mBufferSize == cur_size + mRequestedSize);
-			if(!mBufferSize)//no data received.
-			{
-				delete[] mBuffer; 
-				mBuffer = NULL;
-
-				//abort.
-				mState = DONE;
-				return true;
-			}
-
-			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
-				}
-			}
-						
-			if (mHaveAllData && mRequestedDiscard == 0) //the image file is fully loaded.
-			{
-				mFileSize = mBufferSize;
-			}
-			else //the file size is unknown.
-			{
-				mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded.
-			}
-			
-			U8* buffer = new U8[mBufferSize];
-			if (cur_size > 0)
-			{
-				memcpy(buffer, mFormattedImage->getData(), cur_size);
-			}
-			memcpy(buffer + cur_size, mBuffer, mRequestedSize); // append
-			// NOTE: setData releases current data and owns new data (buffer)
-			mFormattedImage->setData(buffer, mBufferSize);
-			// delete temp data
-			delete[] mBuffer; // Note: not 'buffer' (assigned in setData())
-			mBuffer = NULL;
-			mBufferSize = 0;
-			mLoadedDiscard = mRequestedDiscard;
-			mState = DECODE_IMAGE;
-			if(mWriteToCacheState != NOT_WRITE)
-			{
-				mWriteToCacheState = SHOULD_WRITE ;
-			}
-			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-			return false;
-		}
-		else
-		{
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-			return false;
-		}
-	}
-	
-	if (mState == DECODE_IMAGE)
-	{
-		static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled");
-		if(textures_decode_disabled)
-		{
-			// for debug use, don't decode
-			mState = DONE;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-			return true;
-		}
-
-		if (mDesiredDiscard < 0)
-		{
-			// We aborted, don't decode
-			mState = DONE;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-			return true;
-		}
-		
-		if (mFormattedImage->getDataSize() <= 0)
-		{
-			//llerrs << "Decode entered with invalid mFormattedImage. ID = " << mID << llendl;
-			
-			//abort, don't decode
-			mState = DONE;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-			return true;
-		}
-		if (mLoadedDiscard < 0)
-		{
-			//llerrs << "Decode entered with invalid mLoadedDiscard. ID = " << mID << llendl;
-
-			//abort, don't decode
-			mState = DONE;
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-			return true;
-		}
-		setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
-		mRawImage = NULL;
-		mAuxImage = NULL;
-		llassert_always(mFormattedImage.notNull());
-		S32 discard = mHaveAllData ? 0 : mLoadedDiscard;
-		U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority;
-		mDecoded  = FALSE;
-		mState = DECODE_IMAGE_UPDATE;
-		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 (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);
-					mState = INIT;
-					return false;
-				}
-				else
-				{
-// 					llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl;
-					mState = DONE; // failed
-				}
-			}
-			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;
-			}
-			// fall through
-		}
-		else
-		{
-			return false;
-		}
-	}
-
-	if (mState == WRITE_TO_CACHE)
-	{
-		if (mWriteToCacheState != SHOULD_WRITE || mFormattedImage.isNull())
-		{
-			// 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;
-		}
-		S32 datasize = mFormattedImage->getDataSize();
-		if(mFileSize < datasize)//This could happen when http fetching and sim fetching mixed.
-		{
-			if(mHaveAllData)
-			{
-				mFileSize = datasize ;
-			}
-			else
-			{
-				mFileSize = datasize + 1 ; //flag not fully loaded.
-			}
-		}
-		llassert_always(datasize);
-		setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
-		U32 cache_priority = mWorkPriority;
-		mWritten = FALSE;
-		mState = WAIT_ON_WRITE;
-		CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID);
-		mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority,
-																  mFormattedImage->getData(), datasize,
-																  mFileSize, responder);
-		// fall through
-	}
-	
-	if (mState == WAIT_ON_WRITE)
-	{
-		if (writeToCacheComplete())
-		{
-			mState = DONE;
-			// fall through
-		}
-		else
-		{
-			if (mDesiredDiscard < mDecodedDiscard)
-			{
-				// We're waiting for this write to complete before we can receive more data
-				// (we can't touch mFormattedImage until the write completes)
-				// Prioritize the write
-				mFetcher->mTextureCache->prioritizeWrite(mCacheWriteHandle);
-			}
-			return false;
-		}
-	}
-
-	if (mState == DONE)
-	{
-		if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard)
-		{
-			// More data was requested, return to INIT
-			mState = INIT;
-			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-			return false;
-		}
-		else
-		{
-			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
-			return true;
-		}
-	}
-	
-	return false;
-}
-
-// Called from MAIN thread
-void LLTextureFetchWorker::endWork(S32 param, bool aborted)
-{
-	if (mDecodeHandle != 0)
-	{
-		mFetcher->mImageDecodeThread->abortRequest(mDecodeHandle, false);
-		mDecodeHandle = 0;
-	}
-	mFormattedImage = NULL;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-// virtual
-void LLTextureFetchWorker::finishWork(S32 param, bool completed)
-{
-	// The following are required in case the work was aborted
-	if (mCacheReadHandle != LLTextureCache::nullHandle())
-	{
-		mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
-		mCacheReadHandle = LLTextureCache::nullHandle();
-	}
-	if (mCacheWriteHandle != LLTextureCache::nullHandle())
-	{
-		mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
-		mCacheWriteHandle = LLTextureCache::nullHandle();
-	}
-}
-
-// virtual
-bool LLTextureFetchWorker::deleteOK()
-{
-	bool delete_ok = true;
-	// Allow any pending reads or writes to complete
-	if (mCacheReadHandle != LLTextureCache::nullHandle())
-	{
-		if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, true))
-		{
-			mCacheReadHandle = LLTextureCache::nullHandle();
-		}
-		else
-		{
-			delete_ok = false;
-		}
-	}
-	if (mCacheWriteHandle != LLTextureCache::nullHandle())
-	{
-		if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle))
-		{
-			mCacheWriteHandle = LLTextureCache::nullHandle();
-		}
-		else
-		{
-			delete_ok = false;
-		}
-	}
-
-	if ((haveWork() &&
-		 // not ok to delete from these states
-		 ((mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
-	{
-		delete_ok = false;
-	}
-	
-	return delete_ok;
-}
-
-void LLTextureFetchWorker::removeFromCache()
-{
-	if (!mInLocalCache)
-	{
-		mFetcher->mTextureCache->removeFromCache(mID);
-	}
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-
-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;
-	}
-	
-	if (mLastPacket >= mFirstPacket)
-	{
-		S32 buffer_size = mFormattedImage->getDataSize();
-		for (S32 i = mFirstPacket; i<=mLastPacket; i++)
-		{
-			llassert_always(mPackets[i]);
-			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
-			if (have_all_data)
-			{
-				mHaveAllData = TRUE;
-			}
-			S32 cur_size = mFormattedImage->getDataSize();
-			if (buffer_size > cur_size)
-			{
-				/// We have new data
-				U8* buffer = new U8[buffer_size];
-				S32 offset = 0;
-				if (cur_size > 0 && mFirstPacket > 0)
-				{
-					memcpy(buffer, mFormattedImage->getData(), cur_size);
-					offset = cur_size;
-				}
-				for (S32 i=mFirstPacket; i<=mLastPacket; i++)
-				{
-					memcpy(buffer + offset, mPackets[i]->mData, mPackets[i]->mSize);
-					offset += mPackets[i]->mSize;
-				}
-				// NOTE: setData releases current data
-				mFormattedImage->setData(buffer, buffer_size);
-			}
-			mLoadedDiscard = mRequestedDiscard;
-			return true;
-		}
-	}
-	return false;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
-										   const LLIOPipe::buffer_ptr_t& buffer,
-										   bool partial, bool success)
-{
-	S32 data_size = 0 ;
-
-	LLMutexLock lock(&mWorkMutex);
-
-	if (mState != WAIT_HTTP_REQ)
-	{
-		llwarns << "callbackHttpGet for unrequested fetch worker: " << mID
-				<< " req=" << mSentRequest << " state= " << mState << llendl;
-		return data_size;
-	}
-	if (mLoaded)
-	{
-		llwarns << "Duplicate callback for " << mID.asString() << llendl;
-		return data_size ; // ignore duplicate callback
-	}
-	if (success)
-	{
-		// get length of stream:
-		data_size = buffer->countAfter(channels.in(), NULL);		
-	
-		LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL;
-		if (data_size > 0)
-		{
-			// *TODO: set the formatted image data here directly to avoid the copy
-			mBuffer = new U8[data_size];
-			buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
-			mBufferSize += data_size;
-			if (data_size < mRequestedSize && mRequestedDiscard == 0)
-			{
-				mHaveAllData = TRUE;
-			}
-			else if (data_size > mRequestedSize)
-			{
-				// *TODO: This shouldn't be happening any more
-				llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl;
-				mHaveAllData = TRUE;
-				llassert_always(mDecodeHandle == 0);
-				mFormattedImage = NULL; // discard any previous data we had
-				mBufferSize = data_size;
-			}
-		}
-		else
-		{
-			// We requested data but received none (and no error),
-			// so presumably we have all of it
-			mHaveAllData = TRUE;
-		}
-		mRequestedSize = data_size;
-	}
-	else
-	{
-		mRequestedSize = -1; // error
-	}
-	mLoaded = TRUE;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-
-	return data_size ;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* image,
-											 S32 imagesize, BOOL islocal)
-{
-	LLMutexLock lock(&mWorkMutex);
-	if (mState != LOAD_FROM_TEXTURE_CACHE)
-	{
-// 		llwarns << "Read callback for " << mID << " with state = " << mState << llendl;
-		return;
-	}
-	if (success)
-	{
-		llassert_always(imagesize >= 0);
-		mFileSize = imagesize;
-		mFormattedImage = image;
-		mImageCodec = image->getCodec();
-		mInLocalCache = islocal;
-		if (mFileSize != 0 && mFormattedImage->getDataSize() >= mFileSize)
-		{
-			mHaveAllData = TRUE;
-		}
-	}
-	mLoaded = TRUE;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-}
-
-void LLTextureFetchWorker::callbackCacheWrite(bool success)
-{
-	LLMutexLock lock(&mWorkMutex);
-	if (mState != WAIT_ON_WRITE)
-	{
-// 		llwarns << "Write callback for " << mID << " with state = " << mState << llendl;
-		return;
-	}
-	mWritten = TRUE;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-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;
-	}
-	llassert_always(mFormattedImage.notNull());
-	
-	mDecodeHandle = 0;
-	if (success)
-	{
-		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;
-	}
-	else
-	{
-		llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl;
-		removeFromCache();
-		mDecodedDiscard = -1; // Redundant, here for clarity and paranoia
-	}
-	mDecoded = TRUE;
-// 	llinfos << mID << " : DECODE COMPLETE " << llendl;
-	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-bool LLTextureFetchWorker::writeToCacheComplete()
-{
-	// Complete write to cache
-	if (mCacheWriteHandle != LLTextureCache::nullHandle())
-	{
-		if (!mWritten)
-		{
-			return false;
-		}
-		if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle))
-		{
-			mCacheWriteHandle = LLTextureCache::nullHandle();
-		}
-		else
-		{
-			return false;
-		}
-	}
-	return true;
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-// public
-
-LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode)
-	: LLWorkerThread("TextureFetch", threaded),
-	  mDebugCount(0),
-	  mDebugPause(FALSE),
-	  mPacketCount(0),
-	  mBadPacketCount(0),
-	  mQueueMutex(getAPRPool()),
-	  mNetworkQueueMutex(getAPRPool()),
-	  mTextureCache(cache),
-	  mImageDecodeThread(imagedecodethread),
-	  mTextureBandwidth(0),
-	  mHTTPTextureBits(0),
-	  mTotalHTTPRequests(0),
-	  mCurlGetRequest(NULL),
-	  mQAMode(qa_mode)
-{
-	mCurlPOSTRequestCount = 0;
-	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
-	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
-}
-
-LLTextureFetch::~LLTextureFetch()
-{
-	clearDeleteList() ;
-
-	while (! mCommands.empty())
-	{
-		TFRequest * req(mCommands.front());
-		mCommands.erase(mCommands.begin());
-		delete req;
-	}
-	
-	// ~LLQueuedThread() called here
-}
-
-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, bool can_use_http)
-{
-	if (mDebugPause)
-	{
-		return false;
-	}
-	
-	LLTextureFetchWorker* worker = getWorker(id) ;
-	if (worker)
-	{
-		if (worker->mHost != host)
-		{
-			llwarns << "LLTextureFetch::createRequest " << id << " called with multiple hosts: "
-					<< host << " != " << worker->mHost << llendl;
-			removeRequest(worker, true);
-			worker = NULL;
-			return false;
-		}
-	}
-
-	S32 desired_size;
-	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
-		desired_size = MAX_IMAGE_DATA_SIZE;
-		desired_discard = 0;
-	}
-	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
-		// was compressed - this code ensures that when we request the entire image,
-		// we really do get it.)
-		desired_size = MAX_IMAGE_DATA_SIZE;
-	}
-	else if (w*h*c > 0)
-	{
-		// If the requester knows the dimensions of the image,
-		// this will calculate how much data we need without having to parse the header
-
-		desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, desired_discard);
-	}
-	else
-	{
-		desired_size = TEXTURE_CACHE_ENTRY_SIZE;
-		desired_discard = MAX_DISCARD_LEVEL;
-	}
-
-	
-	if (worker)
-	{
-		if (worker->wasAborted())
-		{
-			return false; // need to wait for previous aborted request to complete
-		}
-		worker->lockWorkMutex();
-		worker->mActiveCount++;
-		worker->mNeedsAux = needs_aux;
-		worker->setImagePriority(priority);
-		worker->setDesiredDiscard(desired_discard, desired_size);
-		worker->setCanUseHTTP(can_use_http) ;
-		if (!worker->haveWork())
-		{
-			worker->mState = LLTextureFetchWorker::INIT;
-			worker->unlockWorkMutex();
-
-			worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
-		}
-		else
-		{
-			worker->unlockWorkMutex();
-		}
-	}
-	else
-	{
-		worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size);
-		lockQueue() ;
-		mRequestMap[id] = worker;
-		unlockQueue() ;
-
-		worker->lockWorkMutex();
-		worker->mActiveCount++;
-		worker->mNeedsAux = needs_aux;
-		worker->setCanUseHTTP(can_use_http) ;
-		worker->unlockWorkMutex();
-	}
-	
-// 	llinfos << "REQUESTED: " << id << " Discard: " << desired_discard << llendl;
-	return true;
-}
-
-// protected
-void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
-{
-	lockQueue() ;
-	bool in_request_map = (mRequestMap.find(worker->mID) != mRequestMap.end()) ;
-	unlockQueue() ;
-
-	LLMutexLock lock(&mNetworkQueueMutex);
-	if (in_request_map)
-	{
-		// only add to the queue if in the request map
-		// i.e. a delete has not been requested
-		mNetworkQueue.insert(worker->mID);
-	}
-	for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
-		 iter1 != mCancelQueue.end(); ++iter1)
-	{
-		iter1->second.erase(worker->mID);
-	}
-}
-
-void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel)
-{
-	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);
-	mTotalHTTPRequests++;
-}
-
-void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size)
-{
-	LLMutexLock lock(&mNetworkQueueMutex);
-	mHTTPTextureQueue.erase(id);
-	mHTTPTextureBits += received_size * 8; // Approximate - does not include header bits	
-}
-
-void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
-{
-	lockQueue() ;
-	LLTextureFetchWorker* worker = getWorkerAfterLock(id);
-	if (worker)
-	{		
-		size_t erased_1 = mRequestMap.erase(worker->mID);
-		unlockQueue() ;
-
-		llassert_always(erased_1 > 0) ;
-
-		removeFromNetworkQueue(worker, cancel);
-		llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
-
-		worker->scheduleDelete();	
-	}
-	else
-	{
-		unlockQueue() ;
-	}
-}
-
-void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel)
-{
-	lockQueue() ;
-	size_t erased_1 = mRequestMap.erase(worker->mID);
-	unlockQueue() ;
-
-	llassert_always(erased_1 > 0) ;
-	removeFromNetworkQueue(worker, cancel);
-	llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
-
-	worker->scheduleDelete();	
-}
-
-S32 LLTextureFetch::getNumRequests() 
-{ 
-	lockQueue() ;
-	S32 size = (S32)mRequestMap.size(); 
-	unlockQueue() ;
-
-	return size ;
-}
-
-S32 LLTextureFetch::getNumHTTPRequests() 
-{ 
-	mNetworkQueueMutex.lock() ;
-	S32 size = (S32)mHTTPTextureQueue.size(); 
-	mNetworkQueueMutex.unlock() ;
-
-	return size ;
-}
-
-U32 LLTextureFetch::getTotalNumHTTPRequests()
-{
-	mNetworkQueueMutex.lock() ;
-	U32 size = mTotalHTTPRequests ;
-	mNetworkQueueMutex.unlock() ;
-
-	return size ;
-}
-
-// call lockQueue() first!
-LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id)
-{
-	LLTextureFetchWorker* res = NULL;
-	map_t::iterator iter = mRequestMap.find(id);
-	if (iter != mRequestMap.end())
-	{
-		res = iter->second;
-	}
-	return res;
-}
-
-LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)
-{
-	LLMutexLock lock(&mQueueMutex) ;
-
-	return getWorkerAfterLock(id) ;
-}
-
-
-bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
-										LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux)
-{
-	bool res = false;
-	LLTextureFetchWorker* worker = getWorker(id);
-	if (worker)
-	{
-		if (worker->wasAborted())
-		{
-			res = true;
-		}
-		else if (!worker->haveWork())
-		{
-			// Should only happen if we set mDebugPause...
-			if (!mDebugPause)
-			{
-// 				llwarns << "Adding work for inactive worker: " << id << llendl;
-				worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
-			}
-		}
-		else if (worker->checkWork())
-		{
-			worker->lockWorkMutex();
-			discard_level = worker->mDecodedDiscard;
-			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->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;
-				raw = worker->mRawImage;
-				aux = worker->mAuxImage;
-			}
-			worker->unlockWorkMutex();
-		}
-	}
-	else
-	{
-		res = true;
-	}
-	return res;
-}
-
-bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
-{
-	bool res = false;
-	LLTextureFetchWorker* worker = getWorker(id);
-	if (worker)
-	{
-		worker->lockWorkMutex();
-		worker->setImagePriority(priority);
-		worker->unlockWorkMutex();
-		res = true;
-	}
-	return res;
-}
-
-// Replicates and expands upon the base class's
-// getPending() implementation.  getPending() and
-// runCondition() replicate one another's logic to
-// an extent and are sometimes used for the same
-// function (deciding whether or not to sleep/pause
-// a thread).  So the implementations need to stay
-// in step, at least until this can be refactored and
-// the redundancy eliminated.
-//
-// May be called from any thread
-
-//virtual
-S32 LLTextureFetch::getPending()
-{
-	S32 res;
-	lockData();
-    {
-        LLMutexLock lock(&mQueueMutex);
-        
-        res = mRequestQueue.size();
-        res += mCurlPOSTRequestCount;
-        res += mCommands.size();
-    }
-	unlockData();
-	return res;
-}
-
-// virtual
-bool LLTextureFetch::runCondition()
-{
-	// Caller is holding the lock on LLThread's condition variable.
-	
-	// LLQueuedThread, unlike its base class LLThread, makes this a
-	// private method which is unfortunate.  I want to use it directly
-	// but I'm going to have to re-implement the logic here (or change
-	// declarations, which I don't want to do right now).
-	//
-	// Changes here may need to be reflected in getPending().
-	
-	bool have_no_commands(false);
-	{
-		LLMutexLock lock(&mQueueMutex);
-		
-		have_no_commands = mCommands.empty();
-	}
-	
-    bool have_no_curl_requests(0 == mCurlPOSTRequestCount);
-	
-	return ! (have_no_commands
-			  && have_no_curl_requests
-			  && (mRequestQueue.empty() && mIdleThread));		// From base class
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs)
-void LLTextureFetch::commonUpdate()
-{
-	// Run a cross-thread command, if any.
-	cmdDoWork();
-	
-	// Update Curl on same thread as mCurlGetRequest was constructed
-	S32 processed = mCurlGetRequest->process();
-	if (processed > 0)
-	{
-		lldebugs << "processed: " << processed << " messages." << llendl;
-	}
-}
-
-
-// MAIN THREAD
-//virtual
-S32 LLTextureFetch::update(U32 max_time_ms)
-{
-	static LLCachedControl<F32> band_width(gSavedSettings,"ThrottleBandwidthKBPS");
-
-	{
-		mNetworkQueueMutex.lock() ;
-		mMaxBandwidth = band_width ;
-
-		gTextureList.sTextureBits += mHTTPTextureBits ;
-		mHTTPTextureBits = 0 ;
-
-		mNetworkQueueMutex.unlock() ;
-	}
-
-	S32 res = LLWorkerThread::update(max_time_ms);
-	
-	if (!mDebugPause)
-	{
-		sendRequestListToSimulators();
-	}
-
-	if (!mThreaded)
-	{
-		commonUpdate();
-	}
-
-	return res;
-}
-
-//called in the MAIN thread after the TextureCacheThread shuts down.
-void LLTextureFetch::shutDownTextureCacheThread() 
-{
-	if(mTextureCache)
-	{
-		llassert_always(mTextureCache->isQuitting() || mTextureCache->isStopped()) ;
-		mTextureCache = NULL ;
-	}
-}
-	
-//called in the MAIN thread after the ImageDecodeThread shuts down.
-void LLTextureFetch::shutDownImageDecodeThread() 
-{
-	if(mImageDecodeThread)
-	{
-		llassert_always(mImageDecodeThread->isQuitting() || mImageDecodeThread->isStopped()) ;
-		mImageDecodeThread = NULL ;
-	}
-}
-
-// 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();
-	
-	commonUpdate();
-
-#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 SIM_LAZY_FLUSH_TIMEOUT = 10.0f; // temp
-	const F32 MIN_REQUEST_TIME = 1.0f;
-	const F32 MIN_DELTA_PRIORITY = 1000.f;
-
-	// 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();
-	
-	// 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++;
-		LLTextureFetchWorker* req = getWorker(*curiter);
-		if (!req)
-		{
-			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->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 >= SIM_LAZY_FLUSH_TIMEOUT))
-			{
-				requests[req->mHost].insert(req);
-			}
-		}
-	}
-	}
-
-	for (work_request_map_t::iterator iter1 = requests.begin();
-		 iter1 != requests.end(); ++iter1)
-	{
-		LLHost host = iter1->first;
-		// invalid host = use agent host
-		if (host == LLHost::invalid)
-		{
-			host = gAgent.getRegionHost();
-		}
-
-		S32 sim_request_count = 0;
-		
-		for (request_list_t::iterator iter2 = iter1->second.begin();
-			 iter2 != iter1->second.end(); ++iter2)
-		{
-			LLTextureFetchWorker* req = *iter2;
-			if (gMessageSystem)
-			{
-				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);
-					gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-					gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-				}
-				S32 packet = req->mLastPacket + 1;
-				gMessageSystem->nextBlockFast(_PREHASH_RequestImage);
-				gMessageSystem->addUUIDFast(_PREHASH_Image, req->mID);
-				gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, (S8)req->mDesiredDiscard);
-				gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, req->mImagePriority);
-				gMessageSystem->addU32Fast(_PREHASH_Packet, packet);
-				gMessageSystem->addU8Fast(_PREHASH_Type, req->mType);
-// 				llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard
-// 						<< " Packet: " << packet << " Priority: " << req->mImagePriority << llendl;
-
-				static LLCachedControl<bool> log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog");
-				static LLCachedControl<bool> log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator");
-				if (log_to_viewer_log || log_to_sim)
-				{
-					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->unlockWorkMutex();
-				sim_request_count++;
-				if (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;
-				}
-			}
-		}
-		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
-	{
-	LLMutexLock lock2(&mNetworkQueueMutex);
-	if (gMessageSystem && !mCancelQueue.empty())
-	{
-		for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
-			 iter1 != mCancelQueue.end(); ++iter1)
-		{
-			LLHost host = iter1->first;
-			if (host == LLHost::invalid)
-			{
-				host = gAgent.getRegionHost();
-			}
-			S32 request_count = 0;
-			for (queue_t::iterator iter2 = iter1->second.begin();
-				 iter2 != iter1->second.end(); ++iter2)
-			{
-				if (0 == request_count)
-				{
-					gMessageSystem->newMessageFast(_PREHASH_RequestImage);
-					gMessageSystem->nextBlockFast(_PREHASH_AgentData);
-					gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-					gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-				}
-				gMessageSystem->nextBlockFast(_PREHASH_RequestImage);
-				gMessageSystem->addUUIDFast(_PREHASH_Image, *iter2);
-				gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, -1);
-				gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, 0);
-				gMessageSystem->addU32Fast(_PREHASH_Packet, 0);
-				gMessageSystem->addU8Fast(_PREHASH_Type, 0);
-// 				llinfos << "CANCELING IMAGE REQUEST: " << (*iter2) << llendl;
-
-				request_count++;
-				if (request_count >= IMAGES_PER_REQUEST)
-				{
-					gMessageSystem->sendSemiReliable(host, NULL, NULL);
-					request_count = 0;
-				}
-			}
-			if (request_count > 0 && request_count < IMAGES_PER_REQUEST)
-			{
-				gMessageSystem->sendSemiReliable(host, NULL, NULL);
-			}
-		}
-		mCancelQueue.clear();
-	}
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size)
-{
-	mRequestedTimer.reset();
-	if (index >= mTotalPackets)
-	{
-// 		llwarns << "Received Image Packet " << index << " > max: " << mTotalPackets << " for image: " << mID << llendl;
-		return false;
-	}
-	if (index > 0 && index < mTotalPackets-1 && size != MAX_IMG_PACKET_SIZE)
-	{
-// 		llwarns << "Received bad sized packet: " << index << ", " << size << " != " << MAX_IMG_PACKET_SIZE << " for image: " << mID << llendl;
-		return false;
-	}
-	
-	if (index >= (S32)mPackets.size())
-	{
-		mPackets.resize(index+1, (PacketData*)NULL); // initializes v to NULL pointers
-	}
-	else if (mPackets[index] != NULL)
-	{
-// 		llwarns << "Received duplicate packet: " << index << " for image: " << mID << llendl;
-		return false;
-	}
-
-	mPackets[index] = new PacketData(data, size);
-	while (mLastPacket+1 < (S32)mPackets.size() && mPackets[mLastPacket+1] != NULL)
-	{
-		++mLastPacket;
-	}
-	return true;
-}
-
-bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes,
-										U16 data_size, U8* data)
-{
-	LLTextureFetchWorker* worker = getWorker(id);
-	bool res = true;
-
-	++mPacketCount;
-	
-	if (!worker)
-	{
-// 		llwarns << "Received header for non active worker: " << id << llendl;
-		res = false;
-	}
-	else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK ||
-			 worker->mSentRequest != LLTextureFetchWorker::SENT_SIM)
-	{
-// 		llwarns << "receiveImageHeader for worker: " << id
-// 				<< " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState]
-// 				<< " sent: " << worker->mSentRequest << llendl;
-		res = false;
-	}
-	else if (worker->mLastPacket != -1)
-	{
-		// check to see if we've gotten this packet before
-// 		llwarns << "Received duplicate header for: " << id << llendl;
-		res = false;
-	}
-	else if (!data_size)
-	{
-// 		llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl;
-		res = false;
-	}
-	if (!res)
-	{
-		++mBadPacketCount;
-		mNetworkQueueMutex.lock() ;
-		mCancelQueue[host].insert(id);
-		mNetworkQueueMutex.unlock() ;
-		return false;
-	}
-
-	worker->lockWorkMutex();
-
-	//	Copy header data into image object
-	worker->mImageCodec = codec;
-	worker->mTotalPackets = packets;
-	worker->mFileSize = (S32)totalbytes;	
-	llassert_always(totalbytes > 0);
-	llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize);
-	res = worker->insertPacket(0, data, data_size);
-	worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
-	worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
-	worker->unlockWorkMutex();
-	return res;
-}
-
-bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data)
-{
-	LLTextureFetchWorker* worker = getWorker(id);
-	bool res = true;
-
-	++mPacketCount;
-	
-	if (!worker)
-	{
-// 		llwarns << "Received packet " << packet_num << " for non active worker: " << id << llendl;
-		res = false;
-	}
-	else if (worker->mLastPacket == -1)
-	{
-// 		llwarns << "Received packet " << packet_num << " before header for: " << id << llendl;
-		res = false;
-	}
-	else if (!data_size)
-	{
-// 		llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl;
-		res = false;
-	}
-	if (!res)
-	{
-		++mBadPacketCount;
-		mNetworkQueueMutex.lock() ;
-		mCancelQueue[host].insert(id);
-		mNetworkQueueMutex.unlock() ;
-		return false;
-	}
-
-	worker->lockWorkMutex();
-	
-	res = worker->insertPacket(packet_num, data, data_size);
-	
-	if ((worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) ||
-		(worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK))
-	{
-		worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
-		worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
-	}
-	else
-	{
-// 		llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id
-// 				<< " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl;
-		removeFromNetworkQueue(worker, true); // failsafe
-	}
-
-	if(packet_num >= (worker->mTotalPackets - 1))
-	{
-		static LLCachedControl<bool> log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog");
-		static LLCachedControl<bool> log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator");
-
-		if (log_to_viewer_log || log_to_sim)
-		{
-			U64 timeNow = LLTimer::getTotalTime();
-			mTextureInfo.setRequestSize(id, worker->mFileSize);
-			mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow);
-		}
-	}
-	worker->unlockWorkMutex();
-
-	return res;
-}
-
-//////////////////////////////////////////////////////////////////////////////
-BOOL LLTextureFetch::isFromLocalCache(const LLUUID& id)
-{
-	BOOL from_cache = FALSE ;
-
-	LLTextureFetchWorker* worker = getWorker(id);
-	if (worker)
-	{
-		worker->lockWorkMutex() ;
-		from_cache = worker->mInLocalCache ;
-		worker->unlockWorkMutex() ;
-	}
-
-	return from_cache ;
-}
-
-S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& requested_priority_p,
-								  U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p, bool& can_use_http)
-{
-	S32 state = LLTextureFetchWorker::INVALID;
-	F32 data_progress = 0.0f;
-	F32 requested_priority = 0.0f;
-	F32 fetch_dtime = 999999.f;
-	F32 request_dtime = 999999.f;
-	U32 fetch_priority = 0;
-	
-	LLTextureFetchWorker* worker = getWorker(id);
-	if (worker && worker->haveWork())
-	{
-		worker->lockWorkMutex();
-		state = worker->mState;
-		fetch_dtime = worker->mFetchTimer.getElapsedTimeF32();
-		request_dtime = worker->mRequestedTimer.getElapsedTimeF32();
-		if (worker->mFileSize > 0)
-		{
-			if (state == LLTextureFetchWorker::LOAD_FROM_SIMULATOR)
-			{
-				S32 data_size = FIRST_PACKET_SIZE + (worker->mLastPacket-1) * MAX_IMG_PACKET_SIZE;
-				data_size = llmax(data_size, 0);
-				data_progress = (F32)data_size / (F32)worker->mFileSize;
-			}
-			else if (worker->mFormattedImage.notNull())
-			{
-				data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize;
-			}
-		}
-		if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::WAIT_HTTP_REQ)
-		{
-			requested_priority = worker->mRequestedPriority;
-		}
-		else
-		{
-			requested_priority = worker->mImagePriority;
-		}
-		fetch_priority = worker->getPriority();
-		can_use_http = worker->getCanUseHTTP() ;
-		worker->unlockWorkMutex();
-	}
-	data_progress_p = data_progress;
-	requested_priority_p = requested_priority;
-	fetch_priority_p = fetch_priority;
-	fetch_dtime_p = fetch_dtime;
-	request_dtime_p = request_dtime;
-	return state;
-}
-
-void LLTextureFetch::dump()
-{
-	llinfos << "LLTextureFetch REQUESTS:" << llendl;
-	for (request_queue_t::iterator iter = mRequestQueue.begin();
-		 iter != mRequestQueue.end(); ++iter)
-	{
-		LLQueuedThread::QueuedRequest* qreq = *iter;
-		LLWorkerThread::WorkRequest* wreq = (LLWorkerThread::WorkRequest*)qreq;
-		LLTextureFetchWorker* worker = (LLTextureFetchWorker*)wreq->getWorkerClass();
-		llinfos << " ID: " << worker->mID
-				<< " PRI: " << llformat("0x%08x",wreq->getPriority())
-				<< " STATE: " << worker->sStateDescs[worker->mState]
-				<< llendl;
-	}
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-// cross-thread command methods
-
-void LLTextureFetch::commandSetRegion(U64 region_handle)
-{
-	TFReqSetRegion * req = new TFReqSetRegion(region_handle);
-
-	cmdEnqueue(req);
-}
-
-void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
-										const LLUUID & session_id,
-										const LLUUID & agent_id,
-										LLViewerAssetStats * main_stats)
-{
-	TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats);
-
-	cmdEnqueue(req);
-}
-
-void LLTextureFetch::commandDataBreak()
-{
-	// The pedantically correct way to implement this is to create a command
-	// request object in the above fashion and enqueue it.  However, this is
-	// simple data of an advisorial not operational nature and this case
-	// of shared-write access is tolerable.
-
-	LLTextureFetch::svMetricsDataBreak = true;
-}
-
-void LLTextureFetch::cmdEnqueue(TFRequest * req)
-{
-	lockQueue();
-	mCommands.push_back(req);
-	unlockQueue();
-
-	unpause();
-}
-
-LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue()
-{
-	TFRequest * ret = 0;
-	
-	lockQueue();
-	if (! mCommands.empty())
-	{
-		ret = mCommands.front();
-		mCommands.erase(mCommands.begin());
-	}
-	unlockQueue();
-
-	return ret;
-}
-
-void LLTextureFetch::cmdDoWork()
-{
-	if (mDebugPause)
-	{
-		return;  // debug: don't do any work
-	}
-
-	TFRequest * req = cmdDequeue();
-	if (req)
-	{
-		// One request per pass should really be enough for this.
-		req->doWork(this);
-		delete req;
-	}
-}
-
-
-//////////////////////////////////////////////////////////////////////////////
-
-// Private (anonymous) class methods implementing the command scheme.
-
-namespace
-{
-
-/**
- * Implements the 'Set Region' command.
- *
- * Thread:  Thread1 (TextureFetch)
- */
-bool
-TFReqSetRegion::doWork(LLTextureFetch *)
-{
-	LLViewerAssetStatsFF::set_region_thread1(mRegionHandle);
-
-	return true;
-}
-
-
-TFReqSendMetrics::~TFReqSendMetrics()
-{
-	delete mMainStats;
-	mMainStats = 0;
-}
-
-
-/**
- * Implements the 'Send Metrics' command.  Takes over
- * ownership of the passed LLViewerAssetStats pointer.
- *
- * Thread:  Thread1 (TextureFetch)
- */
-bool
-TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
-{
-	/*
-	 * HTTP POST responder.  Doesn't do much but tries to
-	 * detect simple breaks in recording the metrics stream.
-	 *
-	 * The 'volatile' modifiers don't indicate signals,
-	 * mmap'd memory or threads, really.  They indicate that
-	 * the referenced data is part of a pseudo-closure for
-	 * this responder rather than being required for correct
-	 * operation.
-     *
-     * We don't try very hard with the POST request.  We give
-     * it one shot and that's more-or-less it.  With a proper
-     * refactoring of the LLQueuedThread usage, these POSTs
-     * could be put in a request object and made more reliable.
-	 */
-	class lcl_responder : public LLCurl::Responder
-	{
-	public:
-		lcl_responder(LLTextureFetch * fetcher,
-					  S32 expected_sequence,
-                      volatile const S32 & live_sequence,
-                      volatile bool & reporting_break,
-					  volatile bool & reporting_started)
-			: LLCurl::Responder(),
-			  mFetcher(fetcher),
-              mExpectedSequence(expected_sequence),
-              mLiveSequence(live_sequence),
-			  mReportingBreak(reporting_break),
-			  mReportingStarted(reporting_started)
-			{
-                mFetcher->incrCurlPOSTCount();
-            }
-        
-        ~lcl_responder()
-            {
-                mFetcher->decrCurlPOSTCount();
-            }
-
-		// virtual
-		void error(U32 status_num, const std::string & reason)
-			{
-                if (mLiveSequence == mExpectedSequence)
-                {
-                    mReportingBreak = true;
-                }
-				LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service.  Reason:  "
-									<< reason << LL_ENDL;
-			}
-
-		// virtual
-		void result(const LLSD & content)
-			{
-                if (mLiveSequence == mExpectedSequence)
-                {
-                    mReportingBreak = false;
-                    mReportingStarted = true;
-                }
-			}
-
-	private:
-		LLTextureFetch * mFetcher;
-        S32 mExpectedSequence;
-        volatile const S32 & mLiveSequence;
-		volatile bool & mReportingBreak;
-		volatile bool & mReportingStarted;
-
-	}; // class lcl_responder
-	
-	if (! gViewerAssetStatsThread1)
-		return true;
-
-	static volatile bool reporting_started(false);
-	static volatile S32 report_sequence(0);
-    
-	// We've taken over ownership of the stats copy at this
-	// point.  Get a working reference to it for merging here
-	// but leave it in 'this'.  Destructor will rid us of it.
-	LLViewerAssetStats & main_stats = *mMainStats;
-
-	// Merge existing stats into those from main, convert to LLSD
-	main_stats.merge(*gViewerAssetStatsThread1);
-	LLSD merged_llsd = main_stats.asLLSD(true);
-
-	// Add some additional meta fields to the content
-	merged_llsd["session_id"] = mSessionID;
-	merged_llsd["agent_id"] = mAgentID;
-	merged_llsd["message"] = "ViewerAssetMetrics";					// Identifies the type of metrics
-	merged_llsd["sequence"] = report_sequence;						// Sequence number
-	merged_llsd["initial"] = ! reporting_started;					// Initial data from viewer
-	merged_llsd["break"] = LLTextureFetch::svMetricsDataBreak;		// Break in data prior to this report
-		
-	// Update sequence number
-	if (S32_MAX == ++report_sequence)
-		report_sequence = 0;
-
-	// Limit the size of the stats report if necessary.
-	merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd);
-
-	if (! mCapsURL.empty())
-	{
-		LLCurlRequest::headers_t headers;
-		fetcher->getCurlRequest().post(mCapsURL,
-									   headers,
-									   merged_llsd,
-									   new lcl_responder(fetcher,
-														 report_sequence,
-                                                         report_sequence,
-                                                         LLTextureFetch::svMetricsDataBreak,
-														 reporting_started));
-	}
-	else
-	{
-		LLTextureFetch::svMetricsDataBreak = true;
-	}
-
-	// In QA mode, Metrics submode, log the result for ease of testing
-	if (fetcher->isQAMode())
-	{
-		LL_INFOS("Textures") << merged_llsd << LL_ENDL;
-	}
-
-	gViewerAssetStatsThread1->reset();
-
-	return true;
-}
-
-
-bool
-truncate_viewer_metrics(int max_regions, LLSD & metrics)
-{
-	static const LLSD::String reg_tag("regions");
-	static const LLSD::String duration_tag("duration");
-	
-	LLSD & reg_map(metrics[reg_tag]);
-	if (reg_map.size() <= max_regions)
-	{
-		return false;
-	}
-
-	// Build map of region hashes ordered by duration
-	typedef std::multimap<LLSD::Real, int> reg_ordered_list_t;
-	reg_ordered_list_t regions_by_duration;
-
-	int ind(0);
-	LLSD::array_const_iterator it_end(reg_map.endArray());
-	for (LLSD::array_const_iterator it(reg_map.beginArray()); it_end != it; ++it, ++ind)
-	{
-		LLSD::Real duration = (*it)[duration_tag].asReal();
-		regions_by_duration.insert(reg_ordered_list_t::value_type(duration, ind));
-	}
-
-	// Build a replacement regions array with the longest-persistence regions
-	LLSD new_region(LLSD::emptyArray());
-	reg_ordered_list_t::const_reverse_iterator it2_end(regions_by_duration.rend());
-	reg_ordered_list_t::const_reverse_iterator it2(regions_by_duration.rbegin());
-	for (int i(0); i < max_regions && it2_end != it2; ++i, ++it2)
-	{
-		new_region.append(reg_map[it2->second]);
-	}
-	reg_map = new_region;
-	
-	return true;
-}
-
-} // end of anonymous namespace
-
-
-
+/** 
+ * @file lltexturefetch.cpp
+ * @brief Object which fetches textures from the cache and/or network
+ *
+ * $LicenseInfo:firstyear=2000&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include <iostream>
+#include <map>
+
+#include "llstl.h"
+
+#include "lltexturefetch.h"
+
+#include "llcurl.h"
+#include "lldir.h"
+#include "llhttpclient.h"
+#include "llhttpstatuscodes.h"
+#include "llimage.h"
+#include "llimagej2c.h"
+#include "llimageworker.h"
+#include "llworkerthread.h"
+#include "message.h"
+
+#include "llagent.h"
+#include "lltexturecache.h"
+#include "llviewercontrol.h"
+#include "llviewertexturelist.h"
+#include "llviewertexture.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llviewerassetstats.h"
+#include "llworld.h"
+
+//////////////////////////////////////////////////////////////////////////////
+class LLTextureFetchWorker : public LLWorkerClass
+{
+	friend class LLTextureFetch;
+	friend class HTTPGetResponder;
+	
+private:
+	class CacheReadResponder : public LLTextureCache::ReadResponder
+	{
+	public:
+		CacheReadResponder(LLTextureFetch* fetcher, const LLUUID& id, LLImageFormatted* image)
+			: mFetcher(fetcher), mID(id)
+		{
+			setImage(image);
+		}
+		virtual void completed(bool success)
+		{
+			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
+			if (worker)
+			{
+ 				worker->callbackCacheRead(success, mFormattedImage, mImageSize, mImageLocal);
+			}
+		}
+	private:
+		LLTextureFetch* mFetcher;
+		LLUUID mID;
+	};
+
+	class CacheWriteResponder : public LLTextureCache::WriteResponder
+	{
+	public:
+		CacheWriteResponder(LLTextureFetch* fetcher, const LLUUID& id)
+			: mFetcher(fetcher), mID(id)
+		{
+		}
+		virtual void completed(bool success)
+		{
+			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
+			if (worker)
+			{
+				worker->callbackCacheWrite(success);
+			}
+		}
+	private:
+		LLTextureFetch* mFetcher;
+		LLUUID mID;
+	};
+	
+	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, LLImageRaw* raw, LLImageRaw* aux)
+		{
+			LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
+			if (worker)
+			{
+ 				worker->callbackDecoded(success, raw, aux);
+			}
+		}
+	private:
+		LLTextureFetch* mFetcher;
+		LLUUID mID;
+		LLTextureFetchWorker* mWorker; // debug only (may get deleted from under us, use mFetcher/mID)
+	};
+
+	struct Compare
+	{
+		// lhs < rhs
+		bool operator()(const LLTextureFetchWorker* lhs, const LLTextureFetchWorker* rhs) const
+		{
+			// greater priority is "less"
+			const F32 lpriority = lhs->mImagePriority;
+			const F32 rpriority = rhs->mImagePriority;
+			if (lpriority > rpriority) // higher priority
+				return true;
+			else if (lpriority < rpriority)
+				return false;
+			else
+				return lhs < rhs;
+		}
+	};
+	
+public:
+	/*virtual*/ bool doWork(S32 param); // Called from LLWorkerThread::processRequest()
+	/*virtual*/ void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD)
+	/*virtual*/ bool deleteOK(); // called from update() (WORK THREAD)
+
+	~LLTextureFetchWorker();
+	// void relese() { --mActiveCount; }
+
+	S32 callbackHttpGet(const LLChannelDescriptors& channels,
+						 const LLIOPipe::buffer_ptr_t& buffer,
+						 bool partial, 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)
+	{
+		LLMutexLock lock(&mWorkMutex);
+
+		mGetStatus = status;
+		mGetReason = reason;
+	}
+
+	void setCanUseHTTP(bool can_use_http) { mCanUseHTTP = can_use_http; }
+	bool getCanUseHTTP() const { return mCanUseHTTP; }
+
+	LLTextureFetch & getFetcher() { return *mFetcher; }
+	
+protected:
+	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)
+
+	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 writeToCacheComplete();
+	
+	void lockWorkMutex() { mWorkMutex.lock(); }
+	void unlockWorkMutex() { mWorkMutex.unlock(); }
+
+private:
+	enum e_state // mState
+	{
+		// NOTE: Affects LLTextureBar::draw in lltextureview.cpp (debug hack)
+		INVALID = 0,
+		INIT,
+		LOAD_FROM_TEXTURE_CACHE,
+		CACHE_POST,
+		LOAD_FROM_NETWORK,
+		LOAD_FROM_SIMULATOR,
+		SEND_HTTP_REQ,
+		WAIT_HTTP_REQ,
+		DECODE_IMAGE,
+		DECODE_IMAGE_UPDATE,
+		WRITE_TO_CACHE,
+		WAIT_ON_WRITE,
+		DONE
+	};
+	enum e_request_state // mSentRequest
+	{
+		UNSENT = 0,
+		QUEUED = 1,
+		SENT_SIM = 2
+	};
+	enum e_write_to_cache_state //mWriteToCacheState
+	{
+		NOT_WRITE = 0,
+		CAN_WRITE = 1,
+		SHOULD_WRITE = 2
+	};
+	static const char* sStateDescs[];
+	e_state mState;
+	e_write_to_cache_state mWriteToCacheState;
+	LLTextureFetch* mFetcher;
+	LLPointer<LLImageFormatted> mFormattedImage;
+	LLPointer<LLImageRaw> mRawImage;
+	LLPointer<LLImageRaw> mAuxImage;
+	LLUUID mID;
+	LLHost mHost;
+	std::string mUrl;
+	U8 mType;
+	F32 mImagePriority;
+	U32 mWorkPriority;
+	F32 mRequestedPriority;
+	S32 mDesiredDiscard;
+	S32 mSimRequestedDiscard;
+	S32 mRequestedDiscard;
+	S32 mLoadedDiscard;
+	S32 mDecodedDiscard;
+	LLFrameTimer mRequestedTimer;
+	LLFrameTimer mFetchTimer;
+	LLTextureCache::handle_t mCacheReadHandle;
+	LLTextureCache::handle_t mCacheWriteHandle;
+	U8* mBuffer;
+	S32 mBufferSize;
+	S32 mRequestedSize;
+	S32 mDesiredSize;
+	S32 mFileSize;
+	S32 mCachedSize;	
+	e_request_state mSentRequest;
+	handle_t mDecodeHandle;
+	BOOL mLoaded;
+	BOOL mDecoded;
+	BOOL mWritten;
+	BOOL mNeedsAux;
+	BOOL mHaveAllData;
+	BOOL mInLocalCache;
+	bool mCanUseHTTP ;
+	bool mCanUseNET ; //can get from asset server.
+	S32 mHTTPFailCount;
+	S32 mRetryAttempt;
+	S32 mActiveCount;
+	U32 mGetStatus;
+	std::string mGetReason;
+	
+	// Work Data
+	LLMutex mWorkMutex;
+	struct PacketData
+	{
+		PacketData(U8* data, S32 size) { mData = data; mSize = size; }
+		~PacketData() { clearData(); }
+		void clearData() { delete[] mData; mData = NULL; }
+		U8* mData;
+		U32 mSize;
+	};
+	std::vector<PacketData*> mPackets;
+	S32 mFirstPacket;
+	S32 mLastPacket;
+	U16 mTotalPackets;
+	U8 mImageCodec;
+
+	LLViewerAssetStats::duration_t mMetricsStartTime;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+class HTTPGetResponder : public LLCurl::Responder
+{
+	LOG_CLASS(HTTPGetResponder);
+public:
+	HTTPGetResponder(LLTextureFetch* fetcher, const LLUUID& id, U64 startTime, S32 requestedSize, U32 offset, bool redir)
+		: mFetcher(fetcher), mID(id), mStartTime(startTime), mRequestedSize(requestedSize), mOffset(offset), mFollowRedir(redir)
+	{
+	}
+	~HTTPGetResponder()
+	{
+	}
+
+	virtual void completedRaw(U32 status, const std::string& reason,
+							  const LLChannelDescriptors& channels,
+							  const LLIOPipe::buffer_ptr_t& buffer)
+	{
+		static LLCachedControl<bool> log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog");
+		static LLCachedControl<bool> log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator");
+		static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
+
+		if (log_to_viewer_log || log_to_sim)
+		{
+			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;
+		LLTextureFetchWorker* worker = mFetcher->getWorker(mID);
+		if (worker)
+		{
+			bool success = false;
+			bool partial = false;
+			if (HTTP_OK <= status &&  status < HTTP_MULTIPLE_CHOICES)
+			{
+				success = true;
+				if (HTTP_PARTIAL_CONTENT == status) // partial information
+				{
+					partial = true;
+				}
+			}
+
+			if (!success)
+			{
+				worker->setGetStatus(status, reason);
+// 				llwarns << "CURL GET FAILED, status:" << status << " reason:" << reason << llendl;
+			}
+			
+			S32 data_size = worker->callbackHttpGet(channels, buffer, partial, success);
+			
+			if(log_texture_traffic && data_size > 0)
+			{
+				LLViewerTexture* tex = LLViewerTextureManager::findTexture(mID) ;
+				if(tex)
+				{
+					gTotalTextureBytesPerBoostLevel[tex->getBoostLevel()] += data_size ;
+				}
+			}
+
+			mFetcher->removeFromHTTPQueue(mID, data_size);
+
+			if (worker->mMetricsStartTime)
+			{
+				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
+															  true,
+															  LLImageBase::TYPE_AVATAR_BAKE == worker->mType,
+															  LLViewerAssetStatsFF::get_timestamp() - worker->mMetricsStartTime);
+				worker->mMetricsStartTime = 0;
+			}
+			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
+														 true,
+														 LLImageBase::TYPE_AVATAR_BAKE == worker->mType);
+		}
+		else
+		{
+			mFetcher->removeFromHTTPQueue(mID);
+ 			llwarns << "Worker not found: " << mID << llendl;
+		}
+	}
+
+	virtual bool followRedir()
+	{
+		return mFollowRedir;
+	}
+	
+private:
+	LLTextureFetch* mFetcher;
+	LLUUID mID;
+	U64 mStartTime;
+	S32 mRequestedSize;
+	U32 mOffset;
+	bool mFollowRedir;
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Cross-thread messaging for asset metrics.
+
+/**
+ * @brief Base class for cross-thread requests made of the fetcher
+ *
+ * I believe the intent of the LLQueuedThread class was to
+ * have these operations derived from LLQueuedThread::QueuedRequest
+ * but the texture fetcher has elected to manage the queue
+ * in its own manner.  So these are free-standing objects which are
+ * managed in simple FIFO order on the mCommands queue of the
+ * LLTextureFetch object.
+ *
+ * What each represents is a simple command sent from an
+ * outside thread into the TextureFetch thread to be processed
+ * in order and in a timely fashion (though not an absolute
+ * higher priority than other operations of the thread).
+ * Each operation derives a new class from the base customizing
+ * members, constructors and the doWork() method to effect
+ * the command.
+ *
+ * The flow is one-directional.  There are two global instances
+ * of the LLViewerAssetStats collector, one for the main program's
+ * thread pointed to by gViewerAssetStatsMain and one for the
+ * TextureFetch thread pointed to by gViewerAssetStatsThread1.
+ * Common operations has each thread recording metrics events
+ * into the respective collector unconcerned with locking and
+ * the state of any other thread.  But when the agent moves into
+ * a different region or the metrics timer expires and a report
+ * needs to be sent back to the grid, messaging across threads
+ * is required to distribute data and perform global actions.
+ * In pseudo-UML, it looks like:
+ *
+ *                       Main                 Thread1
+ *                        .                      .
+ *                        .                      .
+ *                     +-----+                   .
+ *                     | AM  |                   .
+ *                     +--+--+                   .
+ *      +-------+         |                      .
+ *      | Main  |      +--+--+                   .
+ *      |       |      | SRE |---.               .
+ *      | Stats |      +-----+    \              .
+ *      |       |         |        \  (uuid)  +-----+
+ *      | Coll. |      +--+--+      `-------->| SR  |
+ *      +-------+      | MSC |                +--+--+
+ *         | ^         +-----+                   |
+ *         | |  (uuid)  / .                   +-----+ (uuid)
+ *         |  `--------'  .                   | MSC |---------.
+ *         |              .                   +-----+         |
+ *         |           +-----+                   .            v
+ *         |           | TE  |                   .        +-------+
+ *         |           +--+--+                   .        | Thd1  |
+ *         |              |                      .        |       |
+ *         |           +-----+                   .        | Stats |
+ *          `--------->| RSC |                   .        |       |
+ *                     +--+--+                   .        | Coll. |
+ *                        |                      .        +-------+
+ *                     +--+--+                   .            |
+ *                     | SME |---.               .            |
+ *                     +-----+    \              .            |
+ *                        .        \ (clone)  +-----+         |
+ *                        .         `-------->| SM  |         |
+ *                        .                   +--+--+         |
+ *                        .                      |            |
+ *                        .                   +-----+         |
+ *                        .                   | RSC |<--------'
+ *                        .                   +-----+
+ *                        .                      |
+ *                        .                   +-----+
+ *                        .                   | CP  |--> HTTP POST
+ *                        .                   +-----+
+ *                        .                      .
+ *                        .                      .
+ *
+ *
+ * Key:
+ *
+ * SRE - Set Region Enqueued.  Enqueue a 'Set Region' command in
+ *       the other thread providing the new UUID of the region.
+ *       TFReqSetRegion carries the data.
+ * SR  - Set Region.  New region UUID is sent to the thread-local
+ *       collector.
+ * SME - Send Metrics Enqueued.  Enqueue a 'Send Metrics' command
+ *       including an ownership transfer of a cloned LLViewerAssetStats.
+ *       TFReqSendMetrics carries the data.
+ * SM  - Send Metrics.  Global metrics reporting operation.  Takes
+ *       the cloned stats from the command, merges it with the
+ *       thread's local stats, converts to LLSD and sends it on
+ *       to the grid.
+ * AM  - Agent Moved.  Agent has completed some sort of move to a
+ *       new region.
+ * TE  - Timer Expired.  Metrics timer has expired (on the order
+ *       of 10 minutes).
+ * CP  - CURL Post
+ * MSC - Modify Stats Collector.  State change in the thread-local
+ *       collector.  Typically a region change which affects the
+ *       global pointers used to find the 'current stats'.
+ * RSC - Read Stats Collector.  Extract collector data cloning it
+ *       (i.e. deep copy) when necessary.
+ *
+ */
+class LLTextureFetch::TFRequest // : public LLQueuedThread::QueuedRequest
+{
+public:
+	// Default ctors and assignment operator are correct.
+
+	virtual ~TFRequest()
+		{}
+
+	// Patterned after QueuedRequest's method but expected behavior
+	// is different.  Always expected to complete on the first call
+	// and work dispatcher will assume the same and delete the
+	// request after invocation.
+	virtual bool doWork(LLTextureFetch * fetcher) = 0;
+};
+
+namespace 
+{
+
+/**
+ * @brief Implements a 'Set Region' cross-thread command.
+ *
+ * When an agent moves to a new region, subsequent metrics need
+ * to be binned into a new or existing stats collection in 1:1
+ * relationship with the region.  We communicate this region
+ * change across the threads involved in the communication with
+ * this message.
+ *
+ * Corresponds to LLTextureFetch::commandSetRegion()
+ */
+class TFReqSetRegion : public LLTextureFetch::TFRequest
+{
+public:
+	TFReqSetRegion(U64 region_handle)
+		: LLTextureFetch::TFRequest(),
+		  mRegionHandle(region_handle)
+		{}
+	TFReqSetRegion & operator=(const TFReqSetRegion &);	// Not defined
+
+	virtual ~TFReqSetRegion()
+		{}
+
+	virtual bool doWork(LLTextureFetch * fetcher);
+		
+public:
+	const U64 mRegionHandle;
+};
+
+
+/**
+ * @brief Implements a 'Send Metrics' cross-thread command.
+ *
+ * This is the big operation.  The main thread gathers metrics
+ * for a period of minutes into LLViewerAssetStats and other
+ * objects then makes a snapshot of the data by cloning the
+ * collector.  This command transfers the clone, along with a few
+ * additional arguments (UUIDs), handing ownership to the
+ * TextureFetch thread.  It then merges its own data into the
+ * cloned copy, converts to LLSD and kicks off an HTTP POST of
+ * the resulting data to the currently active metrics collector.
+ *
+ * Corresponds to LLTextureFetch::commandSendMetrics()
+ */
+class TFReqSendMetrics : public LLTextureFetch::TFRequest
+{
+public:
+    /**
+	 * Construct the 'Send Metrics' command to have the TextureFetch
+	 * thread add and log metrics data.
+	 *
+	 * @param	caps_url		URL of a "ViewerMetrics" Caps target
+	 *							to receive the data.  Does not have to
+	 *							be associated with a particular region.
+	 *
+	 * @param	session_id		UUID of the agent's session.
+	 *
+	 * @param	agent_id		UUID of the agent.  (Being pure here...)
+	 *
+	 * @param	main_stats		Pointer to a clone of the main thread's
+	 *							LLViewerAssetStats data.  Thread1 takes
+	 *							ownership of the copy and disposes of it
+	 *							when done.
+	 */
+	TFReqSendMetrics(const std::string & caps_url,
+					 const LLUUID & session_id,
+					 const LLUUID & agent_id,
+					 LLViewerAssetStats * main_stats)
+		: LLTextureFetch::TFRequest(),
+		  mCapsURL(caps_url),
+		  mSessionID(session_id),
+		  mAgentID(agent_id),
+		  mMainStats(main_stats)
+		{}
+	TFReqSendMetrics & operator=(const TFReqSendMetrics &);	// Not defined
+
+	virtual ~TFReqSendMetrics();
+
+	virtual bool doWork(LLTextureFetch * fetcher);
+		
+public:
+	const std::string mCapsURL;
+	const LLUUID mSessionID;
+	const LLUUID mAgentID;
+	LLViewerAssetStats * mMainStats;
+};
+
+/*
+ * Examines the merged viewer metrics report and if found to be too long,
+ * will attempt to truncate it in some reasonable fashion.
+ *
+ * @param		max_regions		Limit of regions allowed in report.
+ *
+ * @param		metrics			Full, merged viewer metrics report.
+ *
+ * @returns		If data was truncated, returns true.
+ */
+bool truncate_viewer_metrics(int max_regions, LLSD & metrics);
+
+} // end of anonymous namespace
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+//static
+const char* LLTextureFetchWorker::sStateDescs[] = {
+	"INVALID",
+	"INIT",
+	"LOAD_FROM_TEXTURE_CACHE",
+	"CACHE_POST",
+	"LOAD_FROM_NETWORK",
+	"LOAD_FROM_SIMULATOR",
+	"SEND_HTTP_REQ",
+	"WAIT_HTTP_REQ",
+	"DECODE_IMAGE",
+	"DECODE_IMAGE_UPDATE",
+	"WRITE_TO_CACHE",
+	"WAIT_ON_WRITE",
+	"DONE",
+};
+
+// static
+volatile bool LLTextureFetch::svMetricsDataBreak(true);	// Start with a data break
+
+// 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
+										   S32 discard,			// Desired discard
+										   S32 size)			// Desired size
+	: LLWorkerClass(fetcher, "TextureFetch"),
+	  mState(INIT),
+	  mWriteToCacheState(NOT_WRITE),
+	  mFetcher(fetcher),
+	  mID(id),
+	  mHost(host),
+	  mUrl(url),
+	  mImagePriority(priority),
+	  mWorkPriority(0),
+	  mRequestedPriority(0.f),
+	  mDesiredDiscard(-1),
+	  mSimRequestedDiscard(-1),
+	  mRequestedDiscard(-1),
+	  mLoadedDiscard(-1),
+	  mDecodedDiscard(-1),
+	  mCacheReadHandle(LLTextureCache::nullHandle()),
+	  mCacheWriteHandle(LLTextureCache::nullHandle()),
+	  mBuffer(NULL),
+	  mBufferSize(0),
+	  mRequestedSize(0),
+	  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),
+	  mCanUseHTTP(true),
+	  mHTTPFailCount(0),
+	  mRetryAttempt(0),
+	  mActiveCount(0),
+	  mGetStatus(0),
+	  mWorkMutex(NULL),
+	  mFirstPacket(0),
+	  mLastPacket(-1),
+	  mTotalPackets(0),
+	  mImageCodec(IMG_CODEC_INVALID),
+	  mMetricsStartTime(0)
+{
+	mCanUseNET = mUrl.empty() ;
+
+	calcWorkPriority();
+	mType = host.isOk() ? LLImageBase::TYPE_AVATAR_BAKE : LLImageBase::TYPE_NORMAL;
+// 	llinfos << "Create: " << mID << " mHost:" << host << " Discard=" << discard << llendl;
+	if (!mFetcher->mDebugPause)
+	{
+		U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
+		addWork(0, work_priority );
+	}
+	setDesiredDiscard(discard, size);
+}
+
+LLTextureFetchWorker::~LLTextureFetchWorker()
+{
+// 	llinfos << "Destroy: " << mID
+// 			<< " Decoded=" << mDecodedDiscard
+// 			<< " Requested=" << mRequestedDiscard
+// 			<< " Desired=" << mDesiredDiscard << llendl;
+	llassert_always(!haveWork());
+	lockWorkMutex();
+	if (mCacheReadHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache)
+	{
+		mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
+	}
+	if (mCacheWriteHandle != LLTextureCache::nullHandle() && mFetcher->mTextureCache)
+	{
+		mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
+	}
+	mFormattedImage = NULL;
+	clearPackets();
+	unlockWorkMutex();
+	mFetcher->removeFromHTTPQueue(mID);
+}
+
+void LLTextureFetchWorker::clearPackets()
+{
+	for_each(mPackets.begin(), mPackets.end(), DeletePointer());
+	mPackets.clear();
+	mTotalPackets = 0;
+	mLastPacket = -1;
+	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 <= LLViewerFetchedTexture::maxDecodePriority());
+	static const F32 PRIORITY_SCALE = (F32)LLWorkerThread::PRIORITY_LOWBITS / LLViewerFetchedTexture::maxDecodePriority();
+
+	mWorkPriority = llmin((U32)LLWorkerThread::PRIORITY_LOWBITS, (U32)(mImagePriority * PRIORITY_SCALE));
+	return mWorkPriority;
+}
+
+// mWorkMutex is locked
+void LLTextureFetchWorker::setDesiredDiscard(S32 discard, S32 size)
+{
+	bool prioritize = false;
+	if (mDesiredDiscard != discard)
+	{
+		if (!haveWork())
+		{
+			calcWorkPriority();
+			if (!mFetcher->mDebugPause)
+			{
+				U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
+				addWork(0, work_priority);
+			}
+		}
+		else if (mDesiredDiscard < discard)
+		{
+			prioritize = true;
+		}
+		mDesiredDiscard = discard;
+		mDesiredSize = size;
+	}
+	else if (size > mDesiredSize)
+	{
+		mDesiredSize = size;
+		prioritize = true;
+	}
+	mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE);
+	if ((prioritize && mState == INIT) || mState == DONE)
+	{
+		mState = INIT;
+		U32 work_priority = mWorkPriority | LLWorkerThread::PRIORITY_HIGH;
+		setPriority(work_priority);
+	}
+}
+
+void LLTextureFetchWorker::setImagePriority(F32 priority)
+{
+// 	llassert_always(priority >= 0 && priority <= LLViewerTexture::maxDecodePriority());
+	F32 delta = fabs(priority - mImagePriority);
+	if (delta > (mImagePriority * .05f) || mState == DONE)
+	{
+		mImagePriority = priority;
+		calcWorkPriority();
+		U32 work_priority = mWorkPriority | (getPriority() & LLWorkerThread::PRIORITY_HIGHBITS);
+		setPriority(work_priority);
+	}
+}
+
+void LLTextureFetchWorker::resetFormattedData()
+{
+	delete[] mBuffer;
+	mBuffer = NULL;
+	mBufferSize = 0;
+	if (mFormattedImage.notNull())
+	{
+		mFormattedImage->deleteData();
+	}
+	mHaveAllData = FALSE;
+}
+
+// Called from MAIN thread
+void LLTextureFetchWorker::startWork(S32 param)
+{
+	llassert(mFormattedImage.isNull());
+}
+
+#include "llviewertexturelist.h" // debug
+
+// Called from LLWorkerThread::processRequest()
+bool LLTextureFetchWorker::doWork(S32 param)
+{
+	LLMutexLock lock(&mWorkMutex);
+
+	if ((mFetcher->isQuitting() || getFlags(LLWorkerClass::WCF_DELETE_REQUESTED)))
+	{
+		if (mState < DECODE_IMAGE)
+		{
+			return true; // abort
+		}
+	}
+
+	if(mImagePriority < F_ALMOST_ZERO)
+	{
+		if (mState == INIT || mState == LOAD_FROM_NETWORK || mState == LOAD_FROM_SIMULATOR)
+		{
+			return true; // abort
+		}
+	}
+	if(mState > CACHE_POST && !mCanUseNET && !mCanUseHTTP)
+	{
+		//nowhere to get data, abort.
+		return true ;
+	}
+
+	if (mFetcher->mDebugPause)
+	{
+		return false; // debug: don't do any work
+	}
+	if (mID == mFetcher->mDebugID)
+	{
+		mFetcher->mDebugCount++; // for setting breakpoints
+	}
+
+	if (mState != DONE)
+	{
+		mFetchTimer.reset();
+	}
+
+	if (mState == INIT)
+	{		
+		mRawImage = NULL ;
+		mRequestedDiscard = -1;
+		mLoadedDiscard = -1;
+		mDecodedDiscard = -1;
+		mRequestedSize = 0;
+		mFileSize = 0;
+		mCachedSize = 0;
+		mLoaded = FALSE;
+		mSentRequest = UNSENT;
+		mDecoded  = FALSE;
+		mWritten  = FALSE;
+		delete[] mBuffer;
+		mBuffer = NULL;
+		mBufferSize = 0;
+		mHaveAllData = FALSE;
+		clearPackets(); // TODO: Shouldn't be necessary
+		mCacheReadHandle = LLTextureCache::nullHandle();
+		mCacheWriteHandle = LLTextureCache::nullHandle();
+		mState = LOAD_FROM_TEXTURE_CACHE;
+		mDesiredSize = llmax(mDesiredSize, TEXTURE_CACHE_ENTRY_SIZE); // min desired size is TEXTURE_CACHE_ENTRY_SIZE
+		LL_DEBUGS("Texture") << mID << ": Priority: " << llformat("%8.0f",mImagePriority)
+							 << " Desired Discard: " << mDesiredDiscard << " Desired Size: " << mDesiredSize << LL_ENDL;
+		// fall through
+	}
+
+	if (mState == LOAD_FROM_TEXTURE_CACHE)
+	{
+		if (mCacheReadHandle == LLTextureCache::nullHandle())
+		{
+			U32 cache_priority = mWorkPriority;
+			S32 offset = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
+			S32 size = mDesiredSize - offset;
+			if (size <= 0)
+			{
+				mState = CACHE_POST;
+				return false;
+			}
+			mFileSize = 0;
+			mLoaded = FALSE;			
+			
+			if (mUrl.compare(0, 7, "file://") == 0)
+			{
+				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
+
+				// read file from local disk
+				std::string filename = mUrl.substr(7, std::string::npos);
+				CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
+				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(filename, mID, cache_priority,
+																		  offset, size, responder);
+			}
+			else if (mUrl.empty())
+			{
+				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
+
+				CacheReadResponder* responder = new CacheReadResponder(mFetcher, mID, mFormattedImage);
+				mCacheReadHandle = mFetcher->mTextureCache->readFromCache(mID, cache_priority,
+																		  offset, size, responder);
+			}
+			else if(mCanUseHTTP)
+			{
+				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;
+			}
+			else
+			{
+				setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+				mState = LOAD_FROM_NETWORK;
+			}
+		}
+
+		if (mLoaded)
+		{
+			// Make sure request is complete. *TODO: make this auto-complete
+			if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, false))
+			{
+				mCacheReadHandle = LLTextureCache::nullHandle();
+				mState = CACHE_POST;
+				// fall through
+			}
+			else
+			{
+				return false;
+			}
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	if (mState == CACHE_POST)
+	{
+		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;
+			mWriteToCacheState = NOT_WRITE ;
+			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 (mUrl.compare(0, 7, "file://") == 0)
+			{
+				// failed to load local file, we're done.
+				return true;
+			}
+			// need more data
+			else
+			{
+				LL_DEBUGS("Texture") << mID << ": Not in Cache" << LL_ENDL;
+				mState = LOAD_FROM_NETWORK;
+			}
+			// fall through
+		}
+	}
+
+	if (mState == LOAD_FROM_NETWORK)
+	{
+		static LLCachedControl<bool> use_http(gSavedSettings,"ImagePipelineUseHTTP");
+
+// 		if (mHost != LLHost::invalid) get_url = false;
+		if ( use_http && mCanUseHTTP && mUrl.empty())//get http url.
+		{
+			LLViewerRegion* region = NULL;
+			if (mHost == LLHost::invalid)
+				region = gAgent.getRegion();
+			else
+				region = LLWorld::getInstance()->getRegion(mHost);
+
+			if (region)
+			{
+				std::string http_url = region->getHttpUrl() ;
+				if (!http_url.empty())
+				{
+					mUrl = http_url + "/?texture_id=" + mID.asString().c_str();
+					mWriteToCacheState = CAN_WRITE ; //because this texture has a fixed texture id.
+				}
+				else
+				{
+					mCanUseHTTP = false ;
+				}
+			}
+			else
+			{
+				// This will happen if not logged in or if a region deoes not have HTTP Texture enabled
+				//llwarns << "Region not found for host: " << mHost << llendl;
+				mCanUseHTTP = false;
+			}
+		}
+		if (mCanUseHTTP && !mUrl.empty())
+		{
+			mState = LLTextureFetchWorker::SEND_HTTP_REQ;
+			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+			if(mWriteToCacheState != NOT_WRITE)
+			{
+				mWriteToCacheState = CAN_WRITE ;
+			}
+			// don't return, fall through to next state
+		}
+		else if (mSentRequest == UNSENT && mCanUseNET)
+		{
+			// Add this to the network queue and sit here.
+			// LLTextureFetch::update() will send off a request which will change our state
+			mWriteToCacheState = CAN_WRITE ;
+			mRequestedSize = mDesiredSize;
+			mRequestedDiscard = mDesiredDiscard;
+			mSentRequest = QUEUED;
+			mFetcher->addToNetworkQueue(this);
+			if (! mMetricsStartTime)
+			{
+				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+			}
+			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+														 false,
+														 LLImageBase::TYPE_AVATAR_BAKE == mType);
+			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);
+			//if (! mMetricsStartTime)
+			//{
+			//   mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+			//}
+			//LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE, false,
+			//                                             LLImageBase::TYPE_AVATAR_BAKE == mType);
+			//setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			return false;
+		}
+	}
+	
+	if (mState == LOAD_FROM_SIMULATOR)
+	{
+		if (mFormattedImage.isNull())
+		{
+			mFormattedImage = new LLImageJ2C;
+		}
+		if (processSimulatorPackets())
+		{
+			LL_DEBUGS("Texture") << mID << ": Loaded from Sim. Bytes: " << mFormattedImage->getDataSize() << LL_ENDL;
+			mFetcher->removeFromNetworkQueue(this, false);
+			if (mFormattedImage.isNull() || !mFormattedImage->getDataSize())
+			{
+				// processSimulatorPackets() failed
+// 				llwarns << "processSimulatorPackets() failed to load buffer" << llendl;
+				return true; // failed
+			}
+			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+			mState = DECODE_IMAGE;
+			mWriteToCacheState = SHOULD_WRITE;
+
+			if (mMetricsStartTime)
+			{
+				LLViewerAssetStatsFF::record_response_thread1(LLViewerAssetType::AT_TEXTURE,
+															  false,
+															  LLImageBase::TYPE_AVATAR_BAKE == mType,
+															  LLViewerAssetStatsFF::get_timestamp() - mMetricsStartTime);
+				mMetricsStartTime = 0;
+			}
+			LLViewerAssetStatsFF::record_dequeue_thread1(LLViewerAssetType::AT_TEXTURE,
+														 false,
+														 LLImageBase::TYPE_AVATAR_BAKE == mType);
+		}
+		else
+		{
+			mFetcher->addToNetworkQueue(this); // failsafe
+			if (! mMetricsStartTime)
+			{
+				mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+			}
+			LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+														 false,
+														 LLImageBase::TYPE_AVATAR_BAKE == mType);
+			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+		}
+		return false;
+	}
+	
+	if (mState == SEND_HTTP_REQ)
+	{
+		if(mCanUseHTTP)
+		{
+			//NOTE:
+			//control the number of the http requests issued for:
+			//1, not openning too many file descriptors at the same time;
+			//2, control the traffic of http so udp gets bandwidth.
+			//
+			static const S32 MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE = 8 ;
+			if(mFetcher->getNumHTTPRequests() > MAX_NUM_OF_HTTP_REQUESTS_IN_QUEUE)
+			{
+				return false ; //wait.
+			}
+
+			mFetcher->removeFromNetworkQueue(this, false);
+			
+			S32 cur_size = 0;
+			if (mFormattedImage.notNull())
+			{
+				cur_size = mFormattedImage->getDataSize(); // amount of data we already have
+				if (mFormattedImage->getDiscardLevel() == 0)
+				{
+					if(cur_size > 0)
+					{
+						// We already have all the data, just decode it
+						mLoadedDiscard = mFormattedImage->getDiscardLevel();
+						mState = DECODE_IMAGE;
+						return false;
+					}
+					else
+					{
+						return true ; //abort.
+					}
+				}
+			}
+			mRequestedSize = mDesiredSize;
+			mRequestedDiscard = mDesiredDiscard;
+			mRequestedSize -= cur_size;
+			S32 offset = cur_size;
+			mBufferSize = cur_size; // This will get modified by callbackHttpGet()
+			
+			bool res = false;
+			if (!mUrl.empty())
+			{
+				mLoaded = FALSE;
+				mGetStatus = 0;
+				mGetReason.clear();
+				LL_DEBUGS("Texture") << "HTTP GET: " << mID << " Offset: " << offset
+									 << " Bytes: " << mRequestedSize
+									 << " Bandwidth(kbps): " << mFetcher->getTextureBandwidth() << "/" << mFetcher->mMaxBandwidth
+									 << LL_ENDL;
+				setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+				mState = WAIT_HTTP_REQ;	
+
+				mFetcher->addToHTTPQueue(mID);
+				if (! mMetricsStartTime)
+				{
+					mMetricsStartTime = LLViewerAssetStatsFF::get_timestamp();
+				}
+				LLViewerAssetStatsFF::record_enqueue_thread1(LLViewerAssetType::AT_TEXTURE,
+															 true,
+															 LLImageBase::TYPE_AVATAR_BAKE == mType);
+
+				// 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, true));
+			}
+			if (!res)
+			{
+				llwarns << "HTTP GET request failed for " << mID << llendl;
+				resetFormattedData();
+				++mHTTPFailCount;
+				return true; // failed
+			}
+			// fall through
+		}
+		else //can not use http fetch.
+		{
+			return true ; //abort
+		}
+	}
+	
+	if (mState == WAIT_HTTP_REQ)
+	{
+		if (mLoaded)
+		{
+			S32 cur_size = mFormattedImage.notNull() ? mFormattedImage->getDataSize() : 0;
+			if (mRequestedSize < 0)
+			{
+				S32 max_attempts;
+				if (mGetStatus == HTTP_NOT_FOUND)
+				{
+					mHTTPFailCount = max_attempts = 1; // Don't retry
+					llwarns << "Texture missing from server (404): " << mUrl << llendl;
+
+					//roll back to try UDP
+					if(mCanUseNET)
+					{
+						mState = INIT ;
+						mCanUseHTTP = false ;
+						setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+						return false ;
+					}
+				}
+				else if (mGetStatus == HTTP_SERVICE_UNAVAILABLE)
+				{
+					// *TODO: Should probably introduce a timer here to delay future HTTP requsts
+					// for a short time (~1s) to ease server load? Ideally the server would queue
+					// requests instead of returning 503... we already limit the number pending.
+					++mHTTPFailCount;
+					max_attempts = mHTTPFailCount+1; // Keep retrying
+					LL_INFOS_ONCE("Texture") << "Texture server busy (503): " << mUrl << LL_ENDL;
+				}
+				else
+				{
+					const S32 HTTP_MAX_RETRY_COUNT = 3;
+					max_attempts = HTTP_MAX_RETRY_COUNT + 1;
+					++mHTTPFailCount;
+					llinfos << "HTTP GET failed for: " << mUrl
+							<< " Status: " << mGetStatus << " Reason: '" << mGetReason << "'"
+							<< " Attempt:" << mHTTPFailCount+1 << "/" << max_attempts << llendl;
+				}
+
+				if (mHTTPFailCount >= max_attempts)
+				{
+					if (cur_size > 0)
+					{
+						// Use available data
+						mLoadedDiscard = mFormattedImage->getDiscardLevel();
+						mState = DECODE_IMAGE;
+						return false; 
+					}
+					else
+					{
+						resetFormattedData();
+						mState = DONE;
+						return true; // failed
+					}
+				}
+				else
+				{
+					mState = SEND_HTTP_REQ;
+					return false; // retry
+				}
+			}
+			
+			llassert_always(mBufferSize == cur_size + mRequestedSize);
+			if(!mBufferSize)//no data received.
+			{
+				delete[] mBuffer; 
+				mBuffer = NULL;
+
+				//abort.
+				mState = DONE;
+				return true;
+			}
+
+			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
+				}
+			}
+						
+			if (mHaveAllData && mRequestedDiscard == 0) //the image file is fully loaded.
+			{
+				mFileSize = mBufferSize;
+			}
+			else //the file size is unknown.
+			{
+				mFileSize = mBufferSize + 1 ; //flag the file is not fully loaded.
+			}
+			
+			U8* buffer = new U8[mBufferSize];
+			if (cur_size > 0)
+			{
+				memcpy(buffer, mFormattedImage->getData(), cur_size);
+			}
+			memcpy(buffer + cur_size, mBuffer, mRequestedSize); // append
+			// NOTE: setData releases current data and owns new data (buffer)
+			mFormattedImage->setData(buffer, mBufferSize);
+			// delete temp data
+			delete[] mBuffer; // Note: not 'buffer' (assigned in setData())
+			mBuffer = NULL;
+			mBufferSize = 0;
+			mLoadedDiscard = mRequestedDiscard;
+			mState = DECODE_IMAGE;
+			if(mWriteToCacheState != NOT_WRITE)
+			{
+				mWriteToCacheState = SHOULD_WRITE ;
+			}
+			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+			return false;
+		}
+		else
+		{
+			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			return false;
+		}
+	}
+	
+	if (mState == DECODE_IMAGE)
+	{
+		static LLCachedControl<bool> textures_decode_disabled(gSavedSettings,"TextureDecodeDisabled");
+		if(textures_decode_disabled)
+		{
+			// for debug use, don't decode
+			mState = DONE;
+			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			return true;
+		}
+
+		if (mDesiredDiscard < 0)
+		{
+			// We aborted, don't decode
+			mState = DONE;
+			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			return true;
+		}
+		
+		if (mFormattedImage->getDataSize() <= 0)
+		{
+			//llerrs << "Decode entered with invalid mFormattedImage. ID = " << mID << llendl;
+			
+			//abort, don't decode
+			mState = DONE;
+			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			return true;
+		}
+		if (mLoadedDiscard < 0)
+		{
+			//llerrs << "Decode entered with invalid mLoadedDiscard. ID = " << mID << llendl;
+
+			//abort, don't decode
+			mState = DONE;
+			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			return true;
+		}
+		setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
+		mRawImage = NULL;
+		mAuxImage = NULL;
+		llassert_always(mFormattedImage.notNull());
+		S32 discard = mHaveAllData ? 0 : mLoadedDiscard;
+		U32 image_priority = LLWorkerThread::PRIORITY_NORMAL | mWorkPriority;
+		mDecoded  = FALSE;
+		mState = DECODE_IMAGE_UPDATE;
+		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 (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);
+					mState = INIT;
+					return false;
+				}
+				else
+				{
+// 					llwarns << "UNABLE TO LOAD TEXTURE: " << mID << " RETRIES: " << mRetryAttempt << llendl;
+					mState = DONE; // failed
+				}
+			}
+			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;
+			}
+			// fall through
+		}
+		else
+		{
+			return false;
+		}
+	}
+
+	if (mState == WRITE_TO_CACHE)
+	{
+		if (mWriteToCacheState != SHOULD_WRITE || mFormattedImage.isNull())
+		{
+			// 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;
+		}
+		S32 datasize = mFormattedImage->getDataSize();
+		if(mFileSize < datasize)//This could happen when http fetching and sim fetching mixed.
+		{
+			if(mHaveAllData)
+			{
+				mFileSize = datasize ;
+			}
+			else
+			{
+				mFileSize = datasize + 1 ; //flag not fully loaded.
+			}
+		}
+		llassert_always(datasize);
+		setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority); // Set priority first since Responder may change it
+		U32 cache_priority = mWorkPriority;
+		mWritten = FALSE;
+		mState = WAIT_ON_WRITE;
+		CacheWriteResponder* responder = new CacheWriteResponder(mFetcher, mID);
+		mCacheWriteHandle = mFetcher->mTextureCache->writeToCache(mID, cache_priority,
+																  mFormattedImage->getData(), datasize,
+																  mFileSize, responder);
+		// fall through
+	}
+	
+	if (mState == WAIT_ON_WRITE)
+	{
+		if (writeToCacheComplete())
+		{
+			mState = DONE;
+			// fall through
+		}
+		else
+		{
+			if (mDesiredDiscard < mDecodedDiscard)
+			{
+				// We're waiting for this write to complete before we can receive more data
+				// (we can't touch mFormattedImage until the write completes)
+				// Prioritize the write
+				mFetcher->mTextureCache->prioritizeWrite(mCacheWriteHandle);
+			}
+			return false;
+		}
+	}
+
+	if (mState == DONE)
+	{
+		if (mDecodedDiscard >= 0 && mDesiredDiscard < mDecodedDiscard)
+		{
+			// More data was requested, return to INIT
+			mState = INIT;
+			setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+			return false;
+		}
+		else
+		{
+			setPriority(LLWorkerThread::PRIORITY_LOW | mWorkPriority);
+			return true;
+		}
+	}
+	
+	return false;
+}
+
+// Called from MAIN thread
+void LLTextureFetchWorker::endWork(S32 param, bool aborted)
+{
+	if (mDecodeHandle != 0)
+	{
+		mFetcher->mImageDecodeThread->abortRequest(mDecodeHandle, false);
+		mDecodeHandle = 0;
+	}
+	mFormattedImage = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// virtual
+void LLTextureFetchWorker::finishWork(S32 param, bool completed)
+{
+	// The following are required in case the work was aborted
+	if (mCacheReadHandle != LLTextureCache::nullHandle())
+	{
+		mFetcher->mTextureCache->readComplete(mCacheReadHandle, true);
+		mCacheReadHandle = LLTextureCache::nullHandle();
+	}
+	if (mCacheWriteHandle != LLTextureCache::nullHandle())
+	{
+		mFetcher->mTextureCache->writeComplete(mCacheWriteHandle, true);
+		mCacheWriteHandle = LLTextureCache::nullHandle();
+	}
+}
+
+// virtual
+bool LLTextureFetchWorker::deleteOK()
+{
+	bool delete_ok = true;
+	// Allow any pending reads or writes to complete
+	if (mCacheReadHandle != LLTextureCache::nullHandle())
+	{
+		if (mFetcher->mTextureCache->readComplete(mCacheReadHandle, true))
+		{
+			mCacheReadHandle = LLTextureCache::nullHandle();
+		}
+		else
+		{
+			delete_ok = false;
+		}
+	}
+	if (mCacheWriteHandle != LLTextureCache::nullHandle())
+	{
+		if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle))
+		{
+			mCacheWriteHandle = LLTextureCache::nullHandle();
+		}
+		else
+		{
+			delete_ok = false;
+		}
+	}
+
+	if ((haveWork() &&
+		 // not ok to delete from these states
+		 ((mState >= WRITE_TO_CACHE && mState <= WAIT_ON_WRITE))))
+	{
+		delete_ok = false;
+	}
+	
+	return delete_ok;
+}
+
+void LLTextureFetchWorker::removeFromCache()
+{
+	if (!mInLocalCache)
+	{
+		mFetcher->mTextureCache->removeFromCache(mID);
+	}
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+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;
+	}
+	
+	if (mLastPacket >= mFirstPacket)
+	{
+		S32 buffer_size = mFormattedImage->getDataSize();
+		for (S32 i = mFirstPacket; i<=mLastPacket; i++)
+		{
+			llassert_always(mPackets[i]);
+			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
+			if (have_all_data)
+			{
+				mHaveAllData = TRUE;
+			}
+			S32 cur_size = mFormattedImage->getDataSize();
+			if (buffer_size > cur_size)
+			{
+				/// We have new data
+				U8* buffer = new U8[buffer_size];
+				S32 offset = 0;
+				if (cur_size > 0 && mFirstPacket > 0)
+				{
+					memcpy(buffer, mFormattedImage->getData(), cur_size);
+					offset = cur_size;
+				}
+				for (S32 i=mFirstPacket; i<=mLastPacket; i++)
+				{
+					memcpy(buffer + offset, mPackets[i]->mData, mPackets[i]->mSize);
+					offset += mPackets[i]->mSize;
+				}
+				// NOTE: setData releases current data
+				mFormattedImage->setData(buffer, buffer_size);
+			}
+			mLoadedDiscard = mRequestedDiscard;
+			return true;
+		}
+	}
+	return false;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+S32 LLTextureFetchWorker::callbackHttpGet(const LLChannelDescriptors& channels,
+										   const LLIOPipe::buffer_ptr_t& buffer,
+										   bool partial, bool success)
+{
+	S32 data_size = 0 ;
+
+	LLMutexLock lock(&mWorkMutex);
+
+	if (mState != WAIT_HTTP_REQ)
+	{
+		llwarns << "callbackHttpGet for unrequested fetch worker: " << mID
+				<< " req=" << mSentRequest << " state= " << mState << llendl;
+		return data_size;
+	}
+	if (mLoaded)
+	{
+		llwarns << "Duplicate callback for " << mID.asString() << llendl;
+		return data_size ; // ignore duplicate callback
+	}
+	if (success)
+	{
+		// get length of stream:
+		data_size = buffer->countAfter(channels.in(), NULL);		
+	
+		LL_DEBUGS("Texture") << "HTTP RECEIVED: " << mID.asString() << " Bytes: " << data_size << LL_ENDL;
+		if (data_size > 0)
+		{
+			// *TODO: set the formatted image data here directly to avoid the copy
+			mBuffer = new U8[data_size];
+			buffer->readAfter(channels.in(), NULL, mBuffer, data_size);
+			mBufferSize += data_size;
+			if (data_size < mRequestedSize && mRequestedDiscard == 0)
+			{
+				mHaveAllData = TRUE;
+			}
+			else if (data_size > mRequestedSize)
+			{
+				// *TODO: This shouldn't be happening any more
+				llwarns << "data_size = " << data_size << " > requested: " << mRequestedSize << llendl;
+				mHaveAllData = TRUE;
+				llassert_always(mDecodeHandle == 0);
+				mFormattedImage = NULL; // discard any previous data we had
+				mBufferSize = data_size;
+			}
+		}
+		else
+		{
+			// We requested data but received none (and no error),
+			// so presumably we have all of it
+			mHaveAllData = TRUE;
+		}
+		mRequestedSize = data_size;
+	}
+	else
+	{
+		mRequestedSize = -1; // error
+	}
+	mLoaded = TRUE;
+	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+
+	return data_size ;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void LLTextureFetchWorker::callbackCacheRead(bool success, LLImageFormatted* image,
+											 S32 imagesize, BOOL islocal)
+{
+	LLMutexLock lock(&mWorkMutex);
+	if (mState != LOAD_FROM_TEXTURE_CACHE)
+	{
+// 		llwarns << "Read callback for " << mID << " with state = " << mState << llendl;
+		return;
+	}
+	if (success)
+	{
+		llassert_always(imagesize >= 0);
+		mFileSize = imagesize;
+		mFormattedImage = image;
+		mImageCodec = image->getCodec();
+		mInLocalCache = islocal;
+		if (mFileSize != 0 && mFormattedImage->getDataSize() >= mFileSize)
+		{
+			mHaveAllData = TRUE;
+		}
+	}
+	mLoaded = TRUE;
+	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+}
+
+void LLTextureFetchWorker::callbackCacheWrite(bool success)
+{
+	LLMutexLock lock(&mWorkMutex);
+	if (mState != WAIT_ON_WRITE)
+	{
+// 		llwarns << "Write callback for " << mID << " with state = " << mState << llendl;
+		return;
+	}
+	mWritten = TRUE;
+	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+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;
+	}
+	llassert_always(mFormattedImage.notNull());
+	
+	mDecodeHandle = 0;
+	if (success)
+	{
+		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;
+	}
+	else
+	{
+		llwarns << "DECODE FAILED: " << mID << " Discard: " << (S32)mFormattedImage->getDiscardLevel() << llendl;
+		removeFromCache();
+		mDecodedDiscard = -1; // Redundant, here for clarity and paranoia
+	}
+	mDecoded = TRUE;
+// 	llinfos << mID << " : DECODE COMPLETE " << llendl;
+	setPriority(LLWorkerThread::PRIORITY_HIGH | mWorkPriority);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool LLTextureFetchWorker::writeToCacheComplete()
+{
+	// Complete write to cache
+	if (mCacheWriteHandle != LLTextureCache::nullHandle())
+	{
+		if (!mWritten)
+		{
+			return false;
+		}
+		if (mFetcher->mTextureCache->writeComplete(mCacheWriteHandle))
+		{
+			mCacheWriteHandle = LLTextureCache::nullHandle();
+		}
+		else
+		{
+			return false;
+		}
+	}
+	return true;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+// public
+
+LLTextureFetch::LLTextureFetch(LLTextureCache* cache, LLImageDecodeThread* imagedecodethread, bool threaded, bool qa_mode)
+	: LLWorkerThread("TextureFetch", threaded),
+	  mDebugCount(0),
+	  mDebugPause(FALSE),
+	  mPacketCount(0),
+	  mBadPacketCount(0),
+	  mQueueMutex(getAPRPool()),
+	  mNetworkQueueMutex(getAPRPool()),
+	  mTextureCache(cache),
+	  mImageDecodeThread(imagedecodethread),
+	  mTextureBandwidth(0),
+	  mHTTPTextureBits(0),
+	  mTotalHTTPRequests(0),
+	  mCurlGetRequest(NULL),
+	  mQAMode(qa_mode)
+{
+	mCurlPOSTRequestCount = 0;
+	mMaxBandwidth = gSavedSettings.getF32("ThrottleBandwidthKBPS");
+	mTextureInfo.setUpLogging(gSavedSettings.getBOOL("LogTextureDownloadsToViewerLog"), gSavedSettings.getBOOL("LogTextureDownloadsToSimulator"), gSavedSettings.getU32("TextureLoggingThreshold"));
+}
+
+LLTextureFetch::~LLTextureFetch()
+{
+	clearDeleteList() ;
+
+	while (! mCommands.empty())
+	{
+		TFRequest * req(mCommands.front());
+		mCommands.erase(mCommands.begin());
+		delete req;
+	}
+	
+	// ~LLQueuedThread() called here
+}
+
+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, bool can_use_http)
+{
+	if (mDebugPause)
+	{
+		return false;
+	}
+	
+	LLTextureFetchWorker* worker = getWorker(id) ;
+	if (worker)
+	{
+		if (worker->mHost != host)
+		{
+			llwarns << "LLTextureFetch::createRequest " << id << " called with multiple hosts: "
+					<< host << " != " << worker->mHost << llendl;
+			removeRequest(worker, true);
+			worker = NULL;
+			return false;
+		}
+	}
+
+	S32 desired_size;
+	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
+		desired_size = MAX_IMAGE_DATA_SIZE;
+		desired_discard = 0;
+	}
+	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
+		// was compressed - this code ensures that when we request the entire image,
+		// we really do get it.)
+		desired_size = MAX_IMAGE_DATA_SIZE;
+	}
+	else if (w*h*c > 0)
+	{
+		// If the requester knows the dimensions of the image,
+		// this will calculate how much data we need without having to parse the header
+
+		desired_size = LLImageJ2C::calcDataSizeJ2C(w, h, c, desired_discard);
+	}
+	else
+	{
+		desired_size = TEXTURE_CACHE_ENTRY_SIZE;
+		desired_discard = MAX_DISCARD_LEVEL;
+	}
+
+	
+	if (worker)
+	{
+		if (worker->wasAborted())
+		{
+			return false; // need to wait for previous aborted request to complete
+		}
+		worker->lockWorkMutex();
+		worker->mActiveCount++;
+		worker->mNeedsAux = needs_aux;
+		worker->setImagePriority(priority);
+		worker->setDesiredDiscard(desired_discard, desired_size);
+		worker->setCanUseHTTP(can_use_http) ;
+		if (!worker->haveWork())
+		{
+			worker->mState = LLTextureFetchWorker::INIT;
+			worker->unlockWorkMutex();
+
+			worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
+		}
+		else
+		{
+			worker->unlockWorkMutex();
+		}
+	}
+	else
+	{
+		worker = new LLTextureFetchWorker(this, url, id, host, priority, desired_discard, desired_size);
+		lockQueue() ;
+		mRequestMap[id] = worker;
+		unlockQueue() ;
+
+		worker->lockWorkMutex();
+		worker->mActiveCount++;
+		worker->mNeedsAux = needs_aux;
+		worker->setCanUseHTTP(can_use_http) ;
+		worker->unlockWorkMutex();
+	}
+	
+// 	llinfos << "REQUESTED: " << id << " Discard: " << desired_discard << llendl;
+	return true;
+}
+
+// protected
+void LLTextureFetch::addToNetworkQueue(LLTextureFetchWorker* worker)
+{
+	lockQueue() ;
+	bool in_request_map = (mRequestMap.find(worker->mID) != mRequestMap.end()) ;
+	unlockQueue() ;
+
+	LLMutexLock lock(&mNetworkQueueMutex);
+	if (in_request_map)
+	{
+		// only add to the queue if in the request map
+		// i.e. a delete has not been requested
+		mNetworkQueue.insert(worker->mID);
+	}
+	for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
+		 iter1 != mCancelQueue.end(); ++iter1)
+	{
+		iter1->second.erase(worker->mID);
+	}
+}
+
+void LLTextureFetch::removeFromNetworkQueue(LLTextureFetchWorker* worker, bool cancel)
+{
+	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);
+	mTotalHTTPRequests++;
+}
+
+void LLTextureFetch::removeFromHTTPQueue(const LLUUID& id, S32 received_size)
+{
+	LLMutexLock lock(&mNetworkQueueMutex);
+	mHTTPTextureQueue.erase(id);
+	mHTTPTextureBits += received_size * 8; // Approximate - does not include header bits	
+}
+
+void LLTextureFetch::deleteRequest(const LLUUID& id, bool cancel)
+{
+	lockQueue() ;
+	LLTextureFetchWorker* worker = getWorkerAfterLock(id);
+	if (worker)
+	{		
+		size_t erased_1 = mRequestMap.erase(worker->mID);
+		unlockQueue() ;
+
+		llassert_always(erased_1 > 0) ;
+
+		removeFromNetworkQueue(worker, cancel);
+		llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
+
+		worker->scheduleDelete();	
+	}
+	else
+	{
+		unlockQueue() ;
+	}
+}
+
+void LLTextureFetch::removeRequest(LLTextureFetchWorker* worker, bool cancel)
+{
+	lockQueue() ;
+	size_t erased_1 = mRequestMap.erase(worker->mID);
+	unlockQueue() ;
+
+	llassert_always(erased_1 > 0) ;
+	removeFromNetworkQueue(worker, cancel);
+	llassert_always(!(worker->getFlags(LLWorkerClass::WCF_DELETE_REQUESTED))) ;
+
+	worker->scheduleDelete();	
+}
+
+S32 LLTextureFetch::getNumRequests() 
+{ 
+	lockQueue() ;
+	S32 size = (S32)mRequestMap.size(); 
+	unlockQueue() ;
+
+	return size ;
+}
+
+S32 LLTextureFetch::getNumHTTPRequests() 
+{ 
+	mNetworkQueueMutex.lock() ;
+	S32 size = (S32)mHTTPTextureQueue.size(); 
+	mNetworkQueueMutex.unlock() ;
+
+	return size ;
+}
+
+U32 LLTextureFetch::getTotalNumHTTPRequests()
+{
+	mNetworkQueueMutex.lock() ;
+	U32 size = mTotalHTTPRequests ;
+	mNetworkQueueMutex.unlock() ;
+
+	return size ;
+}
+
+// call lockQueue() first!
+LLTextureFetchWorker* LLTextureFetch::getWorkerAfterLock(const LLUUID& id)
+{
+	LLTextureFetchWorker* res = NULL;
+	map_t::iterator iter = mRequestMap.find(id);
+	if (iter != mRequestMap.end())
+	{
+		res = iter->second;
+	}
+	return res;
+}
+
+LLTextureFetchWorker* LLTextureFetch::getWorker(const LLUUID& id)
+{
+	LLMutexLock lock(&mQueueMutex) ;
+
+	return getWorkerAfterLock(id) ;
+}
+
+
+bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level,
+										LLPointer<LLImageRaw>& raw, LLPointer<LLImageRaw>& aux)
+{
+	bool res = false;
+	LLTextureFetchWorker* worker = getWorker(id);
+	if (worker)
+	{
+		if (worker->wasAborted())
+		{
+			res = true;
+		}
+		else if (!worker->haveWork())
+		{
+			// Should only happen if we set mDebugPause...
+			if (!mDebugPause)
+			{
+// 				llwarns << "Adding work for inactive worker: " << id << llendl;
+				worker->addWork(0, LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
+			}
+		}
+		else if (worker->checkWork())
+		{
+			worker->lockWorkMutex();
+			discard_level = worker->mDecodedDiscard;
+			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->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;
+				raw = worker->mRawImage;
+				aux = worker->mAuxImage;
+			}
+			worker->unlockWorkMutex();
+		}
+	}
+	else
+	{
+		res = true;
+	}
+	return res;
+}
+
+bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
+{
+	bool res = false;
+	LLTextureFetchWorker* worker = getWorker(id);
+	if (worker)
+	{
+		worker->lockWorkMutex();
+		worker->setImagePriority(priority);
+		worker->unlockWorkMutex();
+		res = true;
+	}
+	return res;
+}
+
+// Replicates and expands upon the base class's
+// getPending() implementation.  getPending() and
+// runCondition() replicate one another's logic to
+// an extent and are sometimes used for the same
+// function (deciding whether or not to sleep/pause
+// a thread).  So the implementations need to stay
+// in step, at least until this can be refactored and
+// the redundancy eliminated.
+//
+// May be called from any thread
+
+//virtual
+S32 LLTextureFetch::getPending()
+{
+	S32 res;
+	lockData();
+    {
+        LLMutexLock lock(&mQueueMutex);
+        
+        res = mRequestQueue.size();
+        res += mCurlPOSTRequestCount;
+        res += mCommands.size();
+    }
+	unlockData();
+	return res;
+}
+
+// virtual
+bool LLTextureFetch::runCondition()
+{
+	// Caller is holding the lock on LLThread's condition variable.
+	
+	// LLQueuedThread, unlike its base class LLThread, makes this a
+	// private method which is unfortunate.  I want to use it directly
+	// but I'm going to have to re-implement the logic here (or change
+	// declarations, which I don't want to do right now).
+	//
+	// Changes here may need to be reflected in getPending().
+	
+	bool have_no_commands(false);
+	{
+		LLMutexLock lock(&mQueueMutex);
+		
+		have_no_commands = mCommands.empty();
+	}
+	
+    bool have_no_curl_requests(0 == mCurlPOSTRequestCount);
+	
+	return ! (have_no_commands
+			  && have_no_curl_requests
+			  && (mRequestQueue.empty() && mIdleThread));		// From base class
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// MAIN THREAD (unthreaded envs), WORKER THREAD (threaded envs)
+void LLTextureFetch::commonUpdate()
+{
+	// Run a cross-thread command, if any.
+	cmdDoWork();
+	
+	// Update Curl on same thread as mCurlGetRequest was constructed
+	S32 processed = mCurlGetRequest->process();
+	if (processed > 0)
+	{
+		lldebugs << "processed: " << processed << " messages." << llendl;
+	}
+}
+
+
+// MAIN THREAD
+//virtual
+S32 LLTextureFetch::update(U32 max_time_ms)
+{
+	static LLCachedControl<F32> band_width(gSavedSettings,"ThrottleBandwidthKBPS");
+
+	{
+		mNetworkQueueMutex.lock() ;
+		mMaxBandwidth = band_width ;
+
+		gTextureList.sTextureBits += mHTTPTextureBits ;
+		mHTTPTextureBits = 0 ;
+
+		mNetworkQueueMutex.unlock() ;
+	}
+
+	S32 res = LLWorkerThread::update(max_time_ms);
+	
+	if (!mDebugPause)
+	{
+		sendRequestListToSimulators();
+	}
+
+	if (!mThreaded)
+	{
+		commonUpdate();
+	}
+
+	return res;
+}
+
+//called in the MAIN thread after the TextureCacheThread shuts down.
+void LLTextureFetch::shutDownTextureCacheThread() 
+{
+	if(mTextureCache)
+	{
+		llassert_always(mTextureCache->isQuitting() || mTextureCache->isStopped()) ;
+		mTextureCache = NULL ;
+	}
+}
+	
+//called in the MAIN thread after the ImageDecodeThread shuts down.
+void LLTextureFetch::shutDownImageDecodeThread() 
+{
+	if(mImageDecodeThread)
+	{
+		llassert_always(mImageDecodeThread->isQuitting() || mImageDecodeThread->isStopped()) ;
+		mImageDecodeThread = NULL ;
+	}
+}
+
+// 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();
+	
+	commonUpdate();
+
+#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 SIM_LAZY_FLUSH_TIMEOUT = 10.0f; // temp
+	const F32 MIN_REQUEST_TIME = 1.0f;
+	const F32 MIN_DELTA_PRIORITY = 1000.f;
+
+	// 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();
+	
+	// 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++;
+		LLTextureFetchWorker* req = getWorker(*curiter);
+		if (!req)
+		{
+			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->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 >= SIM_LAZY_FLUSH_TIMEOUT))
+			{
+				requests[req->mHost].insert(req);
+			}
+		}
+	}
+	}
+
+	for (work_request_map_t::iterator iter1 = requests.begin();
+		 iter1 != requests.end(); ++iter1)
+	{
+		LLHost host = iter1->first;
+		// invalid host = use agent host
+		if (host == LLHost::invalid)
+		{
+			host = gAgent.getRegionHost();
+		}
+
+		S32 sim_request_count = 0;
+		
+		for (request_list_t::iterator iter2 = iter1->second.begin();
+			 iter2 != iter1->second.end(); ++iter2)
+		{
+			LLTextureFetchWorker* req = *iter2;
+			if (gMessageSystem)
+			{
+				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);
+					gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+					gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+				}
+				S32 packet = req->mLastPacket + 1;
+				gMessageSystem->nextBlockFast(_PREHASH_RequestImage);
+				gMessageSystem->addUUIDFast(_PREHASH_Image, req->mID);
+				gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, (S8)req->mDesiredDiscard);
+				gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, req->mImagePriority);
+				gMessageSystem->addU32Fast(_PREHASH_Packet, packet);
+				gMessageSystem->addU8Fast(_PREHASH_Type, req->mType);
+// 				llinfos << "IMAGE REQUEST: " << req->mID << " Discard: " << req->mDesiredDiscard
+// 						<< " Packet: " << packet << " Priority: " << req->mImagePriority << llendl;
+
+				static LLCachedControl<bool> log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog");
+				static LLCachedControl<bool> log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator");
+				if (log_to_viewer_log || log_to_sim)
+				{
+					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->unlockWorkMutex();
+				sim_request_count++;
+				if (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;
+				}
+			}
+		}
+		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
+	{
+	LLMutexLock lock2(&mNetworkQueueMutex);
+	if (gMessageSystem && !mCancelQueue.empty())
+	{
+		for (cancel_queue_t::iterator iter1 = mCancelQueue.begin();
+			 iter1 != mCancelQueue.end(); ++iter1)
+		{
+			LLHost host = iter1->first;
+			if (host == LLHost::invalid)
+			{
+				host = gAgent.getRegionHost();
+			}
+			S32 request_count = 0;
+			for (queue_t::iterator iter2 = iter1->second.begin();
+				 iter2 != iter1->second.end(); ++iter2)
+			{
+				if (0 == request_count)
+				{
+					gMessageSystem->newMessageFast(_PREHASH_RequestImage);
+					gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+					gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+					gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+				}
+				gMessageSystem->nextBlockFast(_PREHASH_RequestImage);
+				gMessageSystem->addUUIDFast(_PREHASH_Image, *iter2);
+				gMessageSystem->addS8Fast(_PREHASH_DiscardLevel, -1);
+				gMessageSystem->addF32Fast(_PREHASH_DownloadPriority, 0);
+				gMessageSystem->addU32Fast(_PREHASH_Packet, 0);
+				gMessageSystem->addU8Fast(_PREHASH_Type, 0);
+// 				llinfos << "CANCELING IMAGE REQUEST: " << (*iter2) << llendl;
+
+				request_count++;
+				if (request_count >= IMAGES_PER_REQUEST)
+				{
+					gMessageSystem->sendSemiReliable(host, NULL, NULL);
+					request_count = 0;
+				}
+			}
+			if (request_count > 0 && request_count < IMAGES_PER_REQUEST)
+			{
+				gMessageSystem->sendSemiReliable(host, NULL, NULL);
+			}
+		}
+		mCancelQueue.clear();
+	}
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+bool LLTextureFetchWorker::insertPacket(S32 index, U8* data, S32 size)
+{
+	mRequestedTimer.reset();
+	if (index >= mTotalPackets)
+	{
+// 		llwarns << "Received Image Packet " << index << " > max: " << mTotalPackets << " for image: " << mID << llendl;
+		return false;
+	}
+	if (index > 0 && index < mTotalPackets-1 && size != MAX_IMG_PACKET_SIZE)
+	{
+// 		llwarns << "Received bad sized packet: " << index << ", " << size << " != " << MAX_IMG_PACKET_SIZE << " for image: " << mID << llendl;
+		return false;
+	}
+	
+	if (index >= (S32)mPackets.size())
+	{
+		mPackets.resize(index+1, (PacketData*)NULL); // initializes v to NULL pointers
+	}
+	else if (mPackets[index] != NULL)
+	{
+// 		llwarns << "Received duplicate packet: " << index << " for image: " << mID << llendl;
+		return false;
+	}
+
+	mPackets[index] = new PacketData(data, size);
+	while (mLastPacket+1 < (S32)mPackets.size() && mPackets[mLastPacket+1] != NULL)
+	{
+		++mLastPacket;
+	}
+	return true;
+}
+
+bool LLTextureFetch::receiveImageHeader(const LLHost& host, const LLUUID& id, U8 codec, U16 packets, U32 totalbytes,
+										U16 data_size, U8* data)
+{
+	LLTextureFetchWorker* worker = getWorker(id);
+	bool res = true;
+
+	++mPacketCount;
+	
+	if (!worker)
+	{
+// 		llwarns << "Received header for non active worker: " << id << llendl;
+		res = false;
+	}
+	else if (worker->mState != LLTextureFetchWorker::LOAD_FROM_NETWORK ||
+			 worker->mSentRequest != LLTextureFetchWorker::SENT_SIM)
+	{
+// 		llwarns << "receiveImageHeader for worker: " << id
+// 				<< " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState]
+// 				<< " sent: " << worker->mSentRequest << llendl;
+		res = false;
+	}
+	else if (worker->mLastPacket != -1)
+	{
+		// check to see if we've gotten this packet before
+// 		llwarns << "Received duplicate header for: " << id << llendl;
+		res = false;
+	}
+	else if (!data_size)
+	{
+// 		llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl;
+		res = false;
+	}
+	if (!res)
+	{
+		++mBadPacketCount;
+		mNetworkQueueMutex.lock() ;
+		mCancelQueue[host].insert(id);
+		mNetworkQueueMutex.unlock() ;
+		return false;
+	}
+
+	worker->lockWorkMutex();
+
+	//	Copy header data into image object
+	worker->mImageCodec = codec;
+	worker->mTotalPackets = packets;
+	worker->mFileSize = (S32)totalbytes;	
+	llassert_always(totalbytes > 0);
+	llassert_always(data_size == FIRST_PACKET_SIZE || data_size == worker->mFileSize);
+	res = worker->insertPacket(0, data, data_size);
+	worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
+	worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
+	worker->unlockWorkMutex();
+	return res;
+}
+
+bool LLTextureFetch::receiveImagePacket(const LLHost& host, const LLUUID& id, U16 packet_num, U16 data_size, U8* data)
+{
+	LLTextureFetchWorker* worker = getWorker(id);
+	bool res = true;
+
+	++mPacketCount;
+	
+	if (!worker)
+	{
+// 		llwarns << "Received packet " << packet_num << " for non active worker: " << id << llendl;
+		res = false;
+	}
+	else if (worker->mLastPacket == -1)
+	{
+// 		llwarns << "Received packet " << packet_num << " before header for: " << id << llendl;
+		res = false;
+	}
+	else if (!data_size)
+	{
+// 		llwarns << "Img: " << id << ":" << " Empty Image Header" << llendl;
+		res = false;
+	}
+	if (!res)
+	{
+		++mBadPacketCount;
+		mNetworkQueueMutex.lock() ;
+		mCancelQueue[host].insert(id);
+		mNetworkQueueMutex.unlock() ;
+		return false;
+	}
+
+	worker->lockWorkMutex();
+	
+	res = worker->insertPacket(packet_num, data, data_size);
+	
+	if ((worker->mState == LLTextureFetchWorker::LOAD_FROM_SIMULATOR) ||
+		(worker->mState == LLTextureFetchWorker::LOAD_FROM_NETWORK))
+	{
+		worker->setPriority(LLWorkerThread::PRIORITY_HIGH | worker->mWorkPriority);
+		worker->mState = LLTextureFetchWorker::LOAD_FROM_SIMULATOR;
+	}
+	else
+	{
+// 		llwarns << "receiveImagePacket " << packet_num << "/" << worker->mLastPacket << " for worker: " << id
+// 				<< " in state: " << LLTextureFetchWorker::sStateDescs[worker->mState] << llendl;
+		removeFromNetworkQueue(worker, true); // failsafe
+	}
+
+	if(packet_num >= (worker->mTotalPackets - 1))
+	{
+		static LLCachedControl<bool> log_to_viewer_log(gSavedSettings,"LogTextureDownloadsToViewerLog");
+		static LLCachedControl<bool> log_to_sim(gSavedSettings,"LogTextureDownloadsToSimulator");
+
+		if (log_to_viewer_log || log_to_sim)
+		{
+			U64 timeNow = LLTimer::getTotalTime();
+			mTextureInfo.setRequestSize(id, worker->mFileSize);
+			mTextureInfo.setRequestCompleteTimeAndLog(id, timeNow);
+		}
+	}
+	worker->unlockWorkMutex();
+
+	return res;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+BOOL LLTextureFetch::isFromLocalCache(const LLUUID& id)
+{
+	BOOL from_cache = FALSE ;
+
+	LLTextureFetchWorker* worker = getWorker(id);
+	if (worker)
+	{
+		worker->lockWorkMutex() ;
+		from_cache = worker->mInLocalCache ;
+		worker->unlockWorkMutex() ;
+	}
+
+	return from_cache ;
+}
+
+S32 LLTextureFetch::getFetchState(const LLUUID& id, F32& data_progress_p, F32& requested_priority_p,
+								  U32& fetch_priority_p, F32& fetch_dtime_p, F32& request_dtime_p, bool& can_use_http)
+{
+	S32 state = LLTextureFetchWorker::INVALID;
+	F32 data_progress = 0.0f;
+	F32 requested_priority = 0.0f;
+	F32 fetch_dtime = 999999.f;
+	F32 request_dtime = 999999.f;
+	U32 fetch_priority = 0;
+	
+	LLTextureFetchWorker* worker = getWorker(id);
+	if (worker && worker->haveWork())
+	{
+		worker->lockWorkMutex();
+		state = worker->mState;
+		fetch_dtime = worker->mFetchTimer.getElapsedTimeF32();
+		request_dtime = worker->mRequestedTimer.getElapsedTimeF32();
+		if (worker->mFileSize > 0)
+		{
+			if (state == LLTextureFetchWorker::LOAD_FROM_SIMULATOR)
+			{
+				S32 data_size = FIRST_PACKET_SIZE + (worker->mLastPacket-1) * MAX_IMG_PACKET_SIZE;
+				data_size = llmax(data_size, 0);
+				data_progress = (F32)data_size / (F32)worker->mFileSize;
+			}
+			else if (worker->mFormattedImage.notNull())
+			{
+				data_progress = (F32)worker->mFormattedImage->getDataSize() / (F32)worker->mFileSize;
+			}
+		}
+		if (state >= LLTextureFetchWorker::LOAD_FROM_NETWORK && state <= LLTextureFetchWorker::WAIT_HTTP_REQ)
+		{
+			requested_priority = worker->mRequestedPriority;
+		}
+		else
+		{
+			requested_priority = worker->mImagePriority;
+		}
+		fetch_priority = worker->getPriority();
+		can_use_http = worker->getCanUseHTTP() ;
+		worker->unlockWorkMutex();
+	}
+	data_progress_p = data_progress;
+	requested_priority_p = requested_priority;
+	fetch_priority_p = fetch_priority;
+	fetch_dtime_p = fetch_dtime;
+	request_dtime_p = request_dtime;
+	return state;
+}
+
+void LLTextureFetch::dump()
+{
+	llinfos << "LLTextureFetch REQUESTS:" << llendl;
+	for (request_queue_t::iterator iter = mRequestQueue.begin();
+		 iter != mRequestQueue.end(); ++iter)
+	{
+		LLQueuedThread::QueuedRequest* qreq = *iter;
+		LLWorkerThread::WorkRequest* wreq = (LLWorkerThread::WorkRequest*)qreq;
+		LLTextureFetchWorker* worker = (LLTextureFetchWorker*)wreq->getWorkerClass();
+		llinfos << " ID: " << worker->mID
+				<< " PRI: " << llformat("0x%08x",wreq->getPriority())
+				<< " STATE: " << worker->sStateDescs[worker->mState]
+				<< llendl;
+	}
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+// cross-thread command methods
+
+void LLTextureFetch::commandSetRegion(U64 region_handle)
+{
+	TFReqSetRegion * req = new TFReqSetRegion(region_handle);
+
+	cmdEnqueue(req);
+}
+
+void LLTextureFetch::commandSendMetrics(const std::string & caps_url,
+										const LLUUID & session_id,
+										const LLUUID & agent_id,
+										LLViewerAssetStats * main_stats)
+{
+	TFReqSendMetrics * req = new TFReqSendMetrics(caps_url, session_id, agent_id, main_stats);
+
+	cmdEnqueue(req);
+}
+
+void LLTextureFetch::commandDataBreak()
+{
+	// The pedantically correct way to implement this is to create a command
+	// request object in the above fashion and enqueue it.  However, this is
+	// simple data of an advisorial not operational nature and this case
+	// of shared-write access is tolerable.
+
+	LLTextureFetch::svMetricsDataBreak = true;
+}
+
+void LLTextureFetch::cmdEnqueue(TFRequest * req)
+{
+	lockQueue();
+	mCommands.push_back(req);
+	unlockQueue();
+
+	unpause();
+}
+
+LLTextureFetch::TFRequest * LLTextureFetch::cmdDequeue()
+{
+	TFRequest * ret = 0;
+	
+	lockQueue();
+	if (! mCommands.empty())
+	{
+		ret = mCommands.front();
+		mCommands.erase(mCommands.begin());
+	}
+	unlockQueue();
+
+	return ret;
+}
+
+void LLTextureFetch::cmdDoWork()
+{
+	if (mDebugPause)
+	{
+		return;  // debug: don't do any work
+	}
+
+	TFRequest * req = cmdDequeue();
+	if (req)
+	{
+		// One request per pass should really be enough for this.
+		req->doWork(this);
+		delete req;
+	}
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Private (anonymous) class methods implementing the command scheme.
+
+namespace
+{
+
+/**
+ * Implements the 'Set Region' command.
+ *
+ * Thread:  Thread1 (TextureFetch)
+ */
+bool
+TFReqSetRegion::doWork(LLTextureFetch *)
+{
+	LLViewerAssetStatsFF::set_region_thread1(mRegionHandle);
+
+	return true;
+}
+
+
+TFReqSendMetrics::~TFReqSendMetrics()
+{
+	delete mMainStats;
+	mMainStats = 0;
+}
+
+
+/**
+ * Implements the 'Send Metrics' command.  Takes over
+ * ownership of the passed LLViewerAssetStats pointer.
+ *
+ * Thread:  Thread1 (TextureFetch)
+ */
+bool
+TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
+{
+	/*
+	 * HTTP POST responder.  Doesn't do much but tries to
+	 * detect simple breaks in recording the metrics stream.
+	 *
+	 * The 'volatile' modifiers don't indicate signals,
+	 * mmap'd memory or threads, really.  They indicate that
+	 * the referenced data is part of a pseudo-closure for
+	 * this responder rather than being required for correct
+	 * operation.
+     *
+     * We don't try very hard with the POST request.  We give
+     * it one shot and that's more-or-less it.  With a proper
+     * refactoring of the LLQueuedThread usage, these POSTs
+     * could be put in a request object and made more reliable.
+	 */
+	class lcl_responder : public LLCurl::Responder
+	{
+	public:
+		lcl_responder(LLTextureFetch * fetcher,
+					  S32 expected_sequence,
+                      volatile const S32 & live_sequence,
+                      volatile bool & reporting_break,
+					  volatile bool & reporting_started)
+			: LLCurl::Responder(),
+			  mFetcher(fetcher),
+              mExpectedSequence(expected_sequence),
+              mLiveSequence(live_sequence),
+			  mReportingBreak(reporting_break),
+			  mReportingStarted(reporting_started)
+			{
+                mFetcher->incrCurlPOSTCount();
+            }
+        
+        ~lcl_responder()
+            {
+                mFetcher->decrCurlPOSTCount();
+            }
+
+		// virtual
+		void error(U32 status_num, const std::string & reason)
+			{
+                if (mLiveSequence == mExpectedSequence)
+                {
+                    mReportingBreak = true;
+                }
+				LL_WARNS("Texture") << "Break in metrics stream due to POST failure to metrics collection service.  Reason:  "
+									<< reason << LL_ENDL;
+			}
+
+		// virtual
+		void result(const LLSD & content)
+			{
+                if (mLiveSequence == mExpectedSequence)
+                {
+                    mReportingBreak = false;
+                    mReportingStarted = true;
+                }
+			}
+
+	private:
+		LLTextureFetch * mFetcher;
+        S32 mExpectedSequence;
+        volatile const S32 & mLiveSequence;
+		volatile bool & mReportingBreak;
+		volatile bool & mReportingStarted;
+
+	}; // class lcl_responder
+	
+	if (! gViewerAssetStatsThread1)
+		return true;
+
+	static volatile bool reporting_started(false);
+	static volatile S32 report_sequence(0);
+    
+	// We've taken over ownership of the stats copy at this
+	// point.  Get a working reference to it for merging here
+	// but leave it in 'this'.  Destructor will rid us of it.
+	LLViewerAssetStats & main_stats = *mMainStats;
+
+	// Merge existing stats into those from main, convert to LLSD
+	main_stats.merge(*gViewerAssetStatsThread1);
+	LLSD merged_llsd = main_stats.asLLSD(true);
+
+	// Add some additional meta fields to the content
+	merged_llsd["session_id"] = mSessionID;
+	merged_llsd["agent_id"] = mAgentID;
+	merged_llsd["message"] = "ViewerAssetMetrics";					// Identifies the type of metrics
+	merged_llsd["sequence"] = report_sequence;						// Sequence number
+	merged_llsd["initial"] = ! reporting_started;					// Initial data from viewer
+	merged_llsd["break"] = LLTextureFetch::svMetricsDataBreak;		// Break in data prior to this report
+		
+	// Update sequence number
+	if (S32_MAX == ++report_sequence)
+		report_sequence = 0;
+
+	// Limit the size of the stats report if necessary.
+	merged_llsd["truncated"] = truncate_viewer_metrics(10, merged_llsd);
+
+	if (! mCapsURL.empty())
+	{
+		LLCurlRequest::headers_t headers;
+		fetcher->getCurlRequest().post(mCapsURL,
+									   headers,
+									   merged_llsd,
+									   new lcl_responder(fetcher,
+														 report_sequence,
+                                                         report_sequence,
+                                                         LLTextureFetch::svMetricsDataBreak,
+														 reporting_started));
+	}
+	else
+	{
+		LLTextureFetch::svMetricsDataBreak = true;
+	}
+
+	// In QA mode, Metrics submode, log the result for ease of testing
+	if (fetcher->isQAMode())
+	{
+		LL_INFOS("Textures") << merged_llsd << LL_ENDL;
+	}
+
+	gViewerAssetStatsThread1->reset();
+
+	return true;
+}
+
+
+bool
+truncate_viewer_metrics(int max_regions, LLSD & metrics)
+{
+	static const LLSD::String reg_tag("regions");
+	static const LLSD::String duration_tag("duration");
+	
+	LLSD & reg_map(metrics[reg_tag]);
+	if (reg_map.size() <= max_regions)
+	{
+		return false;
+	}
+
+	// Build map of region hashes ordered by duration
+	typedef std::multimap<LLSD::Real, int> reg_ordered_list_t;
+	reg_ordered_list_t regions_by_duration;
+
+	int ind(0);
+	LLSD::array_const_iterator it_end(reg_map.endArray());
+	for (LLSD::array_const_iterator it(reg_map.beginArray()); it_end != it; ++it, ++ind)
+	{
+		LLSD::Real duration = (*it)[duration_tag].asReal();
+		regions_by_duration.insert(reg_ordered_list_t::value_type(duration, ind));
+	}
+
+	// Build a replacement regions array with the longest-persistence regions
+	LLSD new_region(LLSD::emptyArray());
+	reg_ordered_list_t::const_reverse_iterator it2_end(regions_by_duration.rend());
+	reg_ordered_list_t::const_reverse_iterator it2(regions_by_duration.rbegin());
+	for (int i(0); i < max_regions && it2_end != it2; ++i, ++it2)
+	{
+		new_region.append(reg_map[it2->second]);
+	}
+	reg_map = new_region;
+	
+	return true;
+}
+
+} // end of anonymous namespace
+
+
+
-- 
cgit v1.2.3


From c62055043380147a760dc7f37ac0900df1a7f789 Mon Sep 17 00:00:00 2001
From: Kent Quirk <q@lindenlab.com>
Date: Mon, 31 Jan 2011 19:18:58 -0500
Subject: VWR-22024 -- apply Bao's patch to beta

---
 indra/newview/llfirstuse.cpp | 58 +++++++++++++++++++++++++-------------------
 indra/newview/llfirstuse.h   |  9 ++++---
 2 files changed, 38 insertions(+), 29 deletions(-)

diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index 4c17199895..4d252dc662 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -41,35 +41,36 @@
 
 
 // static
-std::set<std::string> LLFirstUse::sConfigVariables;
+//std::set<std::string> LLFirstUse::sConfigVariables;
+std::set<std::string> LLFirstUse::sConfigVariablesEnabled;
 
 // static
-void LLFirstUse::addConfigVariable(const std::string& var)
-{
-	sConfigVariables.insert(var);
-}
+//void LLFirstUse::addConfigVariable(const std::string& var)
+//{
+//	sConfigVariables.insert(var);
+//}
 
 // static
-void LLFirstUse::disableFirstUse()
-{
-	// Set all first-use warnings to disabled
-	for (std::set<std::string>::iterator iter = sConfigVariables.begin();
-		 iter != sConfigVariables.end(); ++iter)
-	{
-		gWarningSettings.setBOOL(*iter, FALSE);
-	}
-}
+//void LLFirstUse::disableFirstUse()
+//{
+//	// Set all first-use warnings to disabled
+//	for (std::set<std::string>::iterator iter = sConfigVariables.begin();
+//		 iter != sConfigVariables.end(); ++iter)
+//	{
+//		gWarningSettings.setBOOL(*iter, FALSE);
+//	}
+//}
 
 // static
-void LLFirstUse::resetFirstUse()
-{
-	// Set all first-use warnings to disabled
-	for (std::set<std::string>::iterator iter = sConfigVariables.begin();
-		 iter != sConfigVariables.end(); ++iter)
-	{
-		gWarningSettings.setBOOL(*iter, TRUE);
-	}
-}
+//void LLFirstUse::resetFirstUse()
+//{
+//	// Set all first-use warnings to disabled
+//	for (std::set<std::string>::iterator iter = sConfigVariables.begin();
+//		 iter != sConfigVariables.end(); ++iter)
+//	{
+//		gWarningSettings.setBOOL(*iter, TRUE);
+//	}
+//}
 
 // static
 void LLFirstUse::otherAvatarChatFirst(bool enable)
@@ -151,13 +152,21 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl
 
 	if (enable)
 	{
+		if(sConfigVariablesEnabled.find(control_var) != sConfigVariablesEnabled.end())
+		{
+			return ; //already added
+		}
+
 		if (gSavedSettings.getBOOL("EnableUIHints"))
 		{
 			LL_DEBUGS("LLFirstUse") << "Trigger first use notification " << notification_name << LL_ENDL;
 
 			// if notification doesn't already exist and this notification hasn't been disabled...
 			if (gWarningSettings.getBOOL(control_var))
-			{ // create new notification
+			{ 
+				sConfigVariablesEnabled.insert(control_var) ;
+
+				// create new notification
 				LLNotifications::instance().add(LLNotification::Params().name(notification_name).substitutions(args).payload(payload.with("control_var", control_var)));
 			}
 		}
@@ -169,7 +178,6 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl
 		// redundantly clear settings var here, in case there are no notifications to cancel
 		gWarningSettings.setBOOL(control_var, FALSE);
 	}
-
 }
 
 // static
diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h
index 81659988e6..489f58626a 100644
--- a/indra/newview/llfirstuse.h
+++ b/indra/newview/llfirstuse.h
@@ -78,11 +78,11 @@ class LLFirstUse
 public:
 
 	// Add a config variable to be reset on resetFirstUse()
-	static void addConfigVariable(const std::string& var);
+	//static void addConfigVariable(const std::string& var);
 	
 	// Sets all controls back to show the dialogs.
-	static void disableFirstUse();
-	static void resetFirstUse();
+	//static void disableFirstUse();
+	//static void resetFirstUse();
 
 	static void otherAvatarChatFirst(bool enable = true);
 	static void sit(bool enable = true);
@@ -98,7 +98,8 @@ public:
 	
 protected:
 	static void firstUseNotification(const std::string& control_var, bool enable, const std::string& notification_name, LLSD args = LLSD(), LLSD payload = LLSD());
-	static std::set<std::string> sConfigVariables;
+	//static std::set<std::string> sConfigVariables;
+	static std::set<std::string> sConfigVariablesEnabled;
 
 	static void init();
 	static bool processNotification(const LLSD& notify);
-- 
cgit v1.2.3


From c7d0fab7b9279c5f6a57ee3de103b8fb142fb747 Mon Sep 17 00:00:00 2001
From: Loren Shih <seraph@lindenlab.com>
Date: Tue, 1 Feb 2011 12:33:39 -0500
Subject: Fixes for merge up from viewer-development to mesh-development.
 Backed out SH-659 since merge was messy; this will be merged in manually
 later.

---
 indra/llmath/llvolume.cpp     | 6557 ++++++++++++++++++++++++++---------------
 indra/llmath/llvolume.h       | 2212 +++++++-------
 indra/llmath/llvolumeoctree.h |   70 +-
 3 files changed, 5280 insertions(+), 3559 deletions(-)

diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 316eed679d..617a8b4ca3 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -1,4 +1,5 @@
 /** 
+
  * @file llvolume.cpp
  *
  * $LicenseInfo:firstyear=2002&license=viewerlgpl$
@@ -24,9 +25,13 @@
  */
 
 #include "linden_common.h"
+#include "llmemory.h"
 #include "llmath.h"
 
 #include <set>
+#if !LL_WINDOWS
+#include <stdint.h>
+#endif
 
 #include "llerror.h"
 #include "llmemtype.h"
@@ -37,9 +42,15 @@
 #include "v4math.h"
 #include "m4math.h"
 #include "m3math.h"
+#include "llmatrix3a.h"
+#include "lloctree.h"
 #include "lldarray.h"
 #include "llvolume.h"
+#include "llvolumeoctree.h"
 #include "llstl.h"
+#include "llsdserialize.h"
+#include "llvector4a.h"
+#include "llmatrix4a.h"
 
 #define DEBUG_SILHOUETTE_BINORMALS 0
 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
@@ -80,7 +91,18 @@ const F32 SKEW_MAX	=  0.95f;
 const F32 SCULPT_MIN_AREA = 0.002f;
 const S32 SCULPT_MIN_AREA_DETAIL = 1;
 
-#define GEN_TRI_STRIP 0
+extern BOOL gDebugGL;
+
+void assert_aligned(void* ptr, uintptr_t alignment)
+{
+#if 0
+	uintptr_t t = (uintptr_t) ptr;
+	if (t%alignment != 0)
+	{
+		llerrs << "WTF?" << llendl;
+	}
+#endif
+}
 
 BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
 {    
@@ -99,128 +121,262 @@ BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLV
 
 BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size)
 {
-	float fAWdU[3];
-	LLVector3 dir;
-	LLVector3 diff;
+	return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV);
+}
+
+BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size)
+{
+	F32 fAWdU[3];
+	F32 dir[3];
+	F32 diff[3];
 
 	for (U32 i = 0; i < 3; i++)
 	{
-		dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]);
-		diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i];
-		fAWdU[i] = fabsf(dir.mV[i]);
-		if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false;
+		dir[i] = 0.5f * (end[i] - start[i]);
+		diff[i] = (0.5f * (end[i] + start[i])) - center[i];
+		fAWdU[i] = fabsf(dir[i]);
+		if(fabsf(diff[i])>size[i] + fAWdU[i]) return false;
 	}
 
 	float f;
-	f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1];    if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1])  return false;
-	f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2];    if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0])  return false;
-	f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0];    if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0])  return false;
+	f = dir[1] * diff[2] - dir[2] * diff[1];    if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1])  return false;
+	f = dir[2] * diff[0] - dir[0] * diff[2];    if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0])  return false;
+	f = dir[0] * diff[1] - dir[1] * diff[0];    if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0])  return false;
 	
 	return true;
 }
 
 
+
 // intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
 // returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b,
 // and returns the intersection point along dir in intersection_t.
 
 // Moller-Trumbore algorithm
-BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
-							F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided)
+BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t)
 {
-	F32 u, v, t;
 	
 	/* find vectors for two edges sharing vert0 */
-	LLVector3 edge1 = vert1 - vert0;
+	LLVector4a edge1;
+	edge1.setSub(vert1, vert0);
 	
-	LLVector3 edge2 = vert2 - vert0;;
+	LLVector4a edge2;
+	edge2.setSub(vert2, vert0);
 
 	/* begin calculating determinant - also used to calculate U parameter */
-	LLVector3 pvec = dir % edge2;
-	
-	/* if determinant is near zero, ray lies in plane of triangle */
-	F32 det = edge1 * pvec;
+	LLVector4a pvec;
+	pvec.setCross3(dir, edge2);
 
-	if (!two_sided)
+	/* if determinant is near zero, ray lies in plane of triangle */
+	LLVector4a det;
+	det.setAllDot3(edge1, pvec);
+	
+	if (det.greaterEqual(LLVector4a::getEpsilon()).getGatheredBits() & 0x7)
 	{
-		if (det < F_APPROXIMATELY_ZERO)
-		{
-			return FALSE;
-		}
-
 		/* calculate distance from vert0 to ray origin */
-		LLVector3 tvec = orig - vert0;
+		LLVector4a tvec;
+		tvec.setSub(orig, vert0);
 
 		/* calculate U parameter and test bounds */
-		u = tvec * pvec;	
+		LLVector4a u;
+		u.setAllDot3(tvec,pvec);
 
-		if (u < 0.f || u > det)
+		if ((u.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7) &&
+			(u.lessEqual(det).getGatheredBits() & 0x7))
 		{
-			return FALSE;
+			/* prepare to test V parameter */
+			LLVector4a qvec;
+			qvec.setCross3(tvec, edge1);
+			
+			/* calculate V parameter and test bounds */
+			LLVector4a v;
+			v.setAllDot3(dir, qvec);
+
+			
+			//if (!(v < 0.f || u + v > det))
+
+			LLVector4a sum_uv;
+			sum_uv.setAdd(u, v);
+
+			S32 v_gequal = v.greaterEqual(LLVector4a::getZero()).getGatheredBits() & 0x7;
+			S32 sum_lequal = sum_uv.lessEqual(det).getGatheredBits() & 0x7;
+
+			if (v_gequal  && sum_lequal)
+			{
+				/* calculate t, scale parameters, ray intersects triangle */
+				LLVector4a t;
+				t.setAllDot3(edge2,qvec);
+
+				t.div(det);
+				u.div(det);
+				v.div(det);
+				
+				intersection_a = u[0];
+				intersection_b = v[0];
+				intersection_t = t[0];
+				return TRUE;
+			}
 		}
-	
-		/* prepare to test V parameter */
-		LLVector3 qvec = tvec % edge1;
+	}
 		
-		/* calculate V parameter and test bounds */
-		v = dir * qvec;
-		if (v < 0.f || u + v > det)
-		{
-			return FALSE;
-		}
+	return FALSE;
+} 
 
-		/* calculate t, scale parameters, ray intersects triangle */
-		t = edge2 * qvec;
-		F32 inv_det = 1.0 / det;
-		t *= inv_det;
-		u *= inv_det;
-		v *= inv_det;
-	}
+BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t)
+{
+	F32 u, v, t;
 	
-	else // two sided
-			{
-		if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
-				{
-			return FALSE;
-				}
-		F32 inv_det = 1.0 / det;
+	/* find vectors for two edges sharing vert0 */
+	LLVector4a edge1;
+	edge1.setSub(vert1, vert0);
+	
+	
+	LLVector4a edge2;
+	edge2.setSub(vert2, vert0);
 
-		/* calculate distance from vert0 to ray origin */
-		LLVector3 tvec = orig - vert0;
-		
-		/* calculate U parameter and test bounds */
-		u = (tvec * pvec) * inv_det;
-		if (u < 0.f || u > 1.f)
-		{
-			return FALSE;
-			}
+	/* begin calculating determinant - also used to calculate U parameter */
+	LLVector4a pvec;
+	pvec.setCross3(dir, edge2);
 
-		/* prepare to test V parameter */
-		LLVector3 qvec = tvec - edge1;
-		
-		/* calculate V parameter and test bounds */
-		v = (dir * qvec) * inv_det;
-		
-		if (v < 0.f || u + v > 1.f)
-		{
-			return FALSE;
-		}
+	/* if determinant is near zero, ray lies in plane of triangle */
+	F32 det = edge1.dot3(pvec).getF32();
 
-		/* calculate t, ray intersects triangle */
-		t = (edge2 * qvec) * inv_det;
+	
+	if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
+	{
+		return FALSE;
+	}
+
+	F32 inv_det = 1.f / det;
+
+	/* calculate distance from vert0 to ray origin */
+	LLVector4a tvec;
+	tvec.setSub(orig, vert0);
+	
+	/* calculate U parameter and test bounds */
+	u = (tvec.dot3(pvec).getF32()) * inv_det;
+	if (u < 0.f || u > 1.f)
+	{
+		return FALSE;
+	}
+
+	/* prepare to test V parameter */
+	tvec.sub(edge1);
+		
+	/* calculate V parameter and test bounds */
+	v = (dir.dot3(tvec).getF32()) * inv_det;
+	
+	if (v < 0.f || u + v > 1.f)
+	{
+		return FALSE;
 	}
+
+	/* calculate t, ray intersects triangle */
+	t = (edge2.dot3(tvec).getF32()) * inv_det;
 	
-	if (intersection_a != NULL)
-		*intersection_a = u;
-	if (intersection_b != NULL)
-		*intersection_b = v;
-	if (intersection_t != NULL)
-		*intersection_t = t;
+	intersection_a = u;
+	intersection_b = v;
+	intersection_t = t;
 	
 	
 	return TRUE;
 } 
 
+//helper for non-aligned vectors
+BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided)
+{
+	LLVector4a vert0a, vert1a, vert2a, origa, dira;
+	vert0a.load3(vert0.mV);
+	vert1a.load3(vert1.mV);
+	vert2a.load3(vert2.mV);
+	origa.load3(orig.mV);
+	dira.load3(dir.mV);
+
+	if (two_sided)
+	{
+		return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira, 
+				intersection_a, intersection_b, intersection_t);
+	}
+	else
+	{
+		return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira, 
+				intersection_a, intersection_b, intersection_t);
+	}
+}
+
+class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle>
+{
+public:
+	const LLVolumeFace* mFace;
+
+	LLVolumeOctreeRebound(const LLVolumeFace* face)
+	{
+		mFace = face;
+	}
+
+	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+	{ //this is a depth first traversal, so it's safe to assum all children have complete
+		//bounding data
+
+		LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
+
+		LLVector4a& min = node->mExtents[0];
+		LLVector4a& max = node->mExtents[1];
+
+		if (!branch->getData().empty())
+		{ //node has data, find AABB that binds data set
+			const LLVolumeTriangle* tri = *(branch->getData().begin());
+			
+			//initialize min/max to first available vertex
+			min = *(tri->mV[0]);
+			max = *(tri->mV[0]);
+			
+			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = 
+				branch->getData().begin(); iter != branch->getData().end(); ++iter)
+			{ //for each triangle in node
+
+				//stretch by triangles in node
+				tri = *iter;
+				
+				min.setMin(min, *tri->mV[0]);
+				min.setMin(min, *tri->mV[1]);
+				min.setMin(min, *tri->mV[2]);
+
+				max.setMax(max, *tri->mV[0]);
+				max.setMax(max, *tri->mV[1]);
+				max.setMax(max, *tri->mV[2]);
+			}
+		}
+		else if (!branch->getChildren().empty())
+		{ //no data, but child nodes exist
+			LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
+
+			//initialize min/max to extents of first child
+			min = child->mExtents[0];
+			max = child->mExtents[1];
+		}
+		else
+		{
+			llerrs << "WTF? Empty leaf" << llendl;
+		}
+
+		for (S32 i = 0; i < branch->getChildCount(); ++i)
+		{  //stretch by child extents
+			LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+			min.setMin(min, child->mExtents[0]);
+			max.setMax(max, child->mExtents[1]);
+		}
+
+		node->mBounds[0].setAdd(min, max);
+		node->mBounds[0].mul(0.5f);
+
+		node->mBounds[1].setSub(max,min);
+		node->mBounds[1].mul(0.5f);
+	}
+};
 
 //-------------------------------------------------------------------
 // statics
@@ -1669,7 +1825,13 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
 	mFaceMask = 0x0;
 	mDetail = detail;
 	mSculptLevel = -2;
-	
+	mIsTetrahedron = FALSE;
+	mLODScaleBias.setVec(1,1,1);
+	mHullPoints = NULL;
+	mHullIndices = NULL;
+	mNumHullPoints = 0;
+	mNumHullIndices = 0;
+
 	// set defaults
 	if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
 	{
@@ -1684,7 +1846,8 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
 	mGenerateSingleFace = generate_single_face;
 
 	generate();
-	if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE)
+	
+	if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE)
 	{
 		createVolumeFaces();
 	}
@@ -1719,6 +1882,11 @@ LLVolume::~LLVolume()
 	mPathp = NULL;
 	mProfilep = NULL;
 	mVolumeFaces.clear();
+
+	free(mHullPoints);
+	mHullPoints = NULL;
+	free(mHullIndices);
+	mHullIndices = NULL;
 }
 
 BOOL LLVolume::generate()
@@ -1835,815 +2003,1435 @@ BOOL LLVolume::generate()
 	return FALSE;
 }
 
-
-void LLVolume::createVolumeFaces()
+void LLVolumeFace::VertexData::init()
 {
-	LLMemType m1(LLMemType::MTYPE_VOLUME);
-
-	if (mGenerateSingleFace)
+	if (!mData)
 	{
-		// do nothing
+		mData = (LLVector4a*) malloc(sizeof(LLVector4a)*2);
 	}
-	else
-	{
-		S32 num_faces = getNumFaces();
-		BOOL partial_build = TRUE;
-		if (num_faces != mVolumeFaces.size())
-		{
-			partial_build = FALSE;
-			mVolumeFaces.resize(num_faces);
-		}
-		// Initialize volume faces with parameter data
-		for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++)
-		{
-			LLVolumeFace& vf = mVolumeFaces[i];
-			LLProfile::Face& face = mProfilep->mFaces[i];
-			vf.mBeginS = face.mIndex;
-			vf.mNumS = face.mCount;
-			if (vf.mNumS < 0)
-			{
-				llerrs << "Volume face corruption detected." << llendl;
-			}
-
-			vf.mBeginT = 0;
-			vf.mNumT= getPath().mPath.size();
-			vf.mID = i;
+}
 
-			// Set the type mask bits correctly
-			if (mParams.getProfileParams().getHollow() > 0)
-			{
-				vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK;
-			}
-			if (mProfilep->isOpen())
-			{
-				vf.mTypeMask |= LLVolumeFace::OPEN_MASK;
-			}
-			if (face.mCap)
-			{
-				vf.mTypeMask |= LLVolumeFace::CAP_MASK;
-				if (face.mFaceID == LL_FACE_PATH_BEGIN)
-				{
-					vf.mTypeMask |= LLVolumeFace::TOP_MASK;
-				}
-				else
-				{
-					llassert(face.mFaceID == LL_FACE_PATH_END);
-					vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK;
-				}
-			}
-			else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
-			{
-				vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK;
-			}
-			else
-			{
-				vf.mTypeMask |= LLVolumeFace::SIDE_MASK;
-				if (face.mFlat)
-				{
-					vf.mTypeMask |= LLVolumeFace::FLAT_MASK;
-				}
-				if (face.mFaceID & LL_FACE_INNER_SIDE)
-				{
-					vf.mTypeMask |= LLVolumeFace::INNER_MASK;
-					if (face.mFlat && vf.mNumS > 2)
-					{ //flat inner faces have to copy vert normals
-						vf.mNumS = vf.mNumS*2;
-						if (vf.mNumS < 0)
-						{
-							llerrs << "Volume face corruption detected." << llendl;
-						}
-					}
-				}
-				else
-				{
-					vf.mTypeMask |= LLVolumeFace::OUTER_MASK;
-				}
-			}
-		}
+LLVolumeFace::VertexData::VertexData()
+{
+	mData = NULL;
+	init();
+}
+	
+LLVolumeFace::VertexData::VertexData(const VertexData& rhs)
+{
+	mData = NULL;
+	*this = rhs;
+}
 
-		for (face_list_t::iterator iter = mVolumeFaces.begin();
-			 iter != mVolumeFaces.end(); ++iter)
-		{
-			(*iter).create(this, partial_build);
-		}
+const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolumeFace::VertexData& rhs)
+{
+	if (this != &rhs)
+	{
+		init();
+		LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 2*sizeof(LLVector4a));
+		mTexCoord = rhs.mTexCoord;
 	}
+	return *this;
 }
 
-
-inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b)
+LLVolumeFace::VertexData::~VertexData()
 {
-	// maps RGB values to vector values [0..255] -> [-0.5..0.5]
-	LLVector3 value;
-	value.mV[VX] = r / 255.f - 0.5f;
-	value.mV[VY] = g / 255.f - 0.5f;
-	value.mV[VZ] = b / 255.f - 0.5f;
-
-	return value;
+	free(mData);
+	mData = NULL;
 }
 
-inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
+LLVector4a& LLVolumeFace::VertexData::getPosition()
 {
-	U32 index = (x + y * sculpt_width) * sculpt_components;
-	return index;
+	return mData[POSITION];
 }
 
+LLVector4a& LLVolumeFace::VertexData::getNormal()
+{
+	return mData[NORMAL];
+}
 
-inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
+const LLVector4a& LLVolumeFace::VertexData::getPosition() const
 {
-	U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width);
-	U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height);
+	return mData[POSITION];
+}
 
-	return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
+const LLVector4a& LLVolumeFace::VertexData::getNormal() const
+{
+	return mData[NORMAL];
 }
 
 
-inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data)
+void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos)
 {
-	LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]);
-
-	return v;
+	mData[POSITION] = pos;
 }
 
-inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
+void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm)
 {
-	U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components);
-
-	return sculpt_index_to_vector(index, sculpt_data);
+	mData[NORMAL] = norm;
 }
 
-inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
+bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const
 {
-	U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
+	const F32* lp = this->getPosition().getF32ptr();
+	const F32* rp = rhs.getPosition().getF32ptr();
 
-	return sculpt_index_to_vector(index, sculpt_data);
-}
+	if (lp[0] != rp[0])
+	{
+		return lp[0] < rp[0];
+	}
 
+	if (rp[1] != lp[1])
+	{
+		return lp[1] < rp[1];
+	}
 
-F32 LLVolume::sculptGetSurfaceArea()
-{
-	// test to see if image has enough variation to create non-degenerate geometry
+	if (rp[2] != lp[2])
+	{
+		return lp[2] < rp[2];
+	}
 
-	F32 area = 0;
+	lp = getNormal().getF32ptr();
+	rp = rhs.getNormal().getF32ptr();
 
-	S32 sizeS = mPathp->mPath.size();
-	S32 sizeT = mProfilep->mProfile.size();
-			
-	for (S32 s = 0; s < sizeS-1; s++)
+	if (lp[0] != rp[0])
 	{
-		for (S32 t = 0; t < sizeT-1; t++)
-		{
-			// get four corners of quad
-			LLVector3 p1 = mMesh[(s  )*sizeT + (t  )].mPos;
-			LLVector3 p2 = mMesh[(s+1)*sizeT + (t  )].mPos;
-			LLVector3 p3 = mMesh[(s  )*sizeT + (t+1)].mPos;
-			LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos;
+		return lp[0] < rp[0];
+	}
 
-			// compute the area of the quad by taking the length of the cross product of the two triangles
-			LLVector3 cross1 = (p1 - p2) % (p1 - p3);
-			LLVector3 cross2 = (p4 - p2) % (p4 - p3);
-			area += (cross1.magVec() + cross2.magVec()) / 2.0;
+	if (rp[1] != lp[1])
+	{
+		return lp[1] < rp[1];
+	}
+
+	if (rp[2] != lp[2])
+	{
+		return lp[2] < rp[2];
+	}
+
+	if (mTexCoord.mV[0] != rhs.mTexCoord.mV[0])
+	{
+		return mTexCoord.mV[0] < rhs.mTexCoord.mV[0];
+	}
+
+	return mTexCoord.mV[1] < rhs.mTexCoord.mV[1];
+}
+
+bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const
+{
+	return mData[POSITION].equals3(rhs.getPosition()) &&
+			mData[NORMAL].equals3(rhs.getNormal()) &&
+			mTexCoord == rhs.mTexCoord;
+}
+
+bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const
+{
+	bool retval = false;
+	if (rhs.mData[POSITION].equals3(mData[POSITION]) && rhs.mTexCoord == mTexCoord)
+	{
+		if (angle_cutoff > 1.f)
+		{
+			retval = (mData[NORMAL].equals3(rhs.mData[NORMAL]));
+		}
+		else
+		{
+			F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]).getF32();
+			retval = cur_angle > angle_cutoff;
 		}
 	}
 
-	return area;
+	return retval;
 }
 
-// create placeholder shape
-void LLVolume::sculptGeneratePlaceholder()
+BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name)
 {
-	LLMemType m1(LLMemType::MTYPE_VOLUME);
+	std::ifstream is;
 	
-	S32 sizeS = mPathp->mPath.size();
-	S32 sizeT = mProfilep->mProfile.size();
+	is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary);
+
+	BOOL success = createVolumeFacesFromStream(is);
 	
-	S32 line = 0;
+	is.close();
 
-	// for now, this is a sphere.
-	for (S32 s = 0; s < sizeS; s++)
+	return success;
+}
+
+BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
+{
+	mSculptLevel = -1;  // default is an error occured
+
+	LLSD header;
 	{
-		for (S32 t = 0; t < sizeT; t++)
+		if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024))
 		{
-			S32 i = t + line;
-			Point& pt = mMesh[i];
+			llwarns << "Mesh header parse error.  Not a valid mesh asset!" << llendl;
+			return FALSE;
+		}
+	}
+	
+	std::string nm[] = 
+	{
+		"lowest_lod",
+		"low_lod",
+		"medium_lod",
+		"high_lod"
+	};
 
-			
-			F32 u = (F32)s/(sizeS-1);
-			F32 v = (F32)t/(sizeT-1);
+	S32 lod = llclamp((S32) mDetail, 0, 3);
 
-			const F32 RADIUS = (F32) 0.3;
-					
-			pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS);
-			pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS);
-			pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS);
+	while (lod < 4 && 
+		(header[nm[lod]]["offset"].asInteger() == -1 || 
+		header[nm[lod]]["size"].asInteger() == 0 ))
+	{
+		++lod;
+	}
+
+	if (lod >= 4)
+	{
+		lod = llclamp((S32) mDetail, 0, 3);
 
+		while (lod >= 0 && 
+				(header[nm[lod]]["offset"].asInteger() == -1 ||
+				header[nm[lod]]["size"].asInteger() == 0) )
+		{
+			--lod;
+		}
+
+		if (lod < 0)
+		{
+			llwarns << "Mesh header missing LOD offsets.  Not a valid mesh asset!" << llendl;
+			return FALSE;
 		}
-		line += sizeT;
 	}
+
+	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+
+	return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger());
 }
 
-// create the vertices from the map
-void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type)
+bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 {
-	U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
-	BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT;
-	BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
-	BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror);  // XOR
-	
-	
-	LLMemType m1(LLMemType::MTYPE_VOLUME);
-	
-	S32 sizeS = mPathp->mPath.size();
-	S32 sizeT = mProfilep->mProfile.size();
+	//input stream is now pointing at a zlib compressed block of LLSD
+	//decompress block
+	LLSD mdl;
+	if (!unzip_llsd(mdl, is, size))
+	{
+		llwarns << "not a valid mesh asset!" << llendl;
+		return false;
+	}
 	
-	S32 line = 0;
-	for (S32 s = 0; s < sizeS; s++)
 	{
-		// Run along the profile.
-		for (S32 t = 0; t < sizeT; t++)
+		U32 face_count = mdl.size();
+
+		if (face_count == 0)
 		{
-			S32 i = t + line;
-			Point& pt = mMesh[i];
+			llerrs << "WTF?" << llendl;
+		}
 
-			S32 reversed_t = t;
+		mVolumeFaces.resize(face_count);
 
-			if (reverse_horizontal)
-			{
-				reversed_t = sizeT - t - 1;
-			}
-			
-			U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width);
-			U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height);
+		for (U32 i = 0; i < face_count; ++i)
+		{
+			LLSD::Binary pos = mdl[i]["Position"];
+			LLSD::Binary norm = mdl[i]["Normal"];
+			LLSD::Binary tc = mdl[i]["TexCoord0"];
+			LLSD::Binary idx = mdl[i]["TriangleList"];
+
+			LLVolumeFace& face = mVolumeFaces[i];
 
+			//copy out indices
+			face.resizeIndices(idx.size()/2);
 			
-			if (y == 0)  // top row stitching
+			if (idx.empty() || face.mNumIndices < 3)
+			{ //why is there an empty index list?
+				llerrs <<"WTF?" << llendl;
+				continue;
+			}
+
+			U16* indices = (U16*) &(idx[0]);
+			for (U32 j = 0; j < idx.size()/2; ++j)
 			{
-				// pinch?
-				if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE)
-				{
-					x = sculpt_width / 2;
-				}
+				face.mIndices[j] = indices[j];
 			}
 
-			if (y == sculpt_height)  // bottom row stitching
+			//copy out vertices
+			U32 num_verts = pos.size()/(3*2);
+			face.resizeVertices(num_verts);
+
+			if (mdl[i].has("Weights"))
 			{
-				// wrap?
-				if (sculpt_stitching == LL_SCULPT_TYPE_TORUS)
+				face.allocateWeights(num_verts);
+
+				LLSD::Binary weights = mdl[i]["Weights"];
+
+				U32 idx = 0;
+
+				U32 cur_vertex = 0;
+				while (idx < weights.size() && cur_vertex < num_verts)
 				{
-					y = 0;
+					const U8 END_INFLUENCES = 0xFF;
+					U8 joint = weights[idx++];
+
+					U32 cur_influence = 0;
+					LLVector4 wght(0,0,0,0);
+
+					while (joint != END_INFLUENCES && idx < weights.size())
+					{
+						U16 influence = weights[idx++];
+						influence |= ((U16) weights[idx++] << 8);
+
+						F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f);
+						wght.mV[cur_influence++] = (F32) joint + w;
+
+						if (cur_influence >= 4)
+						{
+							joint = END_INFLUENCES;
+						}
+						else
+						{
+							joint = weights[idx++];
+						}
+					}
+
+					face.mWeights[cur_vertex].loadua(wght.mV);
+
+					cur_vertex++;
 				}
-				else
+
+				if (cur_vertex != num_verts || idx != weights.size())
 				{
-					y = sculpt_height - 1;
+					llwarns << "Vertex weight count does not match vertex count!" << llendl;
 				}
+					
+			}
 
-				// pinch?
-				if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE)
+			LLVector3 minp;
+			LLVector3 maxp;
+			LLVector2 min_tc; 
+			LLVector2 max_tc; 
+		
+			minp.setValue(mdl[i]["PositionDomain"]["Min"]);
+			maxp.setValue(mdl[i]["PositionDomain"]["Max"]);
+			LLVector4a min_pos, max_pos;
+			min_pos.load3(minp.mV);
+			max_pos.load3(maxp.mV);
+
+			min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
+			max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
+
+			LLVector4a pos_range;
+			pos_range.setSub(max_pos, min_pos);
+			LLVector2 tc_range = max_tc - min_tc;
+
+			LLVector4a* pos_out = face.mPositions;
+			LLVector4a* norm_out = face.mNormals;
+			LLVector2* tc_out = face.mTexCoords;
+
+			for (U32 j = 0; j < num_verts; ++j)
+			{
+				U16* v = (U16*) &(pos[j*3*2]);
+
+				pos_out->set((F32) v[0], (F32) v[1], (F32) v[2]);
+				pos_out->div(65535.f);
+				pos_out->mul(pos_range);
+				pos_out->add(min_pos);
+
+				pos_out++;
+
+				U16* n = (U16*) &(norm[j*3*2]);
+
+				norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]);
+				norm_out->div(65535.f);
+				norm_out->mul(2.f);
+				norm_out->sub(1.f);
+				norm_out++;
+
+				U16* t = (U16*) &(tc[j*2*2]);
+
+				tc_out->mV[0] = (F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0];
+				tc_out->mV[1] =	(F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1];
+
+				tc_out++;
+			}
+
+			
+			// modifier flags?
+			bool do_mirror = (mParams.getSculptType() & LL_SCULPT_FLAG_MIRROR);
+			bool do_invert = (mParams.getSculptType() &LL_SCULPT_FLAG_INVERT);
+			
+			
+			// translate to actions:
+			bool do_reflect_x = false;
+			bool do_reverse_triangles = false;
+			bool do_invert_normals = false;
+			
+			if (do_mirror)
+			{
+				do_reflect_x = true;
+				do_reverse_triangles = !do_reverse_triangles;
+			}
+			
+			if (do_invert)
+			{
+				do_invert_normals = true;
+				do_reverse_triangles = !do_reverse_triangles;
+			}
+			
+			// now do the work
+
+			if (do_reflect_x)
+			{
+				LLVector4a* p = (LLVector4a*) face.mPositions;
+				LLVector4a* n = (LLVector4a*) face.mNormals;
+				
+				for (S32 i = 0; i < face.mNumVertices; i++)
 				{
-					x = sculpt_width / 2;
+					p[i].mul(-1.0f);
+					n[i].mul(-1.0f);
 				}
 			}
 
-			if (x == sculpt_width)   // side stitching
+			if (do_invert_normals)
 			{
-				// wrap?
-				if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) ||
-					(sculpt_stitching == LL_SCULPT_TYPE_TORUS) ||
-					(sculpt_stitching == LL_SCULPT_TYPE_CYLINDER))
+				LLVector4a* n = (LLVector4a*) face.mNormals;
+				
+				for (S32 i = 0; i < face.mNumVertices; i++)
 				{
-					x = 0;
+					n[i].mul(-1.0f);
 				}
-					
-				else
+			}
+
+			if (do_reverse_triangles)
+			{
+				for (U32 j = 0; j < face.mNumIndices; j += 3)
 				{
-					x = sculpt_width - 1;
+					// swap the 2nd and 3rd index
+					S32 swap = face.mIndices[j+1];
+					face.mIndices[j+1] = face.mIndices[j+2];
+					face.mIndices[j+2] = swap;
 				}
 			}
 
-			pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data);
+			//calculate bounding box
+			LLVector4a& min = face.mExtents[0];
+			LLVector4a& max = face.mExtents[1];
 
-			if (sculpt_mirror)
+			min.clear();
+			max.clear();
+			min = max = face.mPositions[0];
+
+			for (S32 i = 1; i < face.mNumVertices; ++i)
 			{
-				pt.mPos.mV[VX] *= -1.f;
+				min.setMin(min, face.mPositions[i]);
+				max.setMax(max, face.mPositions[i]);
 			}
 		}
-		
-		line += sizeT;
 	}
+
+	mSculptLevel = 0;  // success!
+
+	cacheOptimize();
+
+	return true;
 }
 
+void tetrahedron_set_normal(LLVolumeFace::VertexData* cv)
+{
+	LLVector4a v0;
+	v0.setSub(cv[1].getPosition(), cv[0].getNormal());
+	LLVector4a v1;
+	v1.setSub(cv[2].getNormal(), cv[0].getPosition());
+	
+	cv[0].getNormal().setCross3(v0,v1);
+	cv[0].getNormal().normalize3fast();
+	cv[1].setNormal(cv[0].getNormal());
+	cv[2].setNormal(cv[1].getNormal());
+}
 
-const S32 SCULPT_REZ_1 = 6;  // changed from 4 to 6 - 6 looks round whereas 4 looks square
-const S32 SCULPT_REZ_2 = 8;
-const S32 SCULPT_REZ_3 = 16;
-const S32 SCULPT_REZ_4 = 32;
+BOOL LLVolume::isTetrahedron()
+{
+	return mIsTetrahedron;
+}
 
-S32 sculpt_sides(F32 detail)
+void LLVolume::makeTetrahedron()
 {
+	mVolumeFaces.clear();
 
-	// detail is usually one of: 1, 1.5, 2.5, 4.0.
+	LLVolumeFace face;
+
+	F32 x = 0.25f;
+	LLVector4a p[] = 
+	{ //unit tetrahedron corners
+		LLVector4a(x,x,x),
+		LLVector4a(-x,-x,x),
+		LLVector4a(-x,x,-x),
+		LLVector4a(x,-x,-x)
+	};
+
+	face.mExtents[0].splat(-x);
+	face.mExtents[1].splat(x);
 	
-	if (detail <= 1.0)
-	{
-		return SCULPT_REZ_1;
-	}
-	if (detail <= 2.0)
+	LLVolumeFace::VertexData cv[3];
+
+	//set texture coordinates
+	cv[0].mTexCoord = LLVector2(0,0);
+	cv[1].mTexCoord = LLVector2(1,0);
+	cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3);
+
+
+	//side 1
+	cv[0].setPosition(p[1]);
+	cv[1].setPosition(p[0]);
+	cv[2].setPosition(p[2]);
+
+	tetrahedron_set_normal(cv);
+
+	face.resizeVertices(12);
+	face.resizeIndices(12);
+
+	LLVector4a* v = (LLVector4a*) face.mPositions;
+	LLVector4a* n = (LLVector4a*) face.mNormals;
+	LLVector2* tc = (LLVector2*) face.mTexCoords;
+
+	v[0] = cv[0].getPosition();
+	v[1] = cv[1].getPosition();
+	v[2] = cv[2].getPosition();
+	v += 3;
+
+	n[0] = cv[0].getNormal();
+	n[1] = cv[1].getNormal();
+	n[2] = cv[2].getNormal();
+	n += 3;
+
+	tc[0] = cv[0].mTexCoord;
+	tc[1] = cv[1].mTexCoord;
+	tc[2] = cv[2].mTexCoord;
+	tc += 3;
+
+	
+	//side 2
+	cv[0].setPosition(p[3]);
+	cv[1].setPosition(p[0]);
+	cv[2].setPosition(p[1]);
+
+	tetrahedron_set_normal(cv);
+
+	v[0] = cv[0].getPosition();
+	v[1] = cv[1].getPosition();
+	v[2] = cv[2].getPosition();
+	v += 3;
+
+	n[0] = cv[0].getNormal();
+	n[1] = cv[1].getNormal();
+	n[2] = cv[2].getNormal();
+	n += 3;
+
+	tc[0] = cv[0].mTexCoord;
+	tc[1] = cv[1].mTexCoord;
+	tc[2] = cv[2].mTexCoord;
+	tc += 3;
+	
+	//side 3
+	cv[0].setPosition(p[3]);
+	cv[1].setPosition(p[1]);
+	cv[2].setPosition(p[2]);
+
+	tetrahedron_set_normal(cv);
+
+	v[0] = cv[0].getPosition();
+	v[1] = cv[1].getPosition();
+	v[2] = cv[2].getPosition();
+	v += 3;
+
+	n[0] = cv[0].getNormal();
+	n[1] = cv[1].getNormal();
+	n[2] = cv[2].getNormal();
+	n += 3;
+
+	tc[0] = cv[0].mTexCoord;
+	tc[1] = cv[1].mTexCoord;
+	tc[2] = cv[2].mTexCoord;
+	tc += 3;
+	
+	//side 4
+	cv[0].setPosition(p[2]);
+	cv[1].setPosition(p[0]);
+	cv[2].setPosition(p[3]);
+
+	tetrahedron_set_normal(cv);
+
+	v[0] = cv[0].getPosition();
+	v[1] = cv[1].getPosition();
+	v[2] = cv[2].getPosition();
+	v += 3;
+
+	n[0] = cv[0].getNormal();
+	n[1] = cv[1].getNormal();
+	n[2] = cv[2].getNormal();
+	n += 3;
+
+	tc[0] = cv[0].mTexCoord;
+	tc[1] = cv[1].mTexCoord;
+	tc[2] = cv[2].mTexCoord;
+	tc += 3;
+	
+	//set index buffer
+	for (U16 i = 0; i < 12; i++)
 	{
-		return SCULPT_REZ_2;
+		face.mIndices[i] = i;
 	}
-	if (detail <= 3.0)
+	
+	mVolumeFaces.push_back(face);
+	mSculptLevel = 0;
+	mIsTetrahedron = TRUE;
+}
+
+void LLVolume::copyVolumeFaces(const LLVolume* volume)
+{
+	mVolumeFaces = volume->mVolumeFaces;
+	mSculptLevel = 0;
+	mIsTetrahedron = FALSE;
+}
+
+void LLVolume::cacheOptimize()
+{
+	for (S32 i = 0; i < mVolumeFaces.size(); ++i)
 	{
-		return SCULPT_REZ_3;
+		mVolumeFaces[i].cacheOptimize();
 	}
-	else
+}
+
+
+S32	LLVolume::getNumFaces() const
+{
+	U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
+
+	if (sculpt_type == LL_SCULPT_TYPE_MESH)
 	{
-		return SCULPT_REZ_4;
+		return LL_SCULPT_MESH_MAX_FACES;
 	}
-}
 
+	return (S32)mProfilep->mFaces.size();
+}
 
 
-// determine the number of vertices in both s and t direction for this sculpt
-void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t)
-{
-	// this code has the following properties:
-	// 1) the aspect ratio of the mesh is as close as possible to the ratio of the map
-	//    while still using all available verts
-	// 2) the mesh cannot have more verts than is allowed by LOD
-	// 3) the mesh cannot have more verts than is allowed by the map
-	
-	S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0);
-	S32 max_vertices_map = width * height / 4;
-	
-	S32 vertices;
-	if (max_vertices_map > 0)
-		vertices = llmin(max_vertices_lod, max_vertices_map);
-	else
-		vertices = max_vertices_lod;
-	
-
-	F32 ratio;
-	if ((width == 0) || (height == 0))
-		ratio = 1.f;
-	else
-		ratio = (F32) width / (F32) height;
-
-	
-	s = (S32)fsqrtf(((F32)vertices / ratio));
-
-	s = llmax(s, 4);              // no degenerate sizes, please
-	t = vertices / s;
-
-	t = llmax(t, 4);              // no degenerate sizes, please
-	s = vertices / t;
-}
-
-// sculpt replaces generate() for sculpted surfaces
-void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level)
+void LLVolume::createVolumeFaces()
 {
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
-    U8 sculpt_type = mParams.getSculptType();
-
-	BOOL data_is_empty = FALSE;
 
-	if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL)
+	if (mGenerateSingleFace)
 	{
-		sculpt_level = -1;
-		data_is_empty = TRUE;
+		// do nothing
 	}
-
-	S32 requested_sizeS = 0;
-	S32 requested_sizeT = 0;
-
-	sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT);
-
-	mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS);
-	mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT);
-
-	S32 sizeS = mPathp->mPath.size();         // we requested a specific size, now see what we really got
-	S32 sizeT = mProfilep->mProfile.size();   // we requested a specific size, now see what we really got
-
-	// weird crash bug - DEV-11158 - trying to collect more data:
-	if ((sizeS == 0) || (sizeT == 0))
+	else
 	{
-		llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl;
-	}
-	
-	sNumMeshPoints -= mMesh.size();
-	mMesh.resize(sizeS * sizeT);
-	sNumMeshPoints += mMesh.size();
+		S32 num_faces = getNumFaces();
+		BOOL partial_build = TRUE;
+		if (num_faces != mVolumeFaces.size())
+		{
+			partial_build = FALSE;
+			mVolumeFaces.resize(num_faces);
+		}
+		// Initialize volume faces with parameter data
+		for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++)
+		{
+			LLVolumeFace& vf = mVolumeFaces[i];
+			LLProfile::Face& face = mProfilep->mFaces[i];
+			vf.mBeginS = face.mIndex;
+			vf.mNumS = face.mCount;
+			if (vf.mNumS < 0)
+			{
+				llerrs << "Volume face corruption detected." << llendl;
+			}
 
-	//generate vertex positions
-	if (!data_is_empty)
-	{
-		sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type);
+			vf.mBeginT = 0;
+			vf.mNumT= getPath().mPath.size();
+			vf.mID = i;
 
-		// don't test lowest LOD to support legacy content DEV-33670
-		if (mDetail > SCULPT_MIN_AREA_DETAIL)
-		{
-			if (sculptGetSurfaceArea() < SCULPT_MIN_AREA)
+			// Set the type mask bits correctly
+			if (mParams.getProfileParams().getHollow() > 0)
 			{
-				data_is_empty = TRUE;
+				vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK;
+			}
+			if (mProfilep->isOpen())
+			{
+				vf.mTypeMask |= LLVolumeFace::OPEN_MASK;
+			}
+			if (face.mCap)
+			{
+				vf.mTypeMask |= LLVolumeFace::CAP_MASK;
+				if (face.mFaceID == LL_FACE_PATH_BEGIN)
+				{
+					vf.mTypeMask |= LLVolumeFace::TOP_MASK;
+				}
+				else
+				{
+					llassert(face.mFaceID == LL_FACE_PATH_END);
+					vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK;
+				}
+			}
+			else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
+			{
+				vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK;
+			}
+			else
+			{
+				vf.mTypeMask |= LLVolumeFace::SIDE_MASK;
+				if (face.mFlat)
+				{
+					vf.mTypeMask |= LLVolumeFace::FLAT_MASK;
+				}
+				if (face.mFaceID & LL_FACE_INNER_SIDE)
+				{
+					vf.mTypeMask |= LLVolumeFace::INNER_MASK;
+					if (face.mFlat && vf.mNumS > 2)
+					{ //flat inner faces have to copy vert normals
+						vf.mNumS = vf.mNumS*2;
+						if (vf.mNumS < 0)
+						{
+							llerrs << "Volume face corruption detected." << llendl;
+						}
+					}
+				}
+				else
+				{
+					vf.mTypeMask |= LLVolumeFace::OUTER_MASK;
+				}
 			}
 		}
-	}
 
-	if (data_is_empty)
-	{
-		sculptGeneratePlaceholder();
+		for (face_list_t::iterator iter = mVolumeFaces.begin();
+			 iter != mVolumeFaces.end(); ++iter)
+		{
+			(*iter).create(this, partial_build);
+		}
 	}
+}
 
 
-	
-	for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++)
-	{
-		mFaceMask |= mProfilep->mFaces[i].mFaceID;
-	}
-
-	mSculptLevel = sculpt_level;
+inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b)
+{
+	// maps RGB values to vector values [0..255] -> [-0.5..0.5]
+	LLVector3 value;
+	value.mV[VX] = r / 255.f - 0.5f;
+	value.mV[VY] = g / 255.f - 0.5f;
+	value.mV[VZ] = b / 255.f - 0.5f;
 
-	// Delete any existing faces so that they get regenerated
-	mVolumeFaces.clear();
-	
-	createVolumeFaces();
+	return value;
 }
 
+inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
+{
+	U32 index = (x + y * sculpt_width) * sculpt_components;
+	return index;
+}
 
 
-
-BOOL LLVolume::isCap(S32 face)
+inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
 {
-	return mProfilep->mFaces[face].mCap; 
+	U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width);
+	U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height);
+
+	return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
 }
 
-BOOL LLVolume::isFlat(S32 face)
+
+inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data)
 {
-	return mProfilep->mFaces[face].mFlat;
-}
+	LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]);
 
+	return v;
+}
 
-bool LLVolumeParams::operator==(const LLVolumeParams &params) const
+inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
 {
-	return ( (getPathParams() == params.getPathParams()) &&
-			 (getProfileParams() == params.getProfileParams()) &&
-			 (mSculptID == params.mSculptID) &&
-			 (mSculptType == params.mSculptType) );
+	U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components);
+
+	return sculpt_index_to_vector(index, sculpt_data);
 }
 
-bool LLVolumeParams::operator!=(const LLVolumeParams &params) const
+inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
 {
-	return ( (getPathParams() != params.getPathParams()) ||
-			 (getProfileParams() != params.getProfileParams()) ||
-			 (mSculptID != params.mSculptID) ||
-			 (mSculptType != params.mSculptType) );
+	U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
+
+	return sculpt_index_to_vector(index, sculpt_data);
 }
 
-bool LLVolumeParams::operator<(const LLVolumeParams &params) const
+
+F32 LLVolume::sculptGetSurfaceArea()
 {
-	if( getPathParams() != params.getPathParams() )
-	{
-		return getPathParams() < params.getPathParams();
-	}
-	
-	if (getProfileParams() != params.getProfileParams())
-	{
-		return getProfileParams() < params.getProfileParams();
-	}
-	
-	if (mSculptID != params.mSculptID)
-	{
-		return mSculptID < params.mSculptID;
-	}
+	// test to see if image has enough variation to create non-degenerate geometry
 
+	F32 area = 0;
 
-	return mSculptType < params.mSculptType;
+	S32 sizeS = mPathp->mPath.size();
+	S32 sizeT = mProfilep->mProfile.size();
+			
+	for (S32 s = 0; s < sizeS-1; s++)
+	{
+		for (S32 t = 0; t < sizeT-1; t++)
+		{
+			// get four corners of quad
+			LLVector3 p1 = mMesh[(s  )*sizeT + (t  )].mPos;
+			LLVector3 p2 = mMesh[(s+1)*sizeT + (t  )].mPos;
+			LLVector3 p3 = mMesh[(s  )*sizeT + (t+1)].mPos;
+			LLVector3 p4 = mMesh[(s+1)*sizeT + (t+1)].mPos;
 
+			// compute the area of the quad by taking the length of the cross product of the two triangles
+			LLVector3 cross1 = (p1 - p2) % (p1 - p3);
+			LLVector3 cross2 = (p4 - p2) % (p4 - p3);
+			area += (cross1.magVec() + cross2.magVec()) / 2.0;
+		}
+	}
 
+	return area;
 }
 
-void LLVolumeParams::copyParams(const LLVolumeParams &params)
+// create placeholder shape
+void LLVolume::sculptGeneratePlaceholder()
 {
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
-	mProfileParams.copyParams(params.mProfileParams);
-	mPathParams.copyParams(params.mPathParams);
-	mSculptID = params.getSculptID();
-	mSculptType = params.getSculptType();
-}
-
-// Less restricitve approx 0 for volumes
-const F32 APPROXIMATELY_ZERO = 0.001f;
-bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO)
-{
-	return (f >= -tolerance) && (f <= tolerance);
-}
+	
+	S32 sizeS = mPathp->mPath.size();
+	S32 sizeT = mProfilep->mProfile.size();
+	
+	S32 line = 0;
 
-// return true if in range (or nearly so)
-static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO)
-{
-	F32 min_delta = v - min;
-	if (min_delta < 0.f)
-	{
-		v = min;
-		if (!approx_zero(min_delta, tolerance))
-			return false;
-	}
-	F32 max_delta = max - v;
-	if (max_delta < 0.f)
+	// for now, this is a sphere.
+	for (S32 s = 0; s < sizeS; s++)
 	{
-		v = max;
-		if (!approx_zero(max_delta, tolerance))
-			return false;
-	}
-	return true;
-}
-
-bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e)
-{
-	bool valid = true;
-
-	// First, clamp to valid ranges.
-	F32 begin = b;
-	valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
-
-	F32 end = e;
-	if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error
-	valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
+		for (S32 t = 0; t < sizeT; t++)
+		{
+			S32 i = t + line;
+			Point& pt = mMesh[i];
 
-	valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
+			
+			F32 u = (F32)s/(sizeS-1);
+			F32 v = (F32)t/(sizeT-1);
 
-	// Now set them.
-	mProfileParams.setBegin(begin);
-	mProfileParams.setEnd(end);
+			const F32 RADIUS = (F32) 0.3;
+					
+			pt.mPos.mV[0] = (F32)(sin(F_PI * v) * cos(2.0 * F_PI * u) * RADIUS);
+			pt.mPos.mV[1] = (F32)(sin(F_PI * v) * sin(2.0 * F_PI * u) * RADIUS);
+			pt.mPos.mV[2] = (F32)(cos(F_PI * v) * RADIUS);
 
-	return valid;
+		}
+		line += sizeT;
+	}
 }
 
-bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e)
+// create the vertices from the map
+void LLVolume::sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type)
 {
-	bool valid = true;
+	U8 sculpt_stitching = sculpt_type & LL_SCULPT_TYPE_MASK;
+	BOOL sculpt_invert = sculpt_type & LL_SCULPT_FLAG_INVERT;
+	BOOL sculpt_mirror = sculpt_type & LL_SCULPT_FLAG_MIRROR;
+	BOOL reverse_horizontal = (sculpt_invert ? !sculpt_mirror : sculpt_mirror);  // XOR
+	
+	
+	LLMemType m1(LLMemType::MTYPE_VOLUME);
+	
+	S32 sizeS = mPathp->mPath.size();
+	S32 sizeT = mProfilep->mProfile.size();
+	
+	S32 line = 0;
+	for (S32 s = 0; s < sizeS; s++)
+	{
+		// Run along the profile.
+		for (S32 t = 0; t < sizeT; t++)
+		{
+			S32 i = t + line;
+			Point& pt = mMesh[i];
 
-	// First, clamp to valid ranges.
-	F32 begin = b;
-	valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
+			S32 reversed_t = t;
 
-	F32 end = e;
-	valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
+			if (reverse_horizontal)
+			{
+				reversed_t = sizeT - t - 1;
+			}
+			
+			U32 x = (U32) ((F32)reversed_t/(sizeT-1) * (F32) sculpt_width);
+			U32 y = (U32) ((F32)s/(sizeS-1) * (F32) sculpt_height);
 
-	valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
+			
+			if (y == 0)  // top row stitching
+			{
+				// pinch?
+				if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE)
+				{
+					x = sculpt_width / 2;
+				}
+			}
 
-	// Now set them.
-	mPathParams.setBegin(begin);
-	mPathParams.setEnd(end);
+			if (y == sculpt_height)  // bottom row stitching
+			{
+				// wrap?
+				if (sculpt_stitching == LL_SCULPT_TYPE_TORUS)
+				{
+					y = 0;
+				}
+				else
+				{
+					y = sculpt_height - 1;
+				}
 
-	return valid;
-}			
+				// pinch?
+				if (sculpt_stitching == LL_SCULPT_TYPE_SPHERE)
+				{
+					x = sculpt_width / 2;
+				}
+			}
 
-bool LLVolumeParams::setHollow(const F32 h)
-{
-	// Validate the hollow based on path and profile.
-	U8 profile 	= mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
-	U8 hole_type 	= mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK;
-	
-	F32 max_hollow = HOLLOW_MAX;
+			if (x == sculpt_width)   // side stitching
+			{
+				// wrap?
+				if ((sculpt_stitching == LL_SCULPT_TYPE_SPHERE) ||
+					(sculpt_stitching == LL_SCULPT_TYPE_TORUS) ||
+					(sculpt_stitching == LL_SCULPT_TYPE_CYLINDER))
+				{
+					x = 0;
+				}
+					
+				else
+				{
+					x = sculpt_width - 1;
+				}
+			}
 
-	// Only square holes have trouble.
-	if (LL_PCODE_HOLE_SQUARE == hole_type)
-	{
-		switch(profile)
-		{
-		case LL_PCODE_PROFILE_CIRCLE:
-		case LL_PCODE_PROFILE_CIRCLE_HALF:
-		case LL_PCODE_PROFILE_EQUALTRI:
-			max_hollow = HOLLOW_MAX_SQUARE;
+			pt.mPos = sculpt_xy_to_vector(x, y, sculpt_width, sculpt_height, sculpt_components, sculpt_data);
+
+			if (sculpt_mirror)
+			{
+				pt.mPos.mV[VX] *= -1.f;
+			}
 		}
+		
+		line += sizeT;
 	}
+}
 
-	F32 hollow = h;
-	bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow);
-	mProfileParams.setHollow(hollow); 
 
-	return valid;
-}	
+const S32 SCULPT_REZ_1 = 6;  // changed from 4 to 6 - 6 looks round whereas 4 looks square
+const S32 SCULPT_REZ_2 = 8;
+const S32 SCULPT_REZ_3 = 16;
+const S32 SCULPT_REZ_4 = 32;
 
-bool LLVolumeParams::setTwistBegin(const F32 b)
+S32 sculpt_sides(F32 detail)
 {
-	F32 twist_begin = b;
-	bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX);
-	mPathParams.setTwistBegin(twist_begin);
-	return valid;
-}
-
-bool LLVolumeParams::setTwistEnd(const F32 e)
-{	
-	F32 twist_end = e;
-	bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX);
-	mPathParams.setTwistEnd(twist_end);
-	return valid;
-}
 
-bool LLVolumeParams::setRatio(const F32 x, const F32 y)
-{
-	F32 min_x = RATIO_MIN;
-	F32 max_x = RATIO_MAX;
-	F32 min_y = RATIO_MIN;
-	F32 max_y = RATIO_MAX;
-	// If this is a circular path (and not a sphere) then 'ratio' is actually hole size.
-	U8 path_type 	= mPathParams.getCurveType();
-	U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
-	if ( LL_PCODE_PATH_CIRCLE == path_type &&
-		 LL_PCODE_PROFILE_CIRCLE_HALF != profile_type)
+	// detail is usually one of: 1, 1.5, 2.5, 4.0.
+	
+	if (detail <= 1.0)
 	{
-		// Holes are more restricted...
-		min_x = HOLE_X_MIN;
-		max_x = HOLE_X_MAX;
-		min_y = HOLE_Y_MIN;
-		max_y = HOLE_Y_MAX;
+		return SCULPT_REZ_1;
+	}
+	if (detail <= 2.0)
+	{
+		return SCULPT_REZ_2;
+	}
+	if (detail <= 3.0)
+	{
+		return SCULPT_REZ_3;
+	}
+	else
+	{
+		return SCULPT_REZ_4;
 	}
-
-	F32 ratio_x = x;
-	bool valid = limit_range(ratio_x, min_x, max_x);
-	F32 ratio_y = y;
-	valid &= limit_range(ratio_y, min_y, max_y);
-
-	mPathParams.setScale(ratio_x, ratio_y);
-
-	return valid;
 }
 
-bool LLVolumeParams::setShear(const F32 x, const F32 y)
-{
-	F32 shear_x = x;
-	bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX);
-	F32 shear_y = y;
-	valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX);
-	mPathParams.setShear(shear_x, shear_y);
-	return valid;
-}
 
-bool LLVolumeParams::setTaperX(const F32 v)
-{
-	F32 taper = v;
-	bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
-	mPathParams.setTaperX(taper);
-	return valid;
-}
 
-bool LLVolumeParams::setTaperY(const F32 v)
+// determine the number of vertices in both s and t direction for this sculpt
+void sculpt_calc_mesh_resolution(U16 width, U16 height, U8 type, F32 detail, S32& s, S32& t)
 {
-	F32 taper = v;
-	bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
-	mPathParams.setTaperY(taper);
-	return valid;
-}
+	// this code has the following properties:
+	// 1) the aspect ratio of the mesh is as close as possible to the ratio of the map
+	//    while still using all available verts
+	// 2) the mesh cannot have more verts than is allowed by LOD
+	// 3) the mesh cannot have more verts than is allowed by the map
+	
+	S32 max_vertices_lod = (S32)pow((double)sculpt_sides(detail), 2.0);
+	S32 max_vertices_map = width * height / 4;
+	
+	S32 vertices;
+	if (max_vertices_map > 0)
+		vertices = llmin(max_vertices_lod, max_vertices_map);
+	else
+		vertices = max_vertices_lod;
+	
 
-bool LLVolumeParams::setRevolutions(const F32 r)
-{
-	F32 revolutions = r;
-	bool valid = limit_range(revolutions, REV_MIN, REV_MAX);
-	mPathParams.setRevolutions(revolutions);
-	return valid;
+	F32 ratio;
+	if ((width == 0) || (height == 0))
+		ratio = 1.f;
+	else
+		ratio = (F32) width / (F32) height;
+
+	
+	s = (S32)(F32) sqrt(((F32)vertices / ratio));
+
+	s = llmax(s, 4);              // no degenerate sizes, please
+	t = vertices / s;
+
+	t = llmax(t, 4);              // no degenerate sizes, please
+	s = vertices / t;
 }
 
-bool LLVolumeParams::setRadiusOffset(const F32 offset)
+// sculpt replaces generate() for sculpted surfaces
+void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level)
 {
-	bool valid = true;
+	LLMemType m1(LLMemType::MTYPE_VOLUME);
+    U8 sculpt_type = mParams.getSculptType();
 
-	// If this is a sphere, just set it to 0 and get out.
-	U8 path_type 	= mPathParams.getCurveType();
-	U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
-	if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ||
-		LL_PCODE_PATH_CIRCLE != path_type )
+	BOOL data_is_empty = FALSE;
+
+	if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL)
 	{
-		mPathParams.setRadiusOffset(0.f);
-		return true;
+		sculpt_level = -1;
+		data_is_empty = TRUE;
 	}
 
-	// Limit radius offset, based on taper and hole size y.
-	F32 radius_offset	= offset;
-	F32 taper_y    		= getTaperY();
-	F32 radius_mag		= fabs(radius_offset);
-	F32 hole_y_mag 		= fabs(getRatioY());
-	F32 taper_y_mag		= fabs(taper_y);
-	// Check to see if the taper effects us.
-	if ( (radius_offset > 0.f && taper_y < 0.f) ||
-			(radius_offset < 0.f && taper_y > 0.f) )
+	S32 requested_sizeS = 0;
+	S32 requested_sizeT = 0;
+
+	sculpt_calc_mesh_resolution(sculpt_width, sculpt_height, sculpt_type, mDetail, requested_sizeS, requested_sizeT);
+
+	mPathp->generate(mParams.getPathParams(), mDetail, 0, TRUE, requested_sizeS);
+	mProfilep->generate(mParams.getProfileParams(), mPathp->isOpen(), mDetail, 0, TRUE, requested_sizeT);
+
+	S32 sizeS = mPathp->mPath.size();         // we requested a specific size, now see what we really got
+	S32 sizeT = mProfilep->mProfile.size();   // we requested a specific size, now see what we really got
+
+	// weird crash bug - DEV-11158 - trying to collect more data:
+	if ((sizeS == 0) || (sizeT == 0))
 	{
-		// The taper does not help increase the radius offset range.
-		taper_y_mag = 0.f;
+		llwarns << "sculpt bad mesh size " << sizeS << " " << sizeT << llendl;
 	}
-	F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
+	
+	sNumMeshPoints -= mMesh.size();
+	mMesh.resize(sizeS * sizeT);
+	sNumMeshPoints += mMesh.size();
 
-	// Enforce the maximum magnitude.
-	F32 delta = max_radius_mag - radius_mag;
-	if (delta < 0.f)
+	//generate vertex positions
+	if (!data_is_empty)
 	{
-		// Check radius offset sign.
-		if (radius_offset < 0.f)
-		{
-			radius_offset = -max_radius_mag;
-		}
-		else
+		sculptGenerateMapVertices(sculpt_width, sculpt_height, sculpt_components, sculpt_data, sculpt_type);
+
+		// don't test lowest LOD to support legacy content DEV-33670
+		if (mDetail > SCULPT_MIN_AREA_DETAIL)
 		{
-			radius_offset = max_radius_mag;
+			if (sculptGetSurfaceArea() < SCULPT_MIN_AREA)
+			{
+				data_is_empty = TRUE;
+			}
 		}
-		valid = approx_zero(delta, .1f);
 	}
 
-	mPathParams.setRadiusOffset(radius_offset);
-	return valid;
+	if (data_is_empty)
+	{
+		sculptGeneratePlaceholder();
+	}
+
+
+	
+	for (S32 i = 0; i < (S32)mProfilep->mFaces.size(); i++)
+	{
+		mFaceMask |= mProfilep->mFaces[i].mFaceID;
+	}
+
+	mSculptLevel = sculpt_level;
+
+	// Delete any existing faces so that they get regenerated
+	mVolumeFaces.clear();
+	
+	createVolumeFaces();
 }
 
-bool LLVolumeParams::setSkew(const F32 skew_value)
+
+
+
+BOOL LLVolume::isCap(S32 face)
 {
-	bool valid = true;
+	return mProfilep->mFaces[face].mCap; 
+}
 
-	// Check the skew value against the revolutions.
-	F32 skew		= llclamp(skew_value, SKEW_MIN, SKEW_MAX);
-	F32 skew_mag	= fabs(skew);
-	F32 revolutions = getRevolutions();
-	F32 scale_x		= getRatioX();
-	F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
-	// Discontinuity; A revolution of 1 allows skews below 0.5.
-	if ( fabs(revolutions - 1.0f) < 0.001)
-		min_skew_mag = 0.0f;
+BOOL LLVolume::isFlat(S32 face)
+{
+	return mProfilep->mFaces[face].mFlat;
+}
 
-	// Clip skew.
-	F32 delta = skew_mag - min_skew_mag;
-	if (delta < 0.f)
-	{
-		// Check skew sign.
-		if (skew < 0.0f)
-		{
-			skew = -min_skew_mag;
-		}
-		else 
-		{
-			skew = min_skew_mag;
-		}
-		valid = approx_zero(delta, .01f);
-	}
 
-	mPathParams.setSkew(skew);
-	return valid;
+bool LLVolumeParams::isSculpt() const
+{
+	return mSculptID.notNull();
 }
 
-bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type)
+bool LLVolumeParams::isMeshSculpt() const
 {
-	mSculptID = sculpt_id;
-	mSculptType = sculpt_type;
-	return true;
+	return isSculpt() && ((mSculptType & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH);
 }
 
-bool LLVolumeParams::setType(U8 profile, U8 path)
+bool LLVolumeParams::operator==(const LLVolumeParams &params) const
 {
-	bool result = true;
-	// First, check profile and path for validity.
-	U8 profile_type	= profile & LL_PCODE_PROFILE_MASK;
-	U8 hole_type 	= (profile & LL_PCODE_HOLE_MASK) >> 4;
-	U8 path_type	= path >> 4;
+	return ( (getPathParams() == params.getPathParams()) &&
+			 (getProfileParams() == params.getProfileParams()) &&
+			 (mSculptID == params.mSculptID) &&
+			 (mSculptType == params.mSculptType) );
+}
 
-	if (profile_type > LL_PCODE_PROFILE_MAX)
+bool LLVolumeParams::operator!=(const LLVolumeParams &params) const
+{
+	return ( (getPathParams() != params.getPathParams()) ||
+			 (getProfileParams() != params.getProfileParams()) ||
+			 (mSculptID != params.mSculptID) ||
+			 (mSculptType != params.mSculptType) );
+}
+
+bool LLVolumeParams::operator<(const LLVolumeParams &params) const
+{
+	if( getPathParams() != params.getPathParams() )
 	{
-		// Bad profile.  Make it square.
-		profile = LL_PCODE_PROFILE_SQUARE;
-		result = false;
-		llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type
-			 	<< ") to be LL_PCODE_PROFILE_SQUARE" << llendl;
+		return getPathParams() < params.getPathParams();
 	}
-	else if (hole_type > LL_PCODE_HOLE_MAX)
+	
+	if (getProfileParams() != params.getProfileParams())
 	{
-		// Bad hole.  Make it the same.
-		profile = profile_type;
-		result = false;
-		llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type
-			 	<< ") to be LL_PCODE_HOLE_SAME" << llendl;
+		return getProfileParams() < params.getProfileParams();
 	}
-
-	if (path_type < LL_PCODE_PATH_MIN ||
-		path_type > LL_PCODE_PATH_MAX)
+	
+	if (mSculptID != params.mSculptID)
 	{
-		// Bad path.  Make it linear.
-		result = false;
-		llwarns << "LLVolumeParams::setType changing bad path (" << path
-			 	<< ") to be LL_PCODE_PATH_LINE" << llendl;
-		path = LL_PCODE_PATH_LINE;
+		return mSculptID < params.mSculptID;
 	}
 
-	mProfileParams.setCurveType(profile);
-	mPathParams.setCurveType(path);
-	return result;
+	return mSculptType < params.mSculptType;
+
+
 }
 
-// static 
-bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
-		U8 path_curve, F32 path_begin, F32 path_end,
-		F32 scx, F32 scy, F32 shx, F32 shy,
-		F32 twistend, F32 twistbegin, F32 radiusoffset,
-		F32 tx, F32 ty, F32 revolutions, F32 skew)
+void LLVolumeParams::copyParams(const LLVolumeParams &params)
 {
-	LLVolumeParams test_params;
-	if (!test_params.setType		(prof_curve, path_curve))
+	LLMemType m1(LLMemType::MTYPE_VOLUME);
+	mProfileParams.copyParams(params.mProfileParams);
+	mPathParams.copyParams(params.mPathParams);
+	mSculptID = params.getSculptID();
+	mSculptType = params.getSculptType();
+}
+
+// Less restricitve approx 0 for volumes
+const F32 APPROXIMATELY_ZERO = 0.001f;
+bool approx_zero( F32 f, F32 tolerance = APPROXIMATELY_ZERO)
+{
+	return (f >= -tolerance) && (f <= tolerance);
+}
+
+// return true if in range (or nearly so)
+static bool limit_range(F32& v, F32 min, F32 max, F32 tolerance = APPROXIMATELY_ZERO)
+{
+	F32 min_delta = v - min;
+	if (min_delta < 0.f)
 	{
-	    	return false;
+		v = min;
+		if (!approx_zero(min_delta, tolerance))
+			return false;
+	}
+	F32 max_delta = max - v;
+	if (max_delta < 0.f)
+	{
+		v = max;
+		if (!approx_zero(max_delta, tolerance))
+			return false;
+	}
+	return true;
+}
+
+bool LLVolumeParams::setBeginAndEndS(const F32 b, const F32 e)
+{
+	bool valid = true;
+
+	// First, clamp to valid ranges.
+	F32 begin = b;
+	valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
+
+	F32 end = e;
+	if (end >= .0149f && end < MIN_CUT_DELTA) end = MIN_CUT_DELTA; // eliminate warning for common rounding error
+	valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
+
+	valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
+
+	// Now set them.
+	mProfileParams.setBegin(begin);
+	mProfileParams.setEnd(end);
+
+	return valid;
+}
+
+bool LLVolumeParams::setBeginAndEndT(const F32 b, const F32 e)
+{
+	bool valid = true;
+
+	// First, clamp to valid ranges.
+	F32 begin = b;
+	valid &= limit_range(begin, 0.f, 1.f - MIN_CUT_DELTA);
+
+	F32 end = e;
+	valid &= limit_range(end, MIN_CUT_DELTA, 1.f);
+
+	valid &= limit_range(begin, 0.f, end - MIN_CUT_DELTA, .01f);
+
+	// Now set them.
+	mPathParams.setBegin(begin);
+	mPathParams.setEnd(end);
+
+	return valid;
+}			
+
+bool LLVolumeParams::setHollow(const F32 h)
+{
+	// Validate the hollow based on path and profile.
+	U8 profile 	= mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
+	U8 hole_type 	= mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK;
+	
+	F32 max_hollow = HOLLOW_MAX;
+
+	// Only square holes have trouble.
+	if (LL_PCODE_HOLE_SQUARE == hole_type)
+	{
+		switch(profile)
+		{
+		case LL_PCODE_PROFILE_CIRCLE:
+		case LL_PCODE_PROFILE_CIRCLE_HALF:
+		case LL_PCODE_PROFILE_EQUALTRI:
+			max_hollow = HOLLOW_MAX_SQUARE;
+		}
+	}
+
+	F32 hollow = h;
+	bool valid = limit_range(hollow, HOLLOW_MIN, max_hollow);
+	mProfileParams.setHollow(hollow); 
+
+	return valid;
+}	
+
+bool LLVolumeParams::setTwistBegin(const F32 b)
+{
+	F32 twist_begin = b;
+	bool valid = limit_range(twist_begin, TWIST_MIN, TWIST_MAX);
+	mPathParams.setTwistBegin(twist_begin);
+	return valid;
+}
+
+bool LLVolumeParams::setTwistEnd(const F32 e)
+{	
+	F32 twist_end = e;
+	bool valid = limit_range(twist_end, TWIST_MIN, TWIST_MAX);
+	mPathParams.setTwistEnd(twist_end);
+	return valid;
+}
+
+bool LLVolumeParams::setRatio(const F32 x, const F32 y)
+{
+	F32 min_x = RATIO_MIN;
+	F32 max_x = RATIO_MAX;
+	F32 min_y = RATIO_MIN;
+	F32 max_y = RATIO_MAX;
+	// If this is a circular path (and not a sphere) then 'ratio' is actually hole size.
+	U8 path_type 	= mPathParams.getCurveType();
+	U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
+	if ( LL_PCODE_PATH_CIRCLE == path_type &&
+		 LL_PCODE_PROFILE_CIRCLE_HALF != profile_type)
+	{
+		// Holes are more restricted...
+		min_x = HOLE_X_MIN;
+		max_x = HOLE_X_MAX;
+		min_y = HOLE_Y_MIN;
+		max_y = HOLE_Y_MAX;
+	}
+
+	F32 ratio_x = x;
+	bool valid = limit_range(ratio_x, min_x, max_x);
+	F32 ratio_y = y;
+	valid &= limit_range(ratio_y, min_y, max_y);
+
+	mPathParams.setScale(ratio_x, ratio_y);
+
+	return valid;
+}
+
+bool LLVolumeParams::setShear(const F32 x, const F32 y)
+{
+	F32 shear_x = x;
+	bool valid = limit_range(shear_x, SHEAR_MIN, SHEAR_MAX);
+	F32 shear_y = y;
+	valid &= limit_range(shear_y, SHEAR_MIN, SHEAR_MAX);
+	mPathParams.setShear(shear_x, shear_y);
+	return valid;
+}
+
+bool LLVolumeParams::setTaperX(const F32 v)
+{
+	F32 taper = v;
+	bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
+	mPathParams.setTaperX(taper);
+	return valid;
+}
+
+bool LLVolumeParams::setTaperY(const F32 v)
+{
+	F32 taper = v;
+	bool valid = limit_range(taper, TAPER_MIN, TAPER_MAX);
+	mPathParams.setTaperY(taper);
+	return valid;
+}
+
+bool LLVolumeParams::setRevolutions(const F32 r)
+{
+	F32 revolutions = r;
+	bool valid = limit_range(revolutions, REV_MIN, REV_MAX);
+	mPathParams.setRevolutions(revolutions);
+	return valid;
+}
+
+bool LLVolumeParams::setRadiusOffset(const F32 offset)
+{
+	bool valid = true;
+
+	// If this is a sphere, just set it to 0 and get out.
+	U8 path_type 	= mPathParams.getCurveType();
+	U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
+	if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type ||
+		LL_PCODE_PATH_CIRCLE != path_type )
+	{
+		mPathParams.setRadiusOffset(0.f);
+		return true;
+	}
+
+	// Limit radius offset, based on taper and hole size y.
+	F32 radius_offset	= offset;
+	F32 taper_y    		= getTaperY();
+	F32 radius_mag		= fabs(radius_offset);
+	F32 hole_y_mag 		= fabs(getRatioY());
+	F32 taper_y_mag		= fabs(taper_y);
+	// Check to see if the taper effects us.
+	if ( (radius_offset > 0.f && taper_y < 0.f) ||
+			(radius_offset < 0.f && taper_y > 0.f) )
+	{
+		// The taper does not help increase the radius offset range.
+		taper_y_mag = 0.f;
+	}
+	F32 max_radius_mag = 1.f - hole_y_mag * (1.f - taper_y_mag) / (1.f - hole_y_mag);
+
+	// Enforce the maximum magnitude.
+	F32 delta = max_radius_mag - radius_mag;
+	if (delta < 0.f)
+	{
+		// Check radius offset sign.
+		if (radius_offset < 0.f)
+		{
+			radius_offset = -max_radius_mag;
+		}
+		else
+		{
+			radius_offset = max_radius_mag;
+		}
+		valid = approx_zero(delta, .1f);
+	}
+
+	mPathParams.setRadiusOffset(radius_offset);
+	return valid;
+}
+
+bool LLVolumeParams::setSkew(const F32 skew_value)
+{
+	bool valid = true;
+
+	// Check the skew value against the revolutions.
+	F32 skew		= llclamp(skew_value, SKEW_MIN, SKEW_MAX);
+	F32 skew_mag	= fabs(skew);
+	F32 revolutions = getRevolutions();
+	F32 scale_x		= getRatioX();
+	F32 min_skew_mag = 1.0f - 1.0f / (revolutions * scale_x + 1.0f);
+	// Discontinuity; A revolution of 1 allows skews below 0.5.
+	if ( fabs(revolutions - 1.0f) < 0.001)
+		min_skew_mag = 0.0f;
+
+	// Clip skew.
+	F32 delta = skew_mag - min_skew_mag;
+	if (delta < 0.f)
+	{
+		// Check skew sign.
+		if (skew < 0.0f)
+		{
+			skew = -min_skew_mag;
+		}
+		else 
+		{
+			skew = min_skew_mag;
+		}
+		valid = approx_zero(delta, .01f);
+	}
+
+	mPathParams.setSkew(skew);
+	return valid;
+}
+
+bool LLVolumeParams::setSculptID(const LLUUID sculpt_id, U8 sculpt_type)
+{
+	mSculptID = sculpt_id;
+	mSculptType = sculpt_type;
+	return true;
+}
+
+bool LLVolumeParams::setType(U8 profile, U8 path)
+{
+	bool result = true;
+	// First, check profile and path for validity.
+	U8 profile_type	= profile & LL_PCODE_PROFILE_MASK;
+	U8 hole_type 	= (profile & LL_PCODE_HOLE_MASK) >> 4;
+	U8 path_type	= path >> 4;
+
+	if (profile_type > LL_PCODE_PROFILE_MAX)
+	{
+		// Bad profile.  Make it square.
+		profile = LL_PCODE_PROFILE_SQUARE;
+		result = false;
+		llwarns << "LLVolumeParams::setType changing bad profile type (" << profile_type
+			 	<< ") to be LL_PCODE_PROFILE_SQUARE" << llendl;
+	}
+	else if (hole_type > LL_PCODE_HOLE_MAX)
+	{
+		// Bad hole.  Make it the same.
+		profile = profile_type;
+		result = false;
+		llwarns << "LLVolumeParams::setType changing bad hole type (" << hole_type
+			 	<< ") to be LL_PCODE_HOLE_SAME" << llendl;
+	}
+
+	if (path_type < LL_PCODE_PATH_MIN ||
+		path_type > LL_PCODE_PATH_MAX)
+	{
+		// Bad path.  Make it linear.
+		result = false;
+		llwarns << "LLVolumeParams::setType changing bad path (" << path
+			 	<< ") to be LL_PCODE_PATH_LINE" << llendl;
+		path = LL_PCODE_PATH_LINE;
+	}
+
+	mProfileParams.setCurveType(profile);
+	mPathParams.setCurveType(path);
+	return result;
+}
+
+// static 
+bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
+		U8 path_curve, F32 path_begin, F32 path_end,
+		F32 scx, F32 scy, F32 shx, F32 shy,
+		F32 twistend, F32 twistbegin, F32 radiusoffset,
+		F32 tx, F32 ty, F32 revolutions, F32 skew)
+{
+	LLVolumeParams test_params;
+	if (!test_params.setType		(prof_curve, path_curve))
+	{
+	    	return false;
 	}
 	if (!test_params.setBeginAndEndS	(prof_begin, prof_end))
 	{
@@ -2692,1768 +3480,2536 @@ bool LLVolumeParams::validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 h
 	return true;
 }
 
-S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
-{
-	LLMemType m1(LLMemType::MTYPE_VOLUME);
-	
-	S32 expected_num_triangle_indices = getNumTriangleIndices();
-	if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES)
-	{
-		// we don't allow LLVolumes with this many vertices
-		llwarns << "Couldn't allocate triangle indices" << llendl;
-		num_indices = 0;
-		return NULL;
-	}
+S32 *LLVolume::getTriangleIndices(U32 &num_indices) const
+{
+	LLMemType m1(LLMemType::MTYPE_VOLUME);
+	
+	S32 expected_num_triangle_indices = getNumTriangleIndices();
+	if (expected_num_triangle_indices > MAX_VOLUME_TRIANGLE_INDICES)
+	{
+		// we don't allow LLVolumes with this many vertices
+		llwarns << "Couldn't allocate triangle indices" << llendl;
+		num_indices = 0;
+		return NULL;
+	}
+
+	S32* index = new S32[expected_num_triangle_indices];
+	S32 count = 0;
+
+	// Let's do this totally diffently, as we don't care about faces...
+	// Counter-clockwise triangles are forward facing...
+
+	BOOL open = getProfile().isOpen();
+	BOOL hollow = (mParams.getProfileParams().getHollow() > 0);
+	BOOL path_open = getPath().isOpen();
+	S32 size_s, size_s_out, size_t;
+	S32 s, t, i;
+	size_s = getProfile().getTotal();
+	size_s_out = getProfile().getTotalOut();
+	size_t = getPath().mPath.size();
+
+	// NOTE -- if the construction of the triangles below ever changes
+	// then getNumTriangleIndices() method may also have to be updated.
+
+	if (open)		/* Flawfinder: ignore */
+	{
+		if (hollow)
+		{
+			// Open hollow -- much like the closed solid, except we 
+			// we need to stitch up the gap between s=0 and s=size_s-1
+
+			for (t = 0; t < size_t - 1; t++)
+			{
+				// The outer face, first cut, and inner face
+				for (s = 0; s < size_s - 1; s++)
+				{
+					i  = s + t*size_s;
+					index[count++]  = i;				// x,y
+					index[count++]  = i + 1;			// x+1,y
+					index[count++]  = i + size_s;		// x,y+1
+	
+					index[count++]  = i + size_s;		// x,y+1
+					index[count++]  = i + 1;			// x+1,y
+					index[count++]  = i + size_s + 1;	// x+1,y+1
+				}
+
+				// The other cut face
+				index[count++]  = s + t*size_s;		// x,y
+				index[count++]  = 0 + t*size_s;		// x+1,y
+				index[count++]  = s + (t+1)*size_s;	// x,y+1
+	
+				index[count++]  = s + (t+1)*size_s;	// x,y+1
+				index[count++]  = 0 + t*size_s;		// x+1,y
+				index[count++]  = 0 + (t+1)*size_s;	// x+1,y+1
+			}
+
+			// Do the top and bottom caps, if necessary
+			if (path_open)
+			{
+				// Top cap
+				S32 pt1 = 0;
+				S32 pt2 = size_s-1;
+				S32 i   = (size_t - 1)*size_s;
+
+				while (pt2 - pt1 > 1)
+				{
+					// Use the profile points instead of the mesh, since you want
+					// the un-transformed profile distances.
+					LLVector3 p1 = getProfile().mProfile[pt1];
+					LLVector3 p2 = getProfile().mProfile[pt2];
+					LLVector3 pa = getProfile().mProfile[pt1+1];
+					LLVector3 pb = getProfile().mProfile[pt2-1];
+
+					p1.mV[VZ] = 0.f;
+					p2.mV[VZ] = 0.f;
+					pa.mV[VZ] = 0.f;
+					pb.mV[VZ] = 0.f;
+
+					// Use area of triangle to determine backfacing
+					F32 area_1a2, area_1ba, area_21b, area_2ab;
+					area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+								(pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+								(p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
 
-	S32* index = new S32[expected_num_triangle_indices];
-	S32 count = 0;
+					area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+								(pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+								(pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
 
-	// Let's do this totally diffently, as we don't care about faces...
-	// Counter-clockwise triangles are forward facing...
+					area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+								(p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+								(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
 
-	BOOL open = getProfile().isOpen();
-	BOOL hollow = (mParams.getProfileParams().getHollow() > 0);
-	BOOL path_open = getPath().isOpen();
-	S32 size_s, size_s_out, size_t;
-	S32 s, t, i;
-	size_s = getProfile().getTotal();
-	size_s_out = getProfile().getTotalOut();
-	size_t = getPath().mPath.size();
+					area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+								(pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+								(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
 
-	// NOTE -- if the construction of the triangles below ever changes
-	// then getNumTriangleIndices() method may also have to be updated.
+					BOOL use_tri1a2 = TRUE;
+					BOOL tri_1a2 = TRUE;
+					BOOL tri_21b = TRUE;
 
-	if (open)		/* Flawfinder: ignore */
-	{
-		if (hollow)
+					if (area_1a2 < 0)
+					{
+						tri_1a2 = FALSE;
+					}
+					if (area_2ab < 0)
+					{
+						// Can't use, because it contains point b
+						tri_1a2 = FALSE;
+					}
+					if (area_21b < 0)
+					{
+						tri_21b = FALSE;
+					}
+					if (area_1ba < 0)
+					{
+						// Can't use, because it contains point b
+						tri_21b = FALSE;
+					}
+
+					if (!tri_1a2)
+					{
+						use_tri1a2 = FALSE;
+					}
+					else if (!tri_21b)
+					{
+						use_tri1a2 = TRUE;
+					}
+					else
+					{
+						LLVector3 d1 = p1 - pa;
+						LLVector3 d2 = p2 - pb;
+
+						if (d1.magVecSquared() < d2.magVecSquared())
+						{
+							use_tri1a2 = TRUE;
+						}
+						else
+						{
+							use_tri1a2 = FALSE;
+						}
+					}
+
+					if (use_tri1a2)
+					{
+						index[count++] = pt1 + i;
+						index[count++] = pt1 + 1 + i;
+						index[count++] = pt2 + i;
+						pt1++;
+					}
+					else
+					{
+						index[count++] = pt1 + i;
+						index[count++] = pt2 - 1 + i;
+						index[count++] = pt2 + i;
+						pt2--;
+					}
+				}
+
+				// Bottom cap
+				pt1          = 0;
+				pt2          = size_s-1;
+				while (pt2 - pt1 > 1)
+				{
+					// Use the profile points instead of the mesh, since you want
+					// the un-transformed profile distances.
+					LLVector3 p1 = getProfile().mProfile[pt1];
+					LLVector3 p2 = getProfile().mProfile[pt2];
+					LLVector3 pa = getProfile().mProfile[pt1+1];
+					LLVector3 pb = getProfile().mProfile[pt2-1];
+
+					p1.mV[VZ] = 0.f;
+					p2.mV[VZ] = 0.f;
+					pa.mV[VZ] = 0.f;
+					pb.mV[VZ] = 0.f;
+
+					// Use area of triangle to determine backfacing
+					F32 area_1a2, area_1ba, area_21b, area_2ab;
+					area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+								(pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+								(p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+
+					area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+								(pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+								(pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+
+					area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+								(p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+								(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+					area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+								(pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+								(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+					BOOL use_tri1a2 = TRUE;
+					BOOL tri_1a2 = TRUE;
+					BOOL tri_21b = TRUE;
+
+					if (area_1a2 < 0)
+					{
+						tri_1a2 = FALSE;
+					}
+					if (area_2ab < 0)
+					{
+						// Can't use, because it contains point b
+						tri_1a2 = FALSE;
+					}
+					if (area_21b < 0)
+					{
+						tri_21b = FALSE;
+					}
+					if (area_1ba < 0)
+					{
+						// Can't use, because it contains point b
+						tri_21b = FALSE;
+					}
+
+					if (!tri_1a2)
+					{
+						use_tri1a2 = FALSE;
+					}
+					else if (!tri_21b)
+					{
+						use_tri1a2 = TRUE;
+					}
+					else
+					{
+						LLVector3 d1 = p1 - pa;
+						LLVector3 d2 = p2 - pb;
+
+						if (d1.magVecSquared() < d2.magVecSquared())
+						{
+							use_tri1a2 = TRUE;
+						}
+						else
+						{
+							use_tri1a2 = FALSE;
+						}
+					}
+
+					if (use_tri1a2)
+					{
+						index[count++] = pt1;
+						index[count++] = pt2;
+						index[count++] = pt1 + 1;
+						pt1++;
+					}
+					else
+					{
+						index[count++] = pt1;
+						index[count++] = pt2;
+						index[count++] = pt2 - 1;
+						pt2--;
+					}
+				}
+			}
+		}
+		else
 		{
-			// Open hollow -- much like the closed solid, except we 
-			// we need to stitch up the gap between s=0 and s=size_s-1
+			// Open solid
 
 			for (t = 0; t < size_t - 1; t++)
 			{
-				// The outer face, first cut, and inner face
+				// Outer face + 1 cut face
 				for (s = 0; s < size_s - 1; s++)
 				{
 					i  = s + t*size_s;
+
 					index[count++]  = i;				// x,y
 					index[count++]  = i + 1;			// x+1,y
 					index[count++]  = i + size_s;		// x,y+1
-	
+
 					index[count++]  = i + size_s;		// x,y+1
 					index[count++]  = i + 1;			// x+1,y
 					index[count++]  = i + size_s + 1;	// x+1,y+1
 				}
 
-				// The other cut face
-				index[count++]  = s + t*size_s;		// x,y
-				index[count++]  = 0 + t*size_s;		// x+1,y
-				index[count++]  = s + (t+1)*size_s;	// x,y+1
-	
-				index[count++]  = s + (t+1)*size_s;	// x,y+1
-				index[count++]  = 0 + t*size_s;		// x+1,y
-				index[count++]  = 0 + (t+1)*size_s;	// x+1,y+1
+				// The other cut face
+				index[count++] = (size_s - 1) + (t*size_s);		// x,y
+				index[count++] = 0 + t*size_s;					// x+1,y
+				index[count++] = (size_s - 1) + (t+1)*size_s;	// x,y+1
+
+				index[count++] = (size_s - 1) + (t+1)*size_s;	// x,y+1
+				index[count++] = 0 + (t*size_s);				// x+1,y
+				index[count++] = 0 + (t+1)*size_s;				// x+1,y+1
+			}
+
+			// Do the top and bottom caps, if necessary
+			if (path_open)
+			{
+				for (s = 0; s < size_s - 2; s++)
+				{
+					index[count++] = s+1;
+					index[count++] = s;
+					index[count++] = size_s - 1;
+				}
+
+				// We've got a top cap
+				S32 offset = (size_t - 1)*size_s;
+				for (s = 0; s < size_s - 2; s++)
+				{
+					// Inverted ordering from bottom cap.
+					index[count++] = offset + size_s - 1;
+					index[count++] = offset + s;
+					index[count++] = offset + s + 1;
+				}
+			}
+		}
+	}
+	else if (hollow)
+	{
+		// Closed hollow
+		// Outer face
+		
+		for (t = 0; t < size_t - 1; t++)
+		{
+			for (s = 0; s < size_s_out - 1; s++)
+			{
+				i  = s + t*size_s;
+
+				index[count++]  = i;				// x,y
+				index[count++]  = i + 1;			// x+1,y
+				index[count++]  = i + size_s;		// x,y+1
+
+				index[count++]  = i + size_s;		// x,y+1
+				index[count++]  = i + 1;			// x+1,y
+				index[count++]  = i + 1 + size_s;	// x+1,y+1
 			}
+		}
 
-			// Do the top and bottom caps, if necessary
-			if (path_open)
+		// Inner face
+		// Invert facing from outer face
+		for (t = 0; t < size_t - 1; t++)
+		{
+			for (s = size_s_out; s < size_s - 1; s++)
 			{
-				// Top cap
-				S32 pt1 = 0;
-				S32 pt2 = size_s-1;
-				S32 i   = (size_t - 1)*size_s;
+				i  = s + t*size_s;
 
-				while (pt2 - pt1 > 1)
-				{
-					// Use the profile points instead of the mesh, since you want
-					// the un-transformed profile distances.
-					LLVector3 p1 = getProfile().mProfile[pt1];
-					LLVector3 p2 = getProfile().mProfile[pt2];
-					LLVector3 pa = getProfile().mProfile[pt1+1];
-					LLVector3 pb = getProfile().mProfile[pt2-1];
+				index[count++]  = i;				// x,y
+				index[count++]  = i + 1;			// x+1,y
+				index[count++]  = i + size_s;		// x,y+1
 
-					p1.mV[VZ] = 0.f;
-					p2.mV[VZ] = 0.f;
-					pa.mV[VZ] = 0.f;
-					pb.mV[VZ] = 0.f;
+				index[count++]  = i + size_s;		// x,y+1
+				index[count++]  = i + 1;			// x+1,y
+				index[count++]  = i + 1 + size_s;	// x+1,y+1
+			}
+		}
 
-					// Use area of triangle to determine backfacing
-					F32 area_1a2, area_1ba, area_21b, area_2ab;
-					area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
-								(pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
-								(p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+		// Do the top and bottom caps, if necessary
+		if (path_open)
+		{
+			// Top cap
+			S32 pt1 = 0;
+			S32 pt2 = size_s-1;
+			S32 i   = (size_t - 1)*size_s;
 
-					area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
-								(pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
-								(pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+			while (pt2 - pt1 > 1)
+			{
+				// Use the profile points instead of the mesh, since you want
+				// the un-transformed profile distances.
+				LLVector3 p1 = getProfile().mProfile[pt1];
+				LLVector3 p2 = getProfile().mProfile[pt2];
+				LLVector3 pa = getProfile().mProfile[pt1+1];
+				LLVector3 pb = getProfile().mProfile[pt2-1];
 
-					area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
-								(p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
-								(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+				p1.mV[VZ] = 0.f;
+				p2.mV[VZ] = 0.f;
+				pa.mV[VZ] = 0.f;
+				pb.mV[VZ] = 0.f;
 
-					area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
-								(pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
-								(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+				// Use area of triangle to determine backfacing
+				F32 area_1a2, area_1ba, area_21b, area_2ab;
+				area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+							(pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+							(p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
 
-					BOOL use_tri1a2 = TRUE;
-					BOOL tri_1a2 = TRUE;
-					BOOL tri_21b = TRUE;
+				area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+							(pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+							(pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
 
-					if (area_1a2 < 0)
-					{
-						tri_1a2 = FALSE;
-					}
-					if (area_2ab < 0)
-					{
-						// Can't use, because it contains point b
-						tri_1a2 = FALSE;
-					}
-					if (area_21b < 0)
-					{
-						tri_21b = FALSE;
-					}
-					if (area_1ba < 0)
-					{
-						// Can't use, because it contains point b
-						tri_21b = FALSE;
-					}
+				area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+							(p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+							(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
 
-					if (!tri_1a2)
-					{
-						use_tri1a2 = FALSE;
-					}
-					else if (!tri_21b)
-					{
-						use_tri1a2 = TRUE;
-					}
-					else
-					{
-						LLVector3 d1 = p1 - pa;
-						LLVector3 d2 = p2 - pb;
+				area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+							(pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+							(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
 
-						if (d1.magVecSquared() < d2.magVecSquared())
-						{
-							use_tri1a2 = TRUE;
-						}
-						else
-						{
-							use_tri1a2 = FALSE;
-						}
-					}
+				BOOL use_tri1a2 = TRUE;
+				BOOL tri_1a2 = TRUE;
+				BOOL tri_21b = TRUE;
 
-					if (use_tri1a2)
+				if (area_1a2 < 0)
+				{
+					tri_1a2 = FALSE;
+				}
+				if (area_2ab < 0)
+				{
+					// Can't use, because it contains point b
+					tri_1a2 = FALSE;
+				}
+				if (area_21b < 0)
+				{
+					tri_21b = FALSE;
+				}
+				if (area_1ba < 0)
+				{
+					// Can't use, because it contains point b
+					tri_21b = FALSE;
+				}
+
+				if (!tri_1a2)
+				{
+					use_tri1a2 = FALSE;
+				}
+				else if (!tri_21b)
+				{
+					use_tri1a2 = TRUE;
+				}
+				else
+				{
+					LLVector3 d1 = p1 - pa;
+					LLVector3 d2 = p2 - pb;
+
+					if (d1.magVecSquared() < d2.magVecSquared())
 					{
-						index[count++] = pt1 + i;
-						index[count++] = pt1 + 1 + i;
-						index[count++] = pt2 + i;
-						pt1++;
+						use_tri1a2 = TRUE;
 					}
 					else
 					{
-						index[count++] = pt1 + i;
-						index[count++] = pt2 - 1 + i;
-						index[count++] = pt2 + i;
-						pt2--;
+						use_tri1a2 = FALSE;
 					}
 				}
 
-				// Bottom cap
-				pt1          = 0;
-				pt2          = size_s-1;
-				while (pt2 - pt1 > 1)
+				if (use_tri1a2)
 				{
-					// Use the profile points instead of the mesh, since you want
-					// the un-transformed profile distances.
-					LLVector3 p1 = getProfile().mProfile[pt1];
-					LLVector3 p2 = getProfile().mProfile[pt2];
-					LLVector3 pa = getProfile().mProfile[pt1+1];
-					LLVector3 pb = getProfile().mProfile[pt2-1];
+					index[count++] = pt1 + i;
+					index[count++] = pt1 + 1 + i;
+					index[count++] = pt2 + i;
+					pt1++;
+				}
+				else
+				{
+					index[count++] = pt1 + i;
+					index[count++] = pt2 - 1 + i;
+					index[count++] = pt2 + i;
+					pt2--;
+				}
+			}
 
-					p1.mV[VZ] = 0.f;
-					p2.mV[VZ] = 0.f;
-					pa.mV[VZ] = 0.f;
-					pb.mV[VZ] = 0.f;
+			// Bottom cap
+			pt1          = 0;
+			pt2          = size_s-1;
+			while (pt2 - pt1 > 1)
+			{
+				// Use the profile points instead of the mesh, since you want
+				// the un-transformed profile distances.
+				LLVector3 p1 = getProfile().mProfile[pt1];
+				LLVector3 p2 = getProfile().mProfile[pt2];
+				LLVector3 pa = getProfile().mProfile[pt1+1];
+				LLVector3 pb = getProfile().mProfile[pt2-1];
 
-					// Use area of triangle to determine backfacing
-					F32 area_1a2, area_1ba, area_21b, area_2ab;
-					area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
-								(pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
-								(p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+				p1.mV[VZ] = 0.f;
+				p2.mV[VZ] = 0.f;
+				pa.mV[VZ] = 0.f;
+				pb.mV[VZ] = 0.f;
 
-					area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
-								(pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
-								(pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+				// Use area of triangle to determine backfacing
+				F32 area_1a2, area_1ba, area_21b, area_2ab;
+				area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
+							(pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
+							(p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
 
-					area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
-								(p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
-								(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+				area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+							(pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
+							(pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
 
-					area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
-								(pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
-								(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+				area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
+							(p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
+							(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+
+				area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
+							(pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
+							(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
 
-					BOOL use_tri1a2 = TRUE;
-					BOOL tri_1a2 = TRUE;
-					BOOL tri_21b = TRUE;
+				BOOL use_tri1a2 = TRUE;
+				BOOL tri_1a2 = TRUE;
+				BOOL tri_21b = TRUE;
 
-					if (area_1a2 < 0)
-					{
-						tri_1a2 = FALSE;
-					}
-					if (area_2ab < 0)
-					{
-						// Can't use, because it contains point b
-						tri_1a2 = FALSE;
-					}
-					if (area_21b < 0)
-					{
-						tri_21b = FALSE;
-					}
-					if (area_1ba < 0)
-					{
-						// Can't use, because it contains point b
-						tri_21b = FALSE;
-					}
+				if (area_1a2 < 0)
+				{
+					tri_1a2 = FALSE;
+				}
+				if (area_2ab < 0)
+				{
+					// Can't use, because it contains point b
+					tri_1a2 = FALSE;
+				}
+				if (area_21b < 0)
+				{
+					tri_21b = FALSE;
+				}
+				if (area_1ba < 0)
+				{
+					// Can't use, because it contains point b
+					tri_21b = FALSE;
+				}
 
-					if (!tri_1a2)
-					{
-						use_tri1a2 = FALSE;
-					}
-					else if (!tri_21b)
+				if (!tri_1a2)
+				{
+					use_tri1a2 = FALSE;
+				}
+				else if (!tri_21b)
+				{
+					use_tri1a2 = TRUE;
+				}
+				else
+				{
+					LLVector3 d1 = p1 - pa;
+					LLVector3 d2 = p2 - pb;
+
+					if (d1.magVecSquared() < d2.magVecSquared())
 					{
 						use_tri1a2 = TRUE;
 					}
 					else
 					{
-						LLVector3 d1 = p1 - pa;
-						LLVector3 d2 = p2 - pb;
-
-						if (d1.magVecSquared() < d2.magVecSquared())
-						{
-							use_tri1a2 = TRUE;
-						}
-						else
-						{
-							use_tri1a2 = FALSE;
-						}
+						use_tri1a2 = FALSE;
 					}
+				}
 
-					if (use_tri1a2)
-					{
-						index[count++] = pt1;
-						index[count++] = pt2;
-						index[count++] = pt1 + 1;
-						pt1++;
-					}
-					else
-					{
-						index[count++] = pt1;
-						index[count++] = pt2;
-						index[count++] = pt2 - 1;
-						pt2--;
-					}
+				if (use_tri1a2)
+				{
+					index[count++] = pt1;
+					index[count++] = pt2;
+					index[count++] = pt1 + 1;
+					pt1++;
+				}
+				else
+				{
+					index[count++] = pt1;
+					index[count++] = pt2;
+					index[count++] = pt2 - 1;
+					pt2--;
 				}
 			}
+		}		
+	}
+	else
+	{
+		// Closed solid.  Easy case.
+		for (t = 0; t < size_t - 1; t++)
+		{
+			for (s = 0; s < size_s - 1; s++)
+			{
+				// Should wrap properly, but for now...
+				i  = s + t*size_s;
+
+				index[count++]  = i;				// x,y
+				index[count++]  = i + 1;			// x+1,y
+				index[count++]  = i + size_s;		// x,y+1
+
+				index[count++]  = i + size_s;		// x,y+1
+				index[count++]  = i + 1;			// x+1,y
+				index[count++]  = i + size_s + 1;	// x+1,y+1
+			}
 		}
-		else
+
+		// Do the top and bottom caps, if necessary
+		if (path_open)
 		{
-			// Open solid
+			// bottom cap
+			for (s = 1; s < size_s - 2; s++)
+			{
+				index[count++] = s+1;
+				index[count++] = s;
+				index[count++] = 0;
+			}
 
-			for (t = 0; t < size_t - 1; t++)
+			// top cap
+			S32 offset = (size_t - 1)*size_s;
+			for (s = 1; s < size_s - 2; s++)
 			{
-				// Outer face + 1 cut face
-				for (s = 0; s < size_s - 1; s++)
-				{
-					i  = s + t*size_s;
+				// Inverted ordering from bottom cap.
+				index[count++] = offset;
+				index[count++] = offset + s;
+				index[count++] = offset + s + 1;
+			}
+		}
+	}
 
-					index[count++]  = i;				// x,y
-					index[count++]  = i + 1;			// x+1,y
-					index[count++]  = i + size_s;		// x,y+1
+#ifdef LL_DEBUG
+	// assert that we computed the correct number of indices
+	if (count != expected_num_triangle_indices )
+	{
+		llerrs << "bad index count prediciton:"
+			<< "  expected=" << expected_num_triangle_indices 
+			<< " actual=" << count << llendl;
+	}
+#endif
 
-					index[count++]  = i + size_s;		// x,y+1
-					index[count++]  = i + 1;			// x+1,y
-					index[count++]  = i + size_s + 1;	// x+1,y+1
-				}
+#if 0
+	// verify that each index does not point beyond the size of the mesh
+	S32 num_vertices = mMesh.size();
+	for (i = 0; i < count; i+=3)
+	{
+		llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl;
+		llassert(index[i] < num_vertices);
+		llassert(index[i+1] < num_vertices);
+		llassert(index[i+2] < num_vertices);
+	}
+#endif
 
-				// The other cut face
-				index[count++] = (size_s - 1) + (t*size_s);		// x,y
-				index[count++] = 0 + t*size_s;					// x+1,y
-				index[count++] = (size_s - 1) + (t+1)*size_s;	// x,y+1
+	num_indices = count;
+	return index;
+}
 
-				index[count++] = (size_s - 1) + (t+1)*size_s;	// x,y+1
-				index[count++] = 0 + (t*size_s);				// x+1,y
-				index[count++] = 0 + (t+1)*size_s;				// x+1,y+1
-			}
+S32 LLVolume::getNumTriangleIndices() const
+{
+	BOOL profile_open = getProfile().isOpen();
+	BOOL hollow = (mParams.getProfileParams().getHollow() > 0);
+	BOOL path_open = getPath().isOpen();
 
-			// Do the top and bottom caps, if necessary
-			if (path_open)
-			{
-				for (s = 0; s < size_s - 2; s++)
-				{
-					index[count++] = s+1;
-					index[count++] = s;
-					index[count++] = size_s - 1;
-				}
+	S32 size_s, size_s_out, size_t;
+	size_s = getProfile().getTotal();
+	size_s_out = getProfile().getTotalOut();
+	size_t = getPath().mPath.size();
 
-				// We've got a top cap
-				S32 offset = (size_t - 1)*size_s;
-				for (s = 0; s < size_s - 2; s++)
-				{
-					// Inverted ordering from bottom cap.
-					index[count++] = offset + size_s - 1;
-					index[count++] = offset + s;
-					index[count++] = offset + s + 1;
-				}
-			}
+	S32 count = 0;
+	if (profile_open)		/* Flawfinder: ignore */
+	{
+		if (hollow)
+		{
+			// Open hollow -- much like the closed solid, except we 
+			// we need to stitch up the gap between s=0 and s=size_s-1
+			count = (size_t - 1) * (((size_s -1) * 6) + 6);
+		}
+		else
+		{
+			count = (size_t - 1) * (((size_s -1) * 6) + 6); 
 		}
 	}
 	else if (hollow)
 	{
 		// Closed hollow
 		// Outer face
-		
-		for (t = 0; t < size_t - 1; t++)
+		count = (size_t - 1) * (size_s_out - 1) * 6;
+
+		// Inner face
+		count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6;
+	}
+	else
+	{
+		// Closed solid.  Easy case.
+		count = (size_t - 1) * (size_s - 1) * 6;
+	}
+
+	if (path_open)
+	{
+		S32 cap_triangle_count = size_s - 3;
+		if ( profile_open
+			|| hollow )
 		{
-			for (s = 0; s < size_s_out - 1; s++)
-			{
-				i  = s + t*size_s;
+			cap_triangle_count = size_s - 2;
+		}
+		if ( cap_triangle_count > 0 )
+		{
+			// top and bottom caps
+			count += cap_triangle_count * 2 * 3;
+		}
+	}
+	return count;
+}
 
-				index[count++]  = i;				// x,y
-				index[count++]  = i + 1;			// x+1,y
-				index[count++]  = i + size_s;		// x,y+1
 
-				index[count++]  = i + size_s;		// x,y+1
-				index[count++]  = i + 1;			// x+1,y
-				index[count++]  = i + 1 + size_s;	// x+1,y+1
-			}
-		}
+S32 LLVolume::getNumTriangles() const
+{
+	U32 triangle_count = 0;
 
-		// Inner face
-		// Invert facing from outer face
-		for (t = 0; t < size_t - 1; t++)
-		{
-			for (s = size_s_out; s < size_s - 1; s++)
-			{
-				i  = s + t*size_s;
+	for (S32 i = 0; i < getNumVolumeFaces(); ++i)
+	{
+		triangle_count += getVolumeFace(i).mNumIndices/3;
+	}
 
-				index[count++]  = i;				// x,y
-				index[count++]  = i + 1;			// x+1,y
-				index[count++]  = i + size_s;		// x,y+1
+	return triangle_count;
+}
 
-				index[count++]  = i + size_s;		// x,y+1
-				index[count++]  = i + 1;			// x+1,y
-				index[count++]  = i + 1 + size_s;	// x+1,y+1
-			}
-		}
 
-		// Do the top and bottom caps, if necessary
-		if (path_open)
-		{
-			// Top cap
-			S32 pt1 = 0;
-			S32 pt2 = size_s-1;
-			S32 i   = (size_t - 1)*size_s;
+//-----------------------------------------------------------------------------
+// generateSilhouetteVertices()
+//-----------------------------------------------------------------------------
+void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
+										  std::vector<LLVector3> &normals,
+										  std::vector<S32> &segments,
+										  const LLVector3& obj_cam_vec_in,
+										  const LLMatrix4& mat_in,
+										  const LLMatrix3& norm_mat_in,
+										  S32 face_mask)
+{
+	LLMemType m1(LLMemType::MTYPE_VOLUME);
 
-			while (pt2 - pt1 > 1)
-			{
-				// Use the profile points instead of the mesh, since you want
-				// the un-transformed profile distances.
-				LLVector3 p1 = getProfile().mProfile[pt1];
-				LLVector3 p2 = getProfile().mProfile[pt2];
-				LLVector3 pa = getProfile().mProfile[pt1+1];
-				LLVector3 pb = getProfile().mProfile[pt2-1];
+	LLMatrix4a mat;
+	mat.loadu(mat_in);
 
-				p1.mV[VZ] = 0.f;
-				p2.mV[VZ] = 0.f;
-				pa.mV[VZ] = 0.f;
-				pb.mV[VZ] = 0.f;
+	LLMatrix4a norm_mat;
+	norm_mat.loadu(norm_mat_in);
+		
+	LLVector4a obj_cam_vec;
+	obj_cam_vec.load3(obj_cam_vec_in.mV);
 
-				// Use area of triangle to determine backfacing
-				F32 area_1a2, area_1ba, area_21b, area_2ab;
-				area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
-							(pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
-							(p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+	vertices.clear();
+	normals.clear();
+	segments.clear();
 
-				area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
-							(pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
-							(pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+	if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+	{
+		return;
+	}
+	
+	S32 cur_index = 0;
+	//for each face
+	for (face_list_t::iterator iter = mVolumeFaces.begin();
+		 iter != mVolumeFaces.end(); ++iter)
+	{
+		LLVolumeFace& face = *iter;
+	
+		if (!(face_mask & (0x1 << cur_index++)) ||
+		     face.mNumIndices == 0 || face.mEdge.empty())
+		{
+			continue;
+		}
 
-				area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
-							(p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
-							(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+		if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
+	
+		}
+		else {
 
-				area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
-							(pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
-							(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+			//==============================================
+			//DEBUG draw edge map instead of silhouette edge
+			//==============================================
 
-				BOOL use_tri1a2 = TRUE;
-				BOOL tri_1a2 = TRUE;
-				BOOL tri_21b = TRUE;
+#if DEBUG_SILHOUETTE_EDGE_MAP
 
-				if (area_1a2 < 0)
-				{
-					tri_1a2 = FALSE;
-				}
-				if (area_2ab < 0)
-				{
-					// Can't use, because it contains point b
-					tri_1a2 = FALSE;
-				}
-				if (area_21b < 0)
-				{
-					tri_21b = FALSE;
-				}
-				if (area_1ba < 0)
-				{
-					// Can't use, because it contains point b
-					tri_21b = FALSE;
-				}
+			//for each triangle
+			U32 count = face.mNumIndices;
+			for (U32 j = 0; j < count/3; j++) {
+				//get vertices
+				S32 v1 = face.mIndices[j*3+0];
+				S32 v2 = face.mIndices[j*3+1];
+				S32 v3 = face.mIndices[j*3+2];
 
-				if (!tri_1a2)
-				{
-					use_tri1a2 = FALSE;
-				}
-				else if (!tri_21b)
-				{
-					use_tri1a2 = TRUE;
-				}
-				else
-				{
-					LLVector3 d1 = p1 - pa;
-					LLVector3 d2 = p2 - pb;
+				//get current face center
+				LLVector3 cCenter = (face.mVertices[v1].getPosition() + 
+									face.mVertices[v2].getPosition() + 
+									face.mVertices[v3].getPosition()) / 3.0f;
 
-					if (d1.magVecSquared() < d2.magVecSquared())
-					{
-						use_tri1a2 = TRUE;
+				//for each edge
+				for (S32 k = 0; k < 3; k++) {
+                    S32 nIndex = face.mEdge[j*3+k];
+					if (nIndex <= -1) {
+						continue;
 					}
-					else
-					{
-						use_tri1a2 = FALSE;
+
+					if (nIndex >= (S32) count/3) {
+						continue;
 					}
-				}
+					//get neighbor vertices
+					v1 = face.mIndices[nIndex*3+0];
+					v2 = face.mIndices[nIndex*3+1];
+					v3 = face.mIndices[nIndex*3+2];
 
-				if (use_tri1a2)
-				{
-					index[count++] = pt1 + i;
-					index[count++] = pt1 + 1 + i;
-					index[count++] = pt2 + i;
-					pt1++;
-				}
-				else
-				{
-					index[count++] = pt1 + i;
-					index[count++] = pt2 - 1 + i;
-					index[count++] = pt2 + i;
-					pt2--;
+					//get neighbor face center
+					LLVector3 nCenter = (face.mVertices[v1].getPosition() + 
+									face.mVertices[v2].getPosition() + 
+									face.mVertices[v3].getPosition()) / 3.0f;
+
+					//draw line
+					vertices.push_back(cCenter);
+					vertices.push_back(nCenter);
+					normals.push_back(LLVector3(1,1,1));
+					normals.push_back(LLVector3(1,1,1));
+					segments.push_back(vertices.size());
 				}
 			}
+		
+			continue;
 
-			// Bottom cap
-			pt1          = 0;
-			pt2          = size_s-1;
-			while (pt2 - pt1 > 1)
-			{
-				// Use the profile points instead of the mesh, since you want
-				// the un-transformed profile distances.
-				LLVector3 p1 = getProfile().mProfile[pt1];
-				LLVector3 p2 = getProfile().mProfile[pt2];
-				LLVector3 pa = getProfile().mProfile[pt1+1];
-				LLVector3 pb = getProfile().mProfile[pt2-1];
-
-				p1.mV[VZ] = 0.f;
-				p2.mV[VZ] = 0.f;
-				pa.mV[VZ] = 0.f;
-				pb.mV[VZ] = 0.f;
+			//==============================================
+			//DEBUG
+			//==============================================
 
-				// Use area of triangle to determine backfacing
-				F32 area_1a2, area_1ba, area_21b, area_2ab;
-				area_1a2 =  (p1.mV[0]*pa.mV[1] - pa.mV[0]*p1.mV[1]) +
-							(pa.mV[0]*p2.mV[1] - p2.mV[0]*pa.mV[1]) +
-							(p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]);
+			//==============================================
+			//DEBUG draw normals instead of silhouette edge
+			//==============================================
+#elif DEBUG_SILHOUETTE_NORMALS
 
-				area_1ba =  (p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
-							(pb.mV[0]*pa.mV[1] - pa.mV[0]*pb.mV[1]) +
-							(pa.mV[0]*p1.mV[1] - p1.mV[0]*pa.mV[1]);
+			//for each vertex
+			for (U32 j = 0; j < face.mNumVertices; j++) {
+				vertices.push_back(face.mVertices[j].getPosition());
+				vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].getNormal()*0.1f);
+				normals.push_back(LLVector3(0,0,1));
+				normals.push_back(LLVector3(0,0,1));
+				segments.push_back(vertices.size());
+#if DEBUG_SILHOUETTE_BINORMALS
+				vertices.push_back(face.mVertices[j].getPosition());
+				vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f);
+				normals.push_back(LLVector3(0,0,1));
+				normals.push_back(LLVector3(0,0,1));
+				segments.push_back(vertices.size());
+#endif
+			}
+						
+			continue;
+#else
+			//==============================================
+			//DEBUG
+			//==============================================
 
-				area_21b =  (p2.mV[0]*p1.mV[1] - p1.mV[0]*p2.mV[1]) +
-							(p1.mV[0]*pb.mV[1] - pb.mV[0]*p1.mV[1]) +
-							(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+			static const U8 AWAY = 0x01,
+							TOWARDS = 0x02;
 
-				area_2ab =  (p2.mV[0]*pa.mV[1] - pa.mV[0]*p2.mV[1]) +
-							(pa.mV[0]*pb.mV[1] - pb.mV[0]*pa.mV[1]) +
-							(pb.mV[0]*p2.mV[1] - p2.mV[0]*pb.mV[1]);
+			//for each triangle
+			std::vector<U8> fFacing;
+			vector_append(fFacing, face.mNumIndices/3);
 
-				BOOL use_tri1a2 = TRUE;
-				BOOL tri_1a2 = TRUE;
-				BOOL tri_21b = TRUE;
+			LLVector4a* v = (LLVector4a*) face.mPositions;
+			LLVector4a* n = (LLVector4a*) face.mNormals;
 
-				if (area_1a2 < 0)
-				{
-					tri_1a2 = FALSE;
-				}
-				if (area_2ab < 0)
-				{
-					// Can't use, because it contains point b
-					tri_1a2 = FALSE;
-				}
-				if (area_21b < 0)
-				{
-					tri_21b = FALSE;
-				}
-				if (area_1ba < 0)
-				{
-					// Can't use, because it contains point b
-					tri_21b = FALSE;
-				}
+			for (U32 j = 0; j < face.mNumIndices/3; j++) 
+			{
+				//approximate normal
+				S32 v1 = face.mIndices[j*3+0];
+				S32 v2 = face.mIndices[j*3+1];
+				S32 v3 = face.mIndices[j*3+2];
 
-				if (!tri_1a2)
-				{
-					use_tri1a2 = FALSE;
-				}
-				else if (!tri_21b)
+				LLVector4a c1,c2;
+				c1.setSub(v[v1], v[v2]);
+				c2.setSub(v[v2], v[v3]);
+
+				LLVector4a norm;
+
+				norm.setCross3(c1, c2);
+
+				if (norm.dot3(norm) < 0.00000001f) 
 				{
-					use_tri1a2 = TRUE;
+					fFacing[j] = AWAY | TOWARDS;
 				}
-				else
+				else 
 				{
-					LLVector3 d1 = p1 - pa;
-					LLVector3 d2 = p2 - pb;
-
-					if (d1.magVecSquared() < d2.magVecSquared())
+					//get view vector
+					LLVector4a view;
+					view.setSub(obj_cam_vec, v[v1]);
+					bool away = view.dot3(norm) > 0.0f; 
+					if (away) 
 					{
-						use_tri1a2 = TRUE;
+						fFacing[j] = AWAY;
 					}
-					else
+					else 
 					{
-						use_tri1a2 = FALSE;
+						fFacing[j] = TOWARDS;
 					}
 				}
-
-				if (use_tri1a2)
-				{
-					index[count++] = pt1;
-					index[count++] = pt2;
-					index[count++] = pt1 + 1;
-					pt1++;
-				}
-				else
-				{
-					index[count++] = pt1;
-					index[count++] = pt2;
-					index[count++] = pt2 - 1;
-					pt2--;
+			}
+			
+			//for each triangle
+			for (U32 j = 0; j < face.mNumIndices/3; j++) 
+			{
+				if (fFacing[j] == (AWAY | TOWARDS)) 
+				{ //this is a degenerate triangle
+					//take neighbor facing (degenerate faces get facing of one of their neighbors)
+					// *FIX IF NEEDED:  this does not deal with neighboring degenerate faces
+					for (S32 k = 0; k < 3; k++) 
+					{
+						S32 index = face.mEdge[j*3+k];
+						if (index != -1) 
+						{
+							fFacing[j] = fFacing[index];
+							break;
+						}
+					}
+					continue; //skip degenerate face
 				}
+
+				//for each edge
+				for (S32 k = 0; k < 3; k++) {
+					S32 index = face.mEdge[j*3+k];
+					if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) {
+						//our neighbor is degenerate, make him face our direction
+						fFacing[face.mEdge[j*3+k]] = fFacing[j];
+						continue;
+					}
+
+					if (index == -1 ||		//edge has no neighbor, MUST be a silhouette edge
+						(fFacing[index] & fFacing[j]) == 0) { 	//we found a silhouette edge
+
+						S32 v1 = face.mIndices[j*3+k];
+						S32 v2 = face.mIndices[j*3+((k+1)%3)];
+						
+						LLVector4a t;
+						mat.affineTransform(v[v1], t);
+						vertices.push_back(LLVector3(t[0], t[1], t[2]));
+
+						norm_mat.rotate(n[v1], t);
+
+						t.normalize3fast();
+						normals.push_back(LLVector3(t[0], t[1], t[2]));
+
+						mat.affineTransform(v[v2], t);
+						vertices.push_back(LLVector3(t[0], t[1], t[2]));
+						
+						norm_mat.rotate(n[v2], t);
+						t.normalize3fast();
+						normals.push_back(LLVector3(t[0], t[1], t[2]));
+
+						segments.push_back(vertices.size());
+					}
+				}		
 			}
-		}		
+#endif
+		}
+	}
+}
+
+S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
+								   S32 face,
+								   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+{
+	LLVector4a starta, enda;
+	starta.load3(start.mV);
+	enda.load3(end.mV);
+
+	return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal);
+
+}
+
+
+S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
+								   S32 face,
+								   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+{
+	S32 hit_face = -1;
+	
+	S32 start_face;
+	S32 end_face;
+	
+	if (face == -1) // ALL_SIDES
+	{
+		start_face = 0;
+		end_face = getNumVolumeFaces() - 1;
 	}
 	else
 	{
-		// Closed solid.  Easy case.
-		for (t = 0; t < size_t - 1; t++)
-		{
-			for (s = 0; s < size_s - 1; s++)
-			{
-				// Should wrap properly, but for now...
-				i  = s + t*size_s;
+		start_face = face;
+		end_face = face;
+	}
 
-				index[count++]  = i;				// x,y
-				index[count++]  = i + 1;			// x+1,y
-				index[count++]  = i + size_s;		// x,y+1
+	LLVector4a dir;
+	dir.setSub(end, start);
 
-				index[count++]  = i + size_s;		// x,y+1
-				index[count++]  = i + 1;			// x+1,y
-				index[count++]  = i + size_s + 1;	// x+1,y+1
-			}
-		}
+	F32 closest_t = 2.f; // must be larger than 1
+	
+	end_face = llmin(end_face, getNumVolumeFaces()-1);
 
-		// Do the top and bottom caps, if necessary
-		if (path_open)
+	for (S32 i = start_face; i <= end_face; i++)
+	{
+		LLVolumeFace &face = mVolumeFaces[i];
+
+		LLVector4a box_center;
+		box_center.setAdd(face.mExtents[0], face.mExtents[1]);
+		box_center.mul(0.5f);
+
+		LLVector4a box_size;
+		box_size.setSub(face.mExtents[1], face.mExtents[0]);
+
+        if (LLLineSegmentBoxIntersect(start, end, box_center, box_size))
 		{
-			// bottom cap
-			for (s = 1; s < size_s - 2; s++)
+			if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them
 			{
-				index[count++] = s+1;
-				index[count++] = s;
-				index[count++] = 0;
+				genBinormals(i);
 			}
 
-			// top cap
-			S32 offset = (size_t - 1)*size_s;
-			for (s = 1; s < size_s - 2; s++)
+			if (!face.mOctree)
 			{
-				// Inverted ordering from bottom cap.
-				index[count++] = offset;
-				index[count++] = offset + s;
-				index[count++] = offset + s + 1;
+				face.createOctree();
 			}
-		}
-	}
+			
+			//LLVector4a* p = (LLVector4a*) face.mPositions;
 
-#ifdef LL_DEBUG
-	// assert that we computed the correct number of indices
-	if (count != expected_num_triangle_indices )
-	{
-		llerrs << "bad index count prediciton:"
-			<< "  expected=" << expected_num_triangle_indices 
-			<< " actual=" << count << llendl;
+			LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
+			intersect.traverse(face.mOctree);
+			if (intersect.mHitFace)
+			{
+				hit_face = i;
+			}
+		}		
 	}
-#endif
+	
+	
+	return hit_face;
+}
 
-#if 0
-	// verify that each index does not point beyond the size of the mesh
-	S32 num_vertices = mMesh.size();
-	for (i = 0; i < count; i+=3)
-	{
-		llinfos << index[i] << ":" << index[i+1] << ":" << index[i+2] << llendl;
-		llassert(index[i] < num_vertices);
-		llassert(index[i+1] < num_vertices);
-		llassert(index[i+2] < num_vertices);
-	}
-#endif
+class LLVertexIndexPair
+{
+public:
+	LLVertexIndexPair(const LLVector3 &vertex, const S32 index);
 
-	num_indices = count;
-	return index;
+	LLVector3 mVertex;
+	S32	mIndex;
+};
+
+LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index)
+{
+	mVertex = vertex;
+	mIndex = index;
 }
 
-S32 LLVolume::getNumTriangleIndices() const
+const F32 VERTEX_SLOP = 0.00001f;
+const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP;
+
+struct lessVertex
 {
-	BOOL profile_open = getProfile().isOpen();
-	BOOL hollow = (mParams.getProfileParams().getHollow() > 0);
-	BOOL path_open = getPath().isOpen();
+	bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b)
+	{
+		const F32 slop = VERTEX_SLOP;
 
-	S32 size_s, size_s_out, size_t;
-	size_s = getProfile().getTotal();
-	size_s_out = getProfile().getTotalOut();
-	size_t = getPath().mPath.size();
+		if (a->mVertex.mV[0] + slop < b->mVertex.mV[0])
+		{
+			return TRUE;
+		}
+		else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0])
+		{
+			return FALSE;
+		}
+		
+		if (a->mVertex.mV[1] + slop < b->mVertex.mV[1])
+		{
+			return TRUE;
+		}
+		else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1])
+		{
+			return FALSE;
+		}
+		
+		if (a->mVertex.mV[2] + slop < b->mVertex.mV[2])
+		{
+			return TRUE;
+		}
+		else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2])
+		{
+			return FALSE;
+		}
+		
+		return FALSE;
+	}
+};
 
-	S32 count = 0;
-	if (profile_open)		/* Flawfinder: ignore */
+struct lessTriangle
+{
+	bool operator()(const S32 *a, const S32 *b)
 	{
-		if (hollow)
+		if (*a < *b)
+		{
+			return TRUE;
+		}
+		else if (*a > *b)
+		{
+			return FALSE;
+		}
+
+		if (*(a+1) < *(b+1))
 		{
-			// Open hollow -- much like the closed solid, except we 
-			// we need to stitch up the gap between s=0 and s=size_s-1
-			count = (size_t - 1) * (((size_s -1) * 6) + 6);
+			return TRUE;
 		}
-		else
+		else if (*(a+1) > *(b+1))
 		{
-			count = (size_t - 1) * (((size_s -1) * 6) + 6); 
+			return FALSE;
 		}
-	}
-	else if (hollow)
-	{
-		// Closed hollow
-		// Outer face
-		count = (size_t - 1) * (size_s_out - 1) * 6;
-
-		// Inner face
-		count += (size_t - 1) * ((size_s - 1) - size_s_out) * 6;
-	}
-	else
-	{
-		// Closed solid.  Easy case.
-		count = (size_t - 1) * (size_s - 1) * 6;
-	}
 
-	if (path_open)
-	{
-		S32 cap_triangle_count = size_s - 3;
-		if ( profile_open
-			|| hollow )
+		if (*(a+2) < *(b+2))
 		{
-			cap_triangle_count = size_s - 2;
+			return TRUE;
 		}
-		if ( cap_triangle_count > 0 )
+		else if (*(a+2) > *(b+2))
 		{
-			// top and bottom caps
-			count += cap_triangle_count * 2 * 3;
+			return FALSE;
 		}
+
+		return FALSE;
 	}
-	return count;
+};
+
+BOOL equalTriangle(const S32 *a, const S32 *b)
+{
+	if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2)))
+	{
+		return TRUE;
+	}
+	return FALSE;
 }
 
-//-----------------------------------------------------------------------------
-// generateSilhouetteVertices()
-//-----------------------------------------------------------------------------
-void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
-										  std::vector<LLVector3> &normals,
-										  std::vector<S32> &segments,
-										  const LLVector3& obj_cam_vec,
-										  const LLMatrix4& mat,
-										  const LLMatrix3& norm_mat,
-										  S32 face_mask)
+BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,
+									const std::vector<Point>& input_vertices,
+									const S32 num_input_triangles,
+									S32 *input_triangles,
+									S32 &num_output_vertices,
+									LLVector3 **output_vertices,
+									S32 &num_output_triangles,
+									S32 **output_triangles)
 {
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
 	
-	vertices.clear();
-	normals.clear();
-	segments.clear();
-
-	S32 cur_index = 0;
-	//for each face
-	for (face_list_t::iterator iter = mVolumeFaces.begin();
-		 iter != mVolumeFaces.end(); ++iter)
+	/* Testing: avoid any cleanup
+	static BOOL skip_cleanup = TRUE;
+	if ( skip_cleanup )
 	{
-		const LLVolumeFace& face = *iter;
-	
-		if (!(face_mask & (0x1 << cur_index++)))
+		num_output_vertices = num_input_vertices;
+		num_output_triangles = num_input_triangles;
+
+		*output_vertices = new LLVector3[num_input_vertices];
+		for (S32 index = 0; index < num_input_vertices; index++)
 		{
-			continue;
-		}
-		if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
-	
+			(*output_vertices)[index] = input_vertices[index].mPos;
 		}
-		else {
-
-			//==============================================
-			//DEBUG draw edge map instead of silhouette edge
-			//==============================================
-
-#if DEBUG_SILHOUETTE_EDGE_MAP
-
-			//for each triangle
-			U32 count = face.mIndices.size();
-			for (U32 j = 0; j < count/3; j++) {
-				//get vertices
-				S32 v1 = face.mIndices[j*3+0];
-				S32 v2 = face.mIndices[j*3+1];
-				S32 v3 = face.mIndices[j*3+2];
-
-				//get current face center
-				LLVector3 cCenter = (face.mVertices[v1].mPosition + 
-									face.mVertices[v2].mPosition + 
-									face.mVertices[v3].mPosition) / 3.0f;
-
-				//for each edge
-				for (S32 k = 0; k < 3; k++) {
-                    S32 nIndex = face.mEdge[j*3+k];
-					if (nIndex <= -1) {
-						continue;
-					}
-
-					if (nIndex >= (S32) count/3) {
-						continue;
-					}
-					//get neighbor vertices
-					v1 = face.mIndices[nIndex*3+0];
-					v2 = face.mIndices[nIndex*3+1];
-					v3 = face.mIndices[nIndex*3+2];
-
-					//get neighbor face center
-					LLVector3 nCenter = (face.mVertices[v1].mPosition + 
-									face.mVertices[v2].mPosition + 
-									face.mVertices[v3].mPosition) / 3.0f;
 
-					//draw line
-					vertices.push_back(cCenter);
-					vertices.push_back(nCenter);
-					normals.push_back(LLVector3(1,1,1));
-					normals.push_back(LLVector3(1,1,1));
-					segments.push_back(vertices.size());
-				}
-			}
-		
-			continue;
+		*output_triangles = new S32[num_input_triangles*3];
+		memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32));		// Flawfinder: ignore
+		return TRUE;
+	}
+	*/
 
-			//==============================================
-			//DEBUG
-			//==============================================
+	// Here's how we do this:
+	// Create a structure which contains the original vertex index and the
+	// LLVector3 data.
+	// "Sort" the data by the vectors
+	// Create an array the size of the old vertex list, with a mapping of
+	// old indices to new indices.
+	// Go through triangles, shift so the lowest index is first
+	// Sort triangles by first index
+	// Remove duplicate triangles
+	// Allocate and pack new triangle data.
 
-			//==============================================
-			//DEBUG draw normals instead of silhouette edge
-			//==============================================
-#elif DEBUG_SILHOUETTE_NORMALS
+	//LLTimer cleanupTimer;
+	//llinfos << "In vertices: " << num_input_vertices << llendl;
+	//llinfos << "In triangles: " << num_input_triangles << llendl;
 
-			//for each vertex
-			for (U32 j = 0; j < face.mVertices.size(); j++) {
-				vertices.push_back(face.mVertices[j].mPosition);
-				vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*0.1f);
-				normals.push_back(LLVector3(0,0,1));
-				normals.push_back(LLVector3(0,0,1));
-				segments.push_back(vertices.size());
-#if DEBUG_SILHOUETTE_BINORMALS
-				vertices.push_back(face.mVertices[j].mPosition);
-				vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f);
-				normals.push_back(LLVector3(0,0,1));
-				normals.push_back(LLVector3(0,0,1));
-				segments.push_back(vertices.size());
-#endif
-			}
-						
-			continue;
-#else
-			//==============================================
-			//DEBUG
-			//==============================================
+	S32 i;
+	typedef std::multiset<LLVertexIndexPair*, lessVertex> vertex_set_t;
+	vertex_set_t vertex_list;
 
-			static const U8 AWAY = 0x01,
-							TOWARDS = 0x02;
+	LLVertexIndexPair *pairp = NULL;
+	for (i = 0; i < num_input_vertices; i++)
+	{
+		LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i);
+		vertex_list.insert(new_pairp);
+	}
 
-			//for each triangle
-			std::vector<U8> fFacing;
-			vector_append(fFacing, face.mIndices.size()/3);
-			for (U32 j = 0; j < face.mIndices.size()/3; j++) 
-			{
-				//approximate normal
-				S32 v1 = face.mIndices[j*3+0];
-				S32 v2 = face.mIndices[j*3+1];
-				S32 v3 = face.mIndices[j*3+2];
+	// Generate the vertex mapping and the list of vertices without
+	// duplicates.  This will crash if there are no vertices.
+	llassert(num_input_vertices > 0); // check for no vertices!
+	S32 *vertex_mapping = new S32[num_input_vertices];
+	LLVector3 *new_vertices = new LLVector3[num_input_vertices];
+	LLVertexIndexPair *prev_pairp = NULL;
 
-				LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) % 
-					(face.mVertices[v2].mPosition - face.mVertices[v3].mPosition);
-				
-				if (norm.magVecSquared() < 0.00000001f) 
-				{
-					fFacing[j] = AWAY | TOWARDS;
-				}
-				else 
-				{
-					//get view vector
-					LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition);
-					bool away = view * norm > 0.0f; 
-					if (away) 
-					{
-						fFacing[j] = AWAY;
-					}
-					else 
-					{
-						fFacing[j] = TOWARDS;
-					}
-				}
-			}
-			
-			//for each triangle
-			for (U32 j = 0; j < face.mIndices.size()/3; j++) 
-			{
-				if (fFacing[j] == (AWAY | TOWARDS)) 
-				{ //this is a degenerate triangle
-					//take neighbor facing (degenerate faces get facing of one of their neighbors)
-					// *FIX IF NEEDED:  this does not deal with neighboring degenerate faces
-					for (S32 k = 0; k < 3; k++) 
-					{
-						S32 index = face.mEdge[j*3+k];
-						if (index != -1) 
-						{
-							fFacing[j] = fFacing[index];
-							break;
-						}
-					}
-					continue; //skip degenerate face
-				}
+	S32 new_num_vertices;
 
-				//for each edge
-				for (S32 k = 0; k < 3; k++) {
-					S32 index = face.mEdge[j*3+k];
-					if (index != -1 && fFacing[index] == (AWAY | TOWARDS)) {
-						//our neighbor is degenerate, make him face our direction
-						fFacing[face.mEdge[j*3+k]] = fFacing[j];
-						continue;
-					}
+	new_num_vertices = 0;
+	for (vertex_set_t::iterator iter = vertex_list.begin(),
+			 end = vertex_list.end();
+		 iter != end; iter++)
+	{
+		pairp = *iter;
+		if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD))	
+		{
+			new_vertices[new_num_vertices] = pairp->mVertex;
+			//llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl;
+			new_num_vertices++;
+			// Update the previous
+			prev_pairp = pairp;
+		}
+		else
+		{
+			//llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl;
+		}
+		vertex_mapping[pairp->mIndex] = new_num_vertices - 1;
+	}
 
-					if (index == -1 ||		//edge has no neighbor, MUST be a silhouette edge
-						(fFacing[index] & fFacing[j]) == 0) { 	//we found a silhouette edge
+	// Iterate through triangles and remove degenerates, re-ordering vertices
+	// along the way.
+	S32 *new_triangles = new S32[num_input_triangles * 3];
+	S32 new_num_triangles = 0;
 
-						S32 v1 = face.mIndices[j*3+k];
-						S32 v2 = face.mIndices[j*3+((k+1)%3)];
-						
-						vertices.push_back(face.mVertices[v1].mPosition*mat);
-						LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat;
-						norm1.normVec();
-						normals.push_back(norm1);
+	for (i = 0; i < num_input_triangles; i++)
+	{
+		S32 v1 = i*3;
+		S32 v2 = v1 + 1;
+		S32 v3 = v1 + 2;
 
-						vertices.push_back(face.mVertices[v2].mPosition*mat);
-						LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat;
-						norm2.normVec();
-						normals.push_back(norm2);
+		//llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
+		input_triangles[v1] = vertex_mapping[input_triangles[v1]];
+		input_triangles[v2] = vertex_mapping[input_triangles[v2]];
+		input_triangles[v3] = vertex_mapping[input_triangles[v3]];
 
-						segments.push_back(vertices.size());
-					}
-				}		
+		if ((input_triangles[v1] == input_triangles[v2])
+			|| (input_triangles[v1] == input_triangles[v3])
+			|| (input_triangles[v2] == input_triangles[v3]))
+		{
+			//llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
+			// Degenerate triangle, skip
+			continue;
+		}
+
+		if (input_triangles[v1] < input_triangles[v2])
+		{
+			if (input_triangles[v1] < input_triangles[v3])
+			{
+				// (0 < 1) && (0 < 2)
+				new_triangles[new_num_triangles*3] = input_triangles[v1];
+				new_triangles[new_num_triangles*3+1] = input_triangles[v2];
+				new_triangles[new_num_triangles*3+2] = input_triangles[v3];
+			}
+			else
+			{
+				// (0 < 1) && (2 < 0)
+				new_triangles[new_num_triangles*3] = input_triangles[v3];
+				new_triangles[new_num_triangles*3+1] = input_triangles[v1];
+				new_triangles[new_num_triangles*3+2] = input_triangles[v2];
 			}
-#endif
 		}
+		else if (input_triangles[v2] < input_triangles[v3])
+		{
+			// (1 < 0) && (1 < 2)
+			new_triangles[new_num_triangles*3] = input_triangles[v2];
+			new_triangles[new_num_triangles*3+1] = input_triangles[v3];
+			new_triangles[new_num_triangles*3+2] = input_triangles[v1];
+		}
+		else
+		{
+			// (1 < 0) && (2 < 1)
+			new_triangles[new_num_triangles*3] = input_triangles[v3];
+			new_triangles[new_num_triangles*3+1] = input_triangles[v1];
+			new_triangles[new_num_triangles*3+2] = input_triangles[v2];
+		}
+		new_num_triangles++;
 	}
-}
 
-S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
-								   S32 face,
-								   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
-{
-	S32 hit_face = -1;
-	
-	S32 start_face;
-	S32 end_face;
-	
-	if (face == -1) // ALL_SIDES
-	{
-		start_face = 0;
-		end_face = getNumVolumeFaces() - 1;
-	}
-	else
+	if (new_num_triangles == 0)
 	{
-		start_face = face;
-		end_face = face;
+		llwarns << "Created volume object with 0 faces." << llendl;
+		delete[] new_triangles;
+		delete[] vertex_mapping;
+		delete[] new_vertices;
+		return FALSE;
 	}
 
-	LLVector3 dir = end - start;
+	typedef std::set<S32*, lessTriangle> triangle_set_t;
+	triangle_set_t triangle_list;
 
-	F32 closest_t = 2.f; // must be larger than 1
-	
-	for (S32 i = start_face; i <= end_face; i++)
+	for (i = 0; i < new_num_triangles; i++)
 	{
-		const LLVolumeFace &face = getVolumeFace((U32)i);
+		triangle_list.insert(&new_triangles[i*3]);
+	}
 
-		LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f;
-		LLVector3 box_size   = face.mExtents[1] - face.mExtents[0];
+	// Sort through the triangle list, and delete duplicates
 
-        if (LLLineSegmentBoxIntersect(start, end, box_center, box_size))
-		{
-			if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them
-			{
-				genBinormals(i);
-			}
-			
-			for (U32 tri = 0; tri < face.mIndices.size()/3; tri++) 
-			{
-				S32 index1 = face.mIndices[tri*3+0];
-				S32 index2 = face.mIndices[tri*3+1];
-				S32 index3 = face.mIndices[tri*3+2];
+	S32 *prevp = NULL;
+	S32 *curp = NULL;
 
-				F32 a, b, t;
-			
-				if (LLTriangleRayIntersect(face.mVertices[index1].mPosition,
-										   face.mVertices[index2].mPosition,
-										   face.mVertices[index3].mPosition,
-										   start, dir, &a, &b, &t, FALSE))
-				{
-					if ((t >= 0.f) &&      // if hit is after start
-						(t <= 1.f) &&      // and before end
-						(t < closest_t))   // and this hit is closer
+	S32 *sorted_tris = new S32[new_num_triangles*3];
+	S32 cur_tri = 0;
+	for (triangle_set_t::iterator iter = triangle_list.begin(),
+			 end = triangle_list.end();
+		 iter != end; iter++)
+	{
+		curp = *iter;
+		if (!prevp || !equalTriangle(prevp, curp))
 		{
-						closest_t = t;
-						hit_face = i;
-
-						if (intersection != NULL)
-						{
-							*intersection = start + dir * closest_t;
-						}
-			
-						if (tex_coord != NULL)
-			{
-							*tex_coord = ((1.f - a - b)  * face.mVertices[index1].mTexCoord +
-										  a              * face.mVertices[index2].mTexCoord +
-										  b              * face.mVertices[index3].mTexCoord);
-
-						}
+			//llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
+			sorted_tris[cur_tri*3] = *curp;
+			sorted_tris[cur_tri*3+1] = *(curp+1);
+			sorted_tris[cur_tri*3+2] = *(curp+2);
+			cur_tri++;
+			prevp = curp;
+		}
+		else
+		{
+			//llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
+		}
+	}
 
-						if (normal != NULL)
-				{
-							*normal    = ((1.f - a - b)  * face.mVertices[index1].mNormal + 
-										  a              * face.mVertices[index2].mNormal +
-										  b              * face.mVertices[index3].mNormal);
-						}
+	*output_vertices = new LLVector3[new_num_vertices];
+	num_output_vertices = new_num_vertices;
+	for (i = 0; i < new_num_vertices; i++)
+	{
+		(*output_vertices)[i] = new_vertices[i];
+	}
 
-						if (bi_normal != NULL)
-					{
-							*bi_normal = ((1.f - a - b)  * face.mVertices[index1].mBinormal + 
-										  a              * face.mVertices[index2].mBinormal +
-										  b              * face.mVertices[index3].mBinormal);
-						}
+	*output_triangles = new S32[cur_tri*3];
+	num_output_triangles = cur_tri;
+	memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32));		/* Flawfinder: ignore */
 
-					}
-				}
-			}
-		}		
+	/*
+	llinfos << "Out vertices: " << num_output_vertices << llendl;
+	llinfos << "Out triangles: " << num_output_triangles << llendl;
+	for (i = 0; i < num_output_vertices; i++)
+	{
+		llinfos << i << ":" << (*output_vertices)[i] << llendl;
 	}
+	for (i = 0; i < num_output_triangles; i++)
+	{
+		llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl;
+	}
+	*/
+
+	//llinfos << "Out vertices: " << num_output_vertices << llendl;
+	//llinfos << "Out triangles: " << num_output_triangles << llendl;
+	delete[] vertex_mapping;
+	vertex_mapping = NULL;
+	delete[] new_vertices;
+	new_vertices = NULL;
+	delete[] new_triangles;
+	new_triangles = NULL;
+	delete[] sorted_tris;
+	sorted_tris = NULL;
+	triangle_list.clear();
+	std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer());
+	vertex_list.clear();
 	
-	
-	return hit_face;
+	return TRUE;
 }
 
-class LLVertexIndexPair
-{
-public:
-	LLVertexIndexPair(const LLVector3 &vertex, const S32 index);
-
-	LLVector3 mVertex;
-	S32	mIndex;
-};
 
-LLVertexIndexPair::LLVertexIndexPair(const LLVector3 &vertex, const S32 index)
+BOOL LLVolumeParams::importFile(LLFILE *fp)
 {
-	mVertex = vertex;
-	mIndex = index;
-}
-
-const F32 VERTEX_SLOP = 0.00001f;
-const F32 VERTEX_SLOP_SQRD = VERTEX_SLOP * VERTEX_SLOP;
+	LLMemType m1(LLMemType::MTYPE_VOLUME);
+	
+	//llinfos << "importing volume" << llendl;
+	const S32 BUFSIZE = 16384;
+	char buffer[BUFSIZE];	/* Flawfinder: ignore */
+	// *NOTE: changing the size or type of this buffer will require
+	// changing the sscanf below.
+	char keyword[256];	/* Flawfinder: ignore */
+	keyword[0] = 0;
 
-struct lessVertex
-{
-	bool operator()(const LLVertexIndexPair *a, const LLVertexIndexPair *b)
+	while (!feof(fp))
 	{
-		const F32 slop = VERTEX_SLOP;
-
-		if (a->mVertex.mV[0] + slop < b->mVertex.mV[0])
+		if (fgets(buffer, BUFSIZE, fp) == NULL)
 		{
-			return TRUE;
+			buffer[0] = '\0';
 		}
-		else if (a->mVertex.mV[0] - slop > b->mVertex.mV[0])
+		
+		sscanf(buffer, " %255s", keyword);	/* Flawfinder: ignore */
+		if (!strcmp("{", keyword))
 		{
-			return FALSE;
+			continue;
 		}
-		
-		if (a->mVertex.mV[1] + slop < b->mVertex.mV[1])
+		if (!strcmp("}",keyword))
 		{
-			return TRUE;
+			break;
 		}
-		else if (a->mVertex.mV[1] - slop > b->mVertex.mV[1])
+		else if (!strcmp("profile", keyword))
 		{
-			return FALSE;
+			mProfileParams.importFile(fp);
 		}
-		
-		if (a->mVertex.mV[2] + slop < b->mVertex.mV[2])
+		else if (!strcmp("path",keyword))
 		{
-			return TRUE;
+			mPathParams.importFile(fp);
 		}
-		else if (a->mVertex.mV[2] - slop > b->mVertex.mV[2])
+		else
 		{
-			return FALSE;
+			llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
 		}
-		
-		return FALSE;
 	}
-};
 
-struct lessTriangle
+	return TRUE;
+}
+
+BOOL LLVolumeParams::exportFile(LLFILE *fp) const
+{
+	fprintf(fp,"\tshape 0\n");
+	fprintf(fp,"\t{\n");
+	mPathParams.exportFile(fp);
+	mProfileParams.exportFile(fp);
+	fprintf(fp, "\t}\n");
+	return TRUE;
+}
+
+
+BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream)
 {
-	bool operator()(const S32 *a, const S32 *b)
+	LLMemType m1(LLMemType::MTYPE_VOLUME);
+	
+	//llinfos << "importing volume" << llendl;
+	const S32 BUFSIZE = 16384;
+	// *NOTE: changing the size or type of this buffer will require
+	// changing the sscanf below.
+	char buffer[BUFSIZE];		/* Flawfinder: ignore */
+	char keyword[256];		/* Flawfinder: ignore */
+	keyword[0] = 0;
+
+	while (input_stream.good())
 	{
-		if (*a < *b)
-		{
-			return TRUE;
-		}
-		else if (*a > *b)
+		input_stream.getline(buffer, BUFSIZE);
+		sscanf(buffer, " %255s", keyword);
+		if (!strcmp("{", keyword))
 		{
-			return FALSE;
+			continue;
 		}
-
-		if (*(a+1) < *(b+1))
+		if (!strcmp("}",keyword))
 		{
-			return TRUE;
+			break;
 		}
-		else if (*(a+1) > *(b+1))
+		else if (!strcmp("profile", keyword))
 		{
-			return FALSE;
+			mProfileParams.importLegacyStream(input_stream);
 		}
-
-		if (*(a+2) < *(b+2))
+		else if (!strcmp("path",keyword))
 		{
-			return TRUE;
+			mPathParams.importLegacyStream(input_stream);
 		}
-		else if (*(a+2) > *(b+2))
+		else
 		{
-			return FALSE;
+			llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
 		}
-
-		return FALSE;
 	}
-};
 
-BOOL equalTriangle(const S32 *a, const S32 *b)
-{
-	if ((*a == *b) && (*(a+1) == *(b+1)) && (*(a+2) == *(b+2)))
-	{
-		return TRUE;
-	}
-	return FALSE;
+	return TRUE;
 }
 
-BOOL LLVolume::cleanupTriangleData( const S32 num_input_vertices,
-									const std::vector<Point>& input_vertices,
-									const S32 num_input_triangles,
-									S32 *input_triangles,
-									S32 &num_output_vertices,
-									LLVector3 **output_vertices,
-									S32 &num_output_triangles,
-									S32 **output_triangles)
+BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
 {
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
 	
-	/* Testing: avoid any cleanup
-	static BOOL skip_cleanup = TRUE;
-	if ( skip_cleanup )
-	{
-		num_output_vertices = num_input_vertices;
-		num_output_triangles = num_input_triangles;
+	output_stream <<"\tshape 0\n";
+	output_stream <<"\t{\n";
+	mPathParams.exportLegacyStream(output_stream);
+	mProfileParams.exportLegacyStream(output_stream);
+	output_stream << "\t}\n";
+	return TRUE;
+}
 
-		*output_vertices = new LLVector3[num_input_vertices];
-		for (S32 index = 0; index < num_input_vertices; index++)
-		{
-			(*output_vertices)[index] = input_vertices[index].mPos;
-		}
+LLSD LLVolumeParams::sculptAsLLSD() const
+{
+	LLSD sd = LLSD();
+	sd["id"] = getSculptID();
+	sd["type"] = getSculptType();
 
-		*output_triangles = new S32[num_input_triangles*3];
-		memcpy(*output_triangles, input_triangles, 3*num_input_triangles*sizeof(S32));		// Flawfinder: ignore
-		return TRUE;
-	}
-	*/
+	return sd;
+}
 
-	// Here's how we do this:
-	// Create a structure which contains the original vertex index and the
-	// LLVector3 data.
-	// "Sort" the data by the vectors
-	// Create an array the size of the old vertex list, with a mapping of
-	// old indices to new indices.
-	// Go through triangles, shift so the lowest index is first
-	// Sort triangles by first index
-	// Remove duplicate triangles
-	// Allocate and pack new triangle data.
+bool LLVolumeParams::sculptFromLLSD(LLSD& sd)
+{
+	setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger());
+	return true;
+}
 
-	//LLTimer cleanupTimer;
-	//llinfos << "In vertices: " << num_input_vertices << llendl;
-	//llinfos << "In triangles: " << num_input_triangles << llendl;
+LLSD LLVolumeParams::asLLSD() const
+{
+	LLSD sd = LLSD();
+	sd["path"] = mPathParams;
+	sd["profile"] = mProfileParams;
+	sd["sculpt"] = sculptAsLLSD();
+	
+	return sd;
+}
 
-	S32 i;
-	typedef std::multiset<LLVertexIndexPair*, lessVertex> vertex_set_t;
-	vertex_set_t vertex_list;
+bool LLVolumeParams::fromLLSD(LLSD& sd)
+{
+	mPathParams.fromLLSD(sd["path"]);
+	mProfileParams.fromLLSD(sd["profile"]);
+	sculptFromLLSD(sd["sculpt"]);
+		
+	return true;
+}
 
-	LLVertexIndexPair *pairp = NULL;
-	for (i = 0; i < num_input_vertices; i++)
+void LLVolumeParams::reduceS(F32 begin, F32 end)
+{
+	begin = llclampf(begin);
+	end = llclampf(end);
+	if (begin > end)
 	{
-		LLVertexIndexPair *new_pairp = new LLVertexIndexPair(input_vertices[i].mPos, i);
-		vertex_list.insert(new_pairp);
+		F32 temp = begin;
+		begin = end;
+		end = temp;
 	}
+	F32 a = mProfileParams.getBegin();
+	F32 b = mProfileParams.getEnd();
+	mProfileParams.setBegin(a + begin * (b - a));
+	mProfileParams.setEnd(a + end * (b - a));
+}
 
-	// Generate the vertex mapping and the list of vertices without
-	// duplicates.  This will crash if there are no vertices.
-	llassert(num_input_vertices > 0); // check for no vertices!
-	S32 *vertex_mapping = new S32[num_input_vertices];
-	LLVector3 *new_vertices = new LLVector3[num_input_vertices];
-	LLVertexIndexPair *prev_pairp = NULL;
-
-	S32 new_num_vertices;
-
-	new_num_vertices = 0;
-	for (vertex_set_t::iterator iter = vertex_list.begin(),
-			 end = vertex_list.end();
-		 iter != end; iter++)
+void LLVolumeParams::reduceT(F32 begin, F32 end)
+{
+	begin = llclampf(begin);
+	end = llclampf(end);
+	if (begin > end)
 	{
-		pairp = *iter;
-		if (!prev_pairp || ((pairp->mVertex - prev_pairp->mVertex).magVecSquared() >= VERTEX_SLOP_SQRD))	
-		{
-			new_vertices[new_num_vertices] = pairp->mVertex;
-			//llinfos << "Added vertex " << new_num_vertices << " : " << pairp->mVertex << llendl;
-			new_num_vertices++;
-			// Update the previous
-			prev_pairp = pairp;
-		}
-		else
-		{
-			//llinfos << "Removed duplicate vertex " << pairp->mVertex << ", distance magVecSquared() is " << (pairp->mVertex - prev_pairp->mVertex).magVecSquared() << llendl;
-		}
-		vertex_mapping[pairp->mIndex] = new_num_vertices - 1;
+		F32 temp = begin;
+		begin = end;
+		end = temp;
 	}
+	F32 a = mPathParams.getBegin();
+	F32 b = mPathParams.getEnd();
+	mPathParams.setBegin(a + begin * (b - a));
+	mPathParams.setEnd(a + end * (b - a));
+}
 
-	// Iterate through triangles and remove degenerates, re-ordering vertices
-	// along the way.
-	S32 *new_triangles = new S32[num_input_triangles * 3];
-	S32 new_num_triangles = 0;
+const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f;	// 1/8 unity
+const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f;	// 1/9 unity
 
-	for (i = 0; i < num_input_triangles; i++)
+// returns TRUE if the shape can be approximated with a convex shape 
+// for collison purposes
+BOOL LLVolumeParams::isConvex() const
+{
+	if (!getSculptID().isNull())
 	{
-		S32 v1 = i*3;
-		S32 v2 = v1 + 1;
-		S32 v3 = v1 + 2;
-
-		//llinfos << "Checking triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
-		input_triangles[v1] = vertex_mapping[input_triangles[v1]];
-		input_triangles[v2] = vertex_mapping[input_triangles[v2]];
-		input_triangles[v3] = vertex_mapping[input_triangles[v3]];
-
-		if ((input_triangles[v1] == input_triangles[v2])
-			|| (input_triangles[v1] == input_triangles[v3])
-			|| (input_triangles[v2] == input_triangles[v3]))
-		{
-			//llinfos << "Removing degenerate triangle " << input_triangles[v1] << ":" << input_triangles[v2] << ":" << input_triangles[v3] << llendl;
-			// Degenerate triangle, skip
-			continue;
-		}
+		// can't determine, be safe and say no:
+		return FALSE;
+	}
+	
+	F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
+	F32 hollow = mProfileParams.getHollow();
+	 
+	U8 path_type = mPathParams.getCurveType();
+	if ( path_length > MIN_CONCAVE_PATH_WEDGE
+		&& ( mPathParams.getTwist() != mPathParams.getTwistBegin()
+		     || (hollow > 0.f 
+				 && LL_PCODE_PATH_LINE != path_type) ) )
+	{
+		// twist along a "not too short" path is concave
+		return FALSE;
+	}
 
-		if (input_triangles[v1] < input_triangles[v2])
-		{
-			if (input_triangles[v1] < input_triangles[v3])
-			{
-				// (0 < 1) && (0 < 2)
-				new_triangles[new_num_triangles*3] = input_triangles[v1];
-				new_triangles[new_num_triangles*3+1] = input_triangles[v2];
-				new_triangles[new_num_triangles*3+2] = input_triangles[v3];
-			}
-			else
-			{
-				// (0 < 1) && (2 < 0)
-				new_triangles[new_num_triangles*3] = input_triangles[v3];
-				new_triangles[new_num_triangles*3+1] = input_triangles[v1];
-				new_triangles[new_num_triangles*3+2] = input_triangles[v2];
-			}
-		}
-		else if (input_triangles[v2] < input_triangles[v3])
-		{
-			// (1 < 0) && (1 < 2)
-			new_triangles[new_num_triangles*3] = input_triangles[v2];
-			new_triangles[new_num_triangles*3+1] = input_triangles[v3];
-			new_triangles[new_num_triangles*3+2] = input_triangles[v1];
-		}
-		else
-		{
-			// (1 < 0) && (2 < 1)
-			new_triangles[new_num_triangles*3] = input_triangles[v3];
-			new_triangles[new_num_triangles*3+1] = input_triangles[v1];
-			new_triangles[new_num_triangles*3+2] = input_triangles[v2];
-		}
-		new_num_triangles++;
+	F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin();
+	BOOL same_hole = hollow == 0.f 
+					 || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME;
+
+	F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE;
+	U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
+	if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
+	{
+		// it is a sphere and spheres get twice the minimum profile wedge
+		min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE;
 	}
 
-	if (new_num_triangles == 0)
+	BOOL convex_profile = ( ( profile_length == 1.f
+						     || profile_length <= 0.5f )
+						   && hollow == 0.f )						// trivially convex
+						  || ( profile_length <= min_profile_wedge
+							  && same_hole );						// effectvely convex (even when hollow)
+
+	if (!convex_profile)
 	{
-		llwarns << "Created volume object with 0 faces." << llendl;
-		delete[] new_triangles;
-		delete[] vertex_mapping;
-		delete[] new_vertices;
+		// profile is concave
 		return FALSE;
 	}
 
-	typedef std::set<S32*, lessTriangle> triangle_set_t;
-	triangle_set_t triangle_list;
+	if ( LL_PCODE_PATH_LINE == path_type )
+	{
+		// straight paths with convex profile
+		return TRUE;
+	}
 
-	for (i = 0; i < new_num_triangles; i++)
+	BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f);
+	if (concave_path)
 	{
-		triangle_list.insert(&new_triangles[i*3]);
+		return FALSE;
 	}
 
-	// Sort through the triangle list, and delete duplicates
+	// we're left with spheres, toroids and tubes
+	if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
+	{
+		// at this stage all spheres must be convex
+		return TRUE;
+	}
 
-	S32 *prevp = NULL;
-	S32 *curp = NULL;
+	// it's a toroid or tube		
+	if ( path_length <= MIN_CONCAVE_PATH_WEDGE )
+	{
+		// effectively convex
+		return TRUE;
+	}
 
-	S32 *sorted_tris = new S32[new_num_triangles*3];
-	S32 cur_tri = 0;
-	for (triangle_set_t::iterator iter = triangle_list.begin(),
-			 end = triangle_list.end();
-		 iter != end; iter++)
+	return FALSE;
+}
+
+// debug
+void LLVolumeParams::setCube()
+{
+	mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE);
+	mProfileParams.setBegin(0.f);
+	mProfileParams.setEnd(1.f);
+	mProfileParams.setHollow(0.f);
+
+	mPathParams.setBegin(0.f);
+	mPathParams.setEnd(1.f);
+	mPathParams.setScale(1.f, 1.f);
+	mPathParams.setShear(0.f, 0.f);
+	mPathParams.setCurveType(LL_PCODE_PATH_LINE);
+	mPathParams.setTwistBegin(0.f);
+	mPathParams.setTwistEnd(0.f);
+	mPathParams.setRadiusOffset(0.f);
+	mPathParams.setTaper(0.f, 0.f);
+	mPathParams.setRevolutions(0.f);
+	mPathParams.setSkew(0.f);
+}
+
+LLFaceID LLVolume::generateFaceMask()
+{
+	LLFaceID new_mask = 0x0000;
+
+	switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK)
 	{
-		curp = *iter;
-		if (!prevp || !equalTriangle(prevp, curp))
+	case LL_PCODE_PROFILE_CIRCLE:
+	case LL_PCODE_PROFILE_CIRCLE_HALF:
+		new_mask |= LL_FACE_OUTER_SIDE_0;
+		break;
+	case LL_PCODE_PROFILE_SQUARE:
 		{
-			//llinfos << "Added triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
-			sorted_tris[cur_tri*3] = *curp;
-			sorted_tris[cur_tri*3+1] = *(curp+1);
-			sorted_tris[cur_tri*3+2] = *(curp+2);
-			cur_tri++;
-			prevp = curp;
+			for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++)
+			{
+				new_mask |= LL_FACE_OUTER_SIDE_0 << side;
+			}
 		}
-		else
+		break;
+	case LL_PCODE_PROFILE_ISOTRI:
+	case LL_PCODE_PROFILE_EQUALTRI:
+	case LL_PCODE_PROFILE_RIGHTTRI:
 		{
-			//llinfos << "Skipped triangle " << *curp << ":" << *(curp+1) << ":" << *(curp+2) << llendl;
+			for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++)
+			{
+				new_mask |= LL_FACE_OUTER_SIDE_0 << side;
+			}
 		}
+		break;
+	default:
+		llerrs << "Unknown profile!" << llendl;
+		break;
 	}
 
-	*output_vertices = new LLVector3[new_num_vertices];
-	num_output_vertices = new_num_vertices;
-	for (i = 0; i < new_num_vertices; i++)
+	// handle hollow objects
+	if (mParams.getProfileParams().getHollow() > 0)
 	{
-		(*output_vertices)[i] = new_vertices[i];
+		new_mask |= LL_FACE_INNER_SIDE;
 	}
 
-	*output_triangles = new S32[cur_tri*3];
-	num_output_triangles = cur_tri;
-	memcpy(*output_triangles, sorted_tris, 3*cur_tri*sizeof(S32));		/* Flawfinder: ignore */
+	// handle open profile curves
+	if (mProfilep->isOpen())
+	{
+		new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END;
+	}
 
-	/*
-	llinfos << "Out vertices: " << num_output_vertices << llendl;
-	llinfos << "Out triangles: " << num_output_triangles << llendl;
-	for (i = 0; i < num_output_vertices; i++)
+	// handle open path curves
+	if (mPathp->isOpen())
 	{
-		llinfos << i << ":" << (*output_vertices)[i] << llendl;
+		new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END;
 	}
-	for (i = 0; i < num_output_triangles; i++)
+
+	return new_mask;
+}
+
+BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask)
+{
+	LLFaceID test_mask = 0;
+	for(S32 i = 0; i < getNumFaces(); i++)
 	{
-		llinfos << i << ":" << (*output_triangles)[i*3] << ":" << (*output_triangles)[i*3+1] << ":" << (*output_triangles)[i*3+2] << llendl;
+		test_mask |= mProfilep->mFaces[i].mFaceID;
 	}
-	*/
 
-	//llinfos << "Out vertices: " << num_output_vertices << llendl;
-	//llinfos << "Out triangles: " << num_output_triangles << llendl;
-	delete[] vertex_mapping;
-	vertex_mapping = NULL;
-	delete[] new_vertices;
-	new_vertices = NULL;
-	delete[] new_triangles;
-	new_triangles = NULL;
-	delete[] sorted_tris;
-	sorted_tris = NULL;
-	triangle_list.clear();
-	std::for_each(vertex_list.begin(), vertex_list.end(), DeletePointer());
-	vertex_list.clear();
-	
-	return TRUE;
+	return test_mask == face_mask;
+}
+
+BOOL LLVolume::isConvex() const
+{
+	// mParams.isConvex() may return FALSE even though the final
+	// geometry is actually convex due to LOD approximations.
+	// TODO -- provide LLPath and LLProfile with isConvex() methods
+	// that correctly determine convexity. -- Leviathan
+	return mParams.isConvex();
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params)
+{
+	s << "{type=" << (U32) profile_params.mCurveType;
+	s << ", begin=" << profile_params.mBegin;
+	s << ", end=" << profile_params.mEnd;
+	s << ", hollow=" << profile_params.mHollow;
+	s << "}";
+	return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params)
+{
+	s << "{type=" << (U32) path_params.mCurveType;
+	s << ", begin=" << path_params.mBegin;
+	s << ", end=" << path_params.mEnd;
+	s << ", twist=" << path_params.mTwistEnd;
+	s << ", scale=" << path_params.mScale;
+	s << ", shear=" << path_params.mShear;
+	s << ", twist_begin=" << path_params.mTwistBegin;
+	s << ", radius_offset=" << path_params.mRadiusOffset;
+	s << ", taper=" << path_params.mTaper;
+	s << ", revolutions=" << path_params.mRevolutions;
+	s << ", skew=" << path_params.mSkew;
+	s << "}";
+	return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params)
+{
+	s << "{profileparams = " << volume_params.mProfileParams;
+	s << ", pathparams = " << volume_params.mPathParams;
+	s << "}";
+	return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLProfile &profile)
+{
+	s << " {open=" << (U32) profile.mOpen;
+	s << ", dirty=" << profile.mDirty;
+	s << ", totalout=" << profile.mTotalOut;
+	s << ", total=" << profile.mTotal;
+	s << "}";
+	return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLPath &path)
+{
+	s << "{open=" << (U32) path.mOpen;
+	s << ", dirty=" << path.mDirty;
+	s << ", step=" << path.mStep;
+	s << ", total=" << path.mTotal;
+	s << "}";
+	return s;
+}
+
+std::ostream& operator<<(std::ostream &s, const LLVolume &volume)
+{
+	s << "{params = " << volume.getParams();
+	s << ", path = " << *volume.mPathp;
+	s << ", profile = " << *volume.mProfilep;
+	s << "}";
+	return s;
+}
+
+
+std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
+{
+	s << "{params = " << volumep->getParams();
+	s << ", path = " << *(volumep->mPathp);
+	s << ", profile = " << *(volumep->mProfilep);
+	s << "}";
+	return s;
+}
+
+LLVolumeFace::LLVolumeFace() : 
+	mID(0),
+	mTypeMask(0),
+	mBeginS(0),
+	mBeginT(0),
+	mNumS(0),
+	mNumT(0),
+	mNumVertices(0),
+	mNumIndices(0),
+	mPositions(NULL),
+	mNormals(NULL),
+	mBinormals(NULL),
+	mTexCoords(NULL),
+	mIndices(NULL),
+	mWeights(NULL),
+	mOctree(NULL)
+{
+	mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3);
+	mCenter = mExtents+2;
 }
 
+LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
+:	mID(0),
+	mTypeMask(0),
+	mBeginS(0),
+	mBeginT(0),
+	mNumS(0),
+	mNumT(0),
+	mNumVertices(0),
+	mNumIndices(0),
+	mPositions(NULL),
+	mNormals(NULL),
+	mBinormals(NULL),
+	mTexCoords(NULL),
+	mIndices(NULL),
+	mWeights(NULL),
+	mOctree(NULL)
+{ 
+	mExtents = (LLVector4a*) malloc(sizeof(LLVector4a)*3);
+	mCenter = mExtents+2;
+	*this = src;
+}
 
-BOOL LLVolumeParams::importFile(LLFILE *fp)
+LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 {
-	LLMemType m1(LLMemType::MTYPE_VOLUME);
+	if (&src == this)
+	{ //self assignment, do nothing
+		return *this;
+	}
+
+	mID = src.mID;
+	mTypeMask = src.mTypeMask;
+	mBeginS = src.mBeginS;
+	mBeginT = src.mBeginT;
+	mNumS = src.mNumS;
+	mNumT = src.mNumT;
+
+	mExtents[0] = src.mExtents[0];
+	mExtents[1] = src.mExtents[1];
+	*mCenter = *src.mCenter;
+
+	mNumVertices = 0;
+	mNumIndices = 0;
+
+	freeData();
 	
-	//llinfos << "importing volume" << llendl;
-	const S32 BUFSIZE = 16384;
-	char buffer[BUFSIZE];	/* Flawfinder: ignore */
-	// *NOTE: changing the size or type of this buffer will require
-	// changing the sscanf below.
-	char keyword[256];	/* Flawfinder: ignore */
-	keyword[0] = 0;
+	LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 3*sizeof(LLVector4a));
 
-	while (!feof(fp))
+	resizeVertices(src.mNumVertices);
+	resizeIndices(src.mNumIndices);
+
+	if (mNumVertices)
 	{
-		if (fgets(buffer, BUFSIZE, fp) == NULL)
-		{
-			buffer[0] = '\0';
-		}
-		
-		sscanf(buffer, " %255s", keyword);	/* Flawfinder: ignore */
-		if (!strcmp("{", keyword))
-		{
-			continue;
-		}
-		if (!strcmp("}",keyword))
+		S32 vert_size = mNumVertices*sizeof(LLVector4a);
+		S32 tc_size = (mNumVertices*sizeof(LLVector2)+0xF) & ~0xF;
+			
+		LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size);
+		LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
+		LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, tc_size);
+
+
+		if (src.mBinormals)
 		{
-			break;
+			allocateBinormals(src.mNumVertices);
+			LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size);
 		}
-		else if (!strcmp("profile", keyword))
+		else
 		{
-			mProfileParams.importFile(fp);
+			free(mBinormals);
+			mBinormals = NULL;
 		}
-		else if (!strcmp("path",keyword))
+
+		if (src.mWeights)
 		{
-			mPathParams.importFile(fp);
+			allocateWeights(src.mNumVertices);
+			LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size);
 		}
 		else
 		{
-			llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
+			free(mWeights);
+			mWeights = NULL;
 		}
 	}
 
-	return TRUE;
+	if (mNumIndices)
+	{
+		S32 idx_size = (mNumIndices*sizeof(U16)+0xF) & ~0xF;
+		
+		LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size);
+	}
+	
+	//delete 
+	return *this;
 }
 
-BOOL LLVolumeParams::exportFile(LLFILE *fp) const
+LLVolumeFace::~LLVolumeFace()
 {
-	fprintf(fp,"\tshape 0\n");
-	fprintf(fp,"\t{\n");
-	mPathParams.exportFile(fp);
-	mProfileParams.exportFile(fp);
-	fprintf(fp, "\t}\n");
-	return TRUE;
+	free(mExtents);
+	mExtents = NULL;
+
+	freeData();
 }
 
+void LLVolumeFace::freeData()
+{
+	free(mPositions);
+	mPositions = NULL;
+	free( mNormals);
+	mNormals = NULL;
+	free(mTexCoords);
+	mTexCoords = NULL;
+	free(mIndices);
+	mIndices = NULL;
+	free(mBinormals);
+	mBinormals = NULL;
+	free(mWeights);
+	mWeights = NULL;
+
+	delete mOctree;
+	mOctree = NULL;
+}
 
-BOOL LLVolumeParams::importLegacyStream(std::istream& input_stream)
+BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 {
-	LLMemType m1(LLMemType::MTYPE_VOLUME);
-	
-	//llinfos << "importing volume" << llendl;
-	const S32 BUFSIZE = 16384;
-	// *NOTE: changing the size or type of this buffer will require
-	// changing the sscanf below.
-	char buffer[BUFSIZE];		/* Flawfinder: ignore */
-	char keyword[256];		/* Flawfinder: ignore */
-	keyword[0] = 0;
+	//tree for this face is no longer valid
+	delete mOctree;
+	mOctree = NULL;
 
-	while (input_stream.good())
+	if (mTypeMask & CAP_MASK)
 	{
-		input_stream.getline(buffer, BUFSIZE);
-		sscanf(buffer, " %255s", keyword);
-		if (!strcmp("{", keyword))
-		{
-			continue;
-		}
-		if (!strcmp("}",keyword))
-		{
-			break;
-		}
-		else if (!strcmp("profile", keyword))
-		{
-			mProfileParams.importLegacyStream(input_stream);
-		}
-		else if (!strcmp("path",keyword))
-		{
-			mPathParams.importLegacyStream(input_stream);
-		}
-		else
-		{
-			llwarns << "unknown keyword " << keyword << " in volume import" << llendl;
-		}
+		return createCap(volume, partial_build);
+	}
+	else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
+	{
+		return createSide(volume, partial_build);
+	}
+	else
+	{
+		llerrs << "Unknown/uninitialized face type!" << llendl;
+		return FALSE;
 	}
-
-	return TRUE;
-}
-
-BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
-{
-	LLMemType m1(LLMemType::MTYPE_VOLUME);
-	
-	output_stream <<"\tshape 0\n";
-	output_stream <<"\t{\n";
-	mPathParams.exportLegacyStream(output_stream);
-	mProfileParams.exportLegacyStream(output_stream);
-	output_stream << "\t}\n";
-	return TRUE;
 }
 
-LLSD LLVolumeParams::asLLSD() const
+void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv)
 {
-	LLSD sd = LLSD();
-	sd["path"] = mPathParams;
-	sd["profile"] = mProfileParams;
-	return sd;
+	cv.setPosition(mPositions[index]);
+	cv.setNormal(mNormals[index]);
+	cv.mTexCoord = mTexCoords[index];
 }
 
-bool LLVolumeParams::fromLLSD(LLSD& sd)
+bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const
 {
-	mPathParams.fromLLSD(sd["path"]);
-	mProfileParams.fromLLSD(sd["profile"]);
-	return true;
+	return getPosition().equals3(rhs.getPosition()) &&
+		mTexCoord == rhs.mTexCoord &&
+		getNormal().equals3(rhs.getNormal());
 }
 
-void LLVolumeParams::reduceS(F32 begin, F32 end)
+bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector3& a, const LLVector3& b) const
 {
-	begin = llclampf(begin);
-	end = llclampf(end);
-	if (begin > end)
+	if (a.mV[0] != b.mV[0])
 	{
-		F32 temp = begin;
-		begin = end;
-		end = temp;
+		return a.mV[0] < b.mV[0];
 	}
-	F32 a = mProfileParams.getBegin();
-	F32 b = mProfileParams.getEnd();
-	mProfileParams.setBegin(a + begin * (b - a));
-	mProfileParams.setEnd(a + end * (b - a));
+	
+	if (a.mV[1] != b.mV[1])
+	{
+		return a.mV[1] < b.mV[1];
+	}
+	
+	return a.mV[2] < b.mV[2];
 }
 
-void LLVolumeParams::reduceT(F32 begin, F32 end)
+void LLVolumeFace::optimize(F32 angle_cutoff)
 {
-	begin = llclampf(begin);
-	end = llclampf(end);
-	if (begin > end)
+	LLVolumeFace new_face;
+
+	//map of points to vector of vertices at that point
+	VertexMapData::PointMap point_map;
+
+	//remove redundant vertices
+	for (U32 i = 0; i < mNumIndices; ++i)
 	{
-		F32 temp = begin;
-		begin = end;
-		end = temp;
+		U16 index = mIndices[i];
+
+		LLVolumeFace::VertexData cv;
+		getVertexData(index, cv);
+		
+		BOOL found = FALSE;
+		VertexMapData::PointMap::iterator point_iter = point_map.find(LLVector3(cv.getPosition().getF32ptr()));
+		if (point_iter != point_map.end())
+		{ //duplicate point might exist
+			for (U32 j = 0; j < point_iter->second.size(); ++j)
+			{
+				LLVolumeFace::VertexData& tv = (point_iter->second)[j];
+				if (tv.compareNormal(cv, angle_cutoff))
+				{
+					found = TRUE;
+					new_face.pushIndex((point_iter->second)[j].mIndex);
+					break;
+				}
+			}
+		}
+
+		if (!found)
+		{
+			new_face.pushVertex(cv);
+			U16 index = (U16) new_face.mNumVertices-1;
+			new_face.pushIndex(index);
+
+			VertexMapData d;
+			d.setPosition(cv.getPosition());
+			d.mTexCoord = cv.mTexCoord;
+			d.setNormal(cv.getNormal());
+			d.mIndex = index;
+			if (point_iter != point_map.end())
+			{
+				point_iter->second.push_back(d);
+			}
+			else
+			{
+				point_map[LLVector3(d.getPosition().getF32ptr())].push_back(d);
+			}
+		}
 	}
-	F32 a = mPathParams.getBegin();
-	F32 b = mPathParams.getEnd();
-	mPathParams.setBegin(a + begin * (b - a));
-	mPathParams.setEnd(a + end * (b - a));
+
+	swapData(new_face);
 }
 
-const F32 MIN_CONCAVE_PROFILE_WEDGE = 0.125f;	// 1/8 unity
-const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f;	// 1/9 unity
+class LLVCacheTriangleData;
 
-// returns TRUE if the shape can be approximated with a convex shape 
-// for collison purposes
-BOOL LLVolumeParams::isConvex() const
+class LLVCacheVertexData
 {
-	F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
-	F32 hollow = mProfileParams.getHollow();
-	 
-	U8 path_type = mPathParams.getCurveType();
-	if ( path_length > MIN_CONCAVE_PATH_WEDGE
-		&& ( mPathParams.getTwist() != mPathParams.getTwistBegin()
-		     || (hollow > 0.f 
-				 && LL_PCODE_PATH_LINE != path_type) ) )
+public:
+	S32 mIdx;
+	S32 mCacheTag;
+	F32 mScore;
+	U32 mActiveTriangles;
+	std::vector<LLVCacheTriangleData*> mTriangles;
+
+	LLVCacheVertexData()
 	{
-		// twist along a "not too short" path is concave
-		return FALSE;
+		mCacheTag = -1;
+		mScore = 0.f;
+		mActiveTriangles = 0;
+		mIdx = -1;
 	}
+};
 
-	F32 profile_length = mProfileParams.getEnd() - mProfileParams.getBegin();
-	BOOL same_hole = hollow == 0.f 
-					 || (mProfileParams.getCurveType() & LL_PCODE_HOLE_MASK) == LL_PCODE_HOLE_SAME;
+class LLVCacheTriangleData
+{
+public:
+	bool mActive;
+	F32 mScore;
+	LLVCacheVertexData* mVertex[3];
 
-	F32 min_profile_wedge = MIN_CONCAVE_PROFILE_WEDGE;
-	U8 profile_type = mProfileParams.getCurveType() & LL_PCODE_PROFILE_MASK;
-	if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
+	LLVCacheTriangleData()
 	{
-		// it is a sphere and spheres get twice the minimum profile wedge
-		min_profile_wedge = 2.f * MIN_CONCAVE_PROFILE_WEDGE;
+		mActive = true;
+		mScore = 0.f;
+		mVertex[0] = mVertex[1] = mVertex[2] = NULL;
 	}
 
-	BOOL convex_profile = ( ( profile_length == 1.f
-						     || profile_length <= 0.5f )
-						   && hollow == 0.f )						// trivially convex
-						  || ( profile_length <= min_profile_wedge
-							  && same_hole );						// effectvely convex (even when hollow)
-
-	if (!convex_profile)
+	void complete()
 	{
-		// profile is concave
-		return FALSE;
+		mActive = false;
+		for (S32 i = 0; i < 3; ++i)
+		{
+			if (mVertex[i])
+			{
+				llassert_always(mVertex[i]->mActiveTriangles > 0);
+				mVertex[i]->mActiveTriangles--;
+			}
+		}
 	}
 
-	if ( LL_PCODE_PATH_LINE == path_type )
-	{
-		// straight paths with convex profile
-		return TRUE;
+	bool operator<(const LLVCacheTriangleData& rhs) const
+	{ //highest score first
+		return rhs.mScore < mScore;
 	}
+};
 
-	BOOL concave_path = (path_length < 1.0f) && (path_length > 0.5f);
-	if (concave_path)
-	{
-		return FALSE;
+const F32 FindVertexScore_CacheDecayPower = 1.5f;
+const F32 FindVertexScore_LastTriScore = 0.75f;
+const F32 FindVertexScore_ValenceBoostScale = 2.0f;
+const F32 FindVertexScore_ValenceBoostPower = 0.5f;
+const U32 MaxSizeVertexCache = 32;
+
+F32 find_vertex_score(LLVCacheVertexData& data)
+{
+	if (data.mActiveTriangles == 0)
+	{ //no triangle references this vertex
+		return -1.f;
 	}
 
-	// we're left with spheres, toroids and tubes
-	if ( LL_PCODE_PROFILE_CIRCLE_HALF == profile_type )
+	F32 score = 0.f;
+
+	S32 cache_idx = data.mCacheTag;
+
+	if (cache_idx < 0)
 	{
-		// at this stage all spheres must be convex
-		return TRUE;
+		//not in cache
 	}
-
-	// it's a toroid or tube		
-	if ( path_length <= MIN_CONCAVE_PATH_WEDGE )
+	else
 	{
-		// effectively convex
-		return TRUE;
+		if (cache_idx < 3)
+		{ //vertex was in the last triangle
+			score = FindVertexScore_LastTriScore;
+		}
+		else
+		{ //more points for being higher in the cache
+			F32 scaler = 1.f/(MaxSizeVertexCache-3);
+			score = 1.f-((cache_idx-3)*scaler);
+			score = powf(score, FindVertexScore_CacheDecayPower);
+		}
 	}
 
-	return FALSE;
-}
-
-// debug
-void LLVolumeParams::setCube()
-{
-	mProfileParams.setCurveType(LL_PCODE_PROFILE_SQUARE);
-	mProfileParams.setBegin(0.f);
-	mProfileParams.setEnd(1.f);
-	mProfileParams.setHollow(0.f);
+	//bonus points for having low valence
+	F32 valence_boost = powf(data.mActiveTriangles, -FindVertexScore_ValenceBoostPower);
+	score += FindVertexScore_ValenceBoostScale * valence_boost;
 
-	mPathParams.setBegin(0.f);
-	mPathParams.setEnd(1.f);
-	mPathParams.setScale(1.f, 1.f);
-	mPathParams.setShear(0.f, 0.f);
-	mPathParams.setCurveType(LL_PCODE_PATH_LINE);
-	mPathParams.setTwistBegin(0.f);
-	mPathParams.setTwistEnd(0.f);
-	mPathParams.setRadiusOffset(0.f);
-	mPathParams.setTaper(0.f, 0.f);
-	mPathParams.setRevolutions(0.f);
-	mPathParams.setSkew(0.f);
+	return score;
 }
 
-LLFaceID LLVolume::generateFaceMask()
+class LLVCacheFIFO
 {
-	LLFaceID new_mask = 0x0000;
+public:
+	LLVCacheVertexData* mCache[MaxSizeVertexCache];
+	U32 mMisses;
 
-	switch(mParams.getProfileParams().getCurveType() & LL_PCODE_PROFILE_MASK)
+	LLVCacheFIFO()
 	{
-	case LL_PCODE_PROFILE_CIRCLE:
-	case LL_PCODE_PROFILE_CIRCLE_HALF:
-		new_mask |= LL_FACE_OUTER_SIDE_0;
-		break;
-	case LL_PCODE_PROFILE_SQUARE:
+		mMisses = 0;
+		for (U32 i = 0; i < MaxSizeVertexCache; ++i)
 		{
-			for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 4.f); side < llceil(mParams.getProfileParams().getEnd() * 4.f); side++)
-			{
-				new_mask |= LL_FACE_OUTER_SIDE_0 << side;
-			}
+			mCache[i] = NULL;
 		}
-		break;
-	case LL_PCODE_PROFILE_ISOTRI:
-	case LL_PCODE_PROFILE_EQUALTRI:
-	case LL_PCODE_PROFILE_RIGHTTRI:
+	}
+
+	void addVertex(LLVCacheVertexData* data)
+	{
+		if (data->mCacheTag == -1)
 		{
-			for(S32 side = (S32)(mParams.getProfileParams().getBegin() * 3.f); side < llceil(mParams.getProfileParams().getEnd() * 3.f); side++)
+			mMisses++;
+
+			S32 end = MaxSizeVertexCache-1;
+
+			if (mCache[end])
 			{
-				new_mask |= LL_FACE_OUTER_SIDE_0 << side;
+				mCache[end]->mCacheTag = -1;
+			}
+
+			for (S32 i = end; i > 0; --i)
+			{
+				mCache[i] = mCache[i-1];
+				if (mCache[i])
+				{
+					mCache[i]->mCacheTag = i;
+				}
 			}
+
+			mCache[0] = data;
+			data->mCacheTag = 0;
 		}
-		break;
-	default:
-		llerrs << "Unknown profile!" << llendl;
-		break;
 	}
+};
 
-	// handle hollow objects
-	if (mParams.getProfileParams().getHollow() > 0)
+class LLVCacheLRU
+{
+public:
+	LLVCacheVertexData* mCache[MaxSizeVertexCache+3];
+
+	LLVCacheTriangleData* mBestTriangle;
+	
+	U32 mMisses;
+
+	LLVCacheLRU()
 	{
-		new_mask |= LL_FACE_INNER_SIDE;
+		for (U32 i = 0; i < MaxSizeVertexCache+3; ++i)
+		{
+			mCache[i] = NULL;
+		}
+
+		mBestTriangle = NULL;
+		mMisses = 0;
 	}
 
-	// handle open profile curves
-	if (mProfilep->isOpen())
+	void addVertex(LLVCacheVertexData* data)
 	{
-		new_mask |= LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END;
+		S32 end = MaxSizeVertexCache+2;
+		if (data->mCacheTag != -1)
+		{ //just moving a vertex to the front of the cache
+			end = data->mCacheTag;
+		}
+		else
+		{
+			mMisses++;
+			if (mCache[end])
+			{ //adding a new vertex, vertex at end of cache falls off
+				mCache[end]->mCacheTag = -1;
+			}
+		}
+
+		for (S32 i = end; i > 0; --i)
+		{ //adjust cache pointers and tags
+			mCache[i] = mCache[i-1];
+
+			if (mCache[i])
+			{
+				mCache[i]->mCacheTag = i;			
+			}
+		}
+
+		mCache[0] = data;
+		mCache[0]->mCacheTag = 0;
 	}
 
-	// handle open path curves
-	if (mPathp->isOpen())
+	void addTriangle(LLVCacheTriangleData* data)
 	{
-		new_mask |= LL_FACE_PATH_BEGIN | LL_FACE_PATH_END;
+		addVertex(data->mVertex[0]);
+		addVertex(data->mVertex[1]);
+		addVertex(data->mVertex[2]);
 	}
 
-	return new_mask;
-}
-
-BOOL LLVolume::isFaceMaskValid(LLFaceID face_mask)
-{
-	LLFaceID test_mask = 0;
-	for(S32 i = 0; i < getNumFaces(); i++)
+	void updateScores()
 	{
-		test_mask |= mProfilep->mFaces[i].mFaceID;
+		for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i)
+		{ //trailing 3 vertices aren't actually in the cache for scoring purposes
+			if (mCache[i])
+			{
+				mCache[i]->mCacheTag = -1;
+			}
+		}
+
+		for (U32 i = 0; i < MaxSizeVertexCache; ++i)
+		{ //update scores of vertices in cache
+			if (mCache[i])
+			{
+				mCache[i]->mScore = find_vertex_score(*(mCache[i]));
+				llassert_always(mCache[i]->mCacheTag == i);
+			}
+		}
+
+		mBestTriangle = NULL;
+		//update triangle scores
+		for (U32 i = 0; i < MaxSizeVertexCache+3; ++i)
+		{
+			if (mCache[i])
+			{
+				for (U32 j = 0; j < mCache[i]->mTriangles.size(); ++j)
+				{
+					LLVCacheTriangleData* tri = mCache[i]->mTriangles[j];
+					if (tri->mActive)
+					{
+						tri->mScore = tri->mVertex[0]->mScore;
+						tri->mScore += tri->mVertex[1]->mScore;
+						tri->mScore += tri->mVertex[2]->mScore;
+
+						if (!mBestTriangle || mBestTriangle->mScore < tri->mScore)
+						{
+							mBestTriangle = tri;
+						}
+					}
+				}
+			}
+		}
+
+		//knock trailing 3 vertices off the cache
+		for (U32 i = MaxSizeVertexCache; i < MaxSizeVertexCache+3; ++i)
+		{
+			if (mCache[i])
+			{
+				llassert_always(mCache[i]->mCacheTag == -1);
+				mCache[i] = NULL;
+			}
+		}
 	}
+};
 
-	return test_mask == face_mask;
-}
 
-BOOL LLVolume::isConvex() const
-{
-	// mParams.isConvex() may return FALSE even though the final
-	// geometry is actually convex due to LOD approximations.
-	// TODO -- provide LLPath and LLProfile with isConvex() methods
-	// that correctly determine convexity. -- Leviathan
-	return mParams.isConvex();
-}
+void LLVolumeFace::cacheOptimize()
+{ //optimize for vertex cache according to Forsyth method: 
+  // http://home.comcast.net/~tom_forsyth/papers/fast_vert_cache_opt.html
+	
+	LLVCacheLRU cache;
+	
+	//mapping of vertices to triangles and indices
+	std::vector<LLVCacheVertexData> vertex_data;
 
+	//mapping of triangles do vertices
+	std::vector<LLVCacheTriangleData> triangle_data;
 
-std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params)
-{
-	s << "{type=" << (U32) profile_params.mCurveType;
-	s << ", begin=" << profile_params.mBegin;
-	s << ", end=" << profile_params.mEnd;
-	s << ", hollow=" << profile_params.mHollow;
-	s << "}";
-	return s;
-}
+	triangle_data.resize(mNumIndices/3);
+	vertex_data.resize(mNumVertices);
 
+	for (U32 i = 0; i < mNumIndices; i++)
+	{ //populate vertex data and triangle data arrays
+		U16 idx = mIndices[i];
+		U32 tri_idx = i/3;
 
-std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params)
-{
-	s << "{type=" << (U32) path_params.mCurveType;
-	s << ", begin=" << path_params.mBegin;
-	s << ", end=" << path_params.mEnd;
-	s << ", twist=" << path_params.mTwistEnd;
-	s << ", scale=" << path_params.mScale;
-	s << ", shear=" << path_params.mShear;
-	s << ", twist_begin=" << path_params.mTwistBegin;
-	s << ", radius_offset=" << path_params.mRadiusOffset;
-	s << ", taper=" << path_params.mTaper;
-	s << ", revolutions=" << path_params.mRevolutions;
-	s << ", skew=" << path_params.mSkew;
-	s << "}";
-	return s;
-}
+		vertex_data[idx].mTriangles.push_back(&(triangle_data[tri_idx]));
+		vertex_data[idx].mIdx = idx;
+		triangle_data[tri_idx].mVertex[i%3] = &(vertex_data[idx]);
+	}
 
+	/*F32 pre_acmr = 1.f;
+	//measure cache misses from before rebuild
+	{
+		LLVCacheFIFO test_cache;
+		for (U32 i = 0; i < mNumIndices; ++i)
+		{
+			test_cache.addVertex(&vertex_data[mIndices[i]]);
+		}
 
-std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params)
-{
-	s << "{profileparams = " << volume_params.mProfileParams;
-	s << ", pathparams = " << volume_params.mPathParams;
-	s << "}";
-	return s;
-}
+		for (U32 i = 0; i < mNumVertices; i++)
+		{
+			vertex_data[i].mCacheTag = -1;
+		}
 
+		pre_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
+	}*/
 
-std::ostream& operator<<(std::ostream &s, const LLProfile &profile)
-{
-	s << " {open=" << (U32) profile.mOpen;
-	s << ", dirty=" << profile.mDirty;
-	s << ", totalout=" << profile.mTotalOut;
-	s << ", total=" << profile.mTotal;
-	s << "}";
-	return s;
-}
+	for (U32 i = 0; i < mNumVertices; i++)
+	{ //initialize score values (no cache -- might try a fifo cache here)
+		vertex_data[i].mScore = find_vertex_score(vertex_data[i]);
+		vertex_data[i].mActiveTriangles = vertex_data[i].mTriangles.size();
 
+		for (U32 j = 0; j < vertex_data[i].mTriangles.size(); ++j)
+		{
+			vertex_data[i].mTriangles[j]->mScore += vertex_data[i].mScore;
+		}
+	}
 
-std::ostream& operator<<(std::ostream &s, const LLPath &path)
-{
-	s << "{open=" << (U32) path.mOpen;
-	s << ", dirty=" << path.mDirty;
-	s << ", step=" << path.mStep;
-	s << ", total=" << path.mTotal;
-	s << "}";
-	return s;
-}
+	//sort triangle data by score
+	std::sort(triangle_data.begin(), triangle_data.end());
 
-std::ostream& operator<<(std::ostream &s, const LLVolume &volume)
-{
-	s << "{params = " << volume.getParams();
-	s << ", path = " << *volume.mPathp;
-	s << ", profile = " << *volume.mProfilep;
-	s << "}";
-	return s;
-}
+	std::vector<U16> new_indices;
 
+	LLVCacheTriangleData* tri;
 
-std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
-{
-	s << "{params = " << volumep->getParams();
-	s << ", path = " << *(volumep->mPathp);
-	s << ", profile = " << *(volumep->mProfilep);
-	s << "}";
-	return s;
-}
+	//prime pump by adding first triangle to cache;
+	tri = &(triangle_data[0]);
+	cache.addTriangle(tri);
+	new_indices.push_back(tri->mVertex[0]->mIdx);
+	new_indices.push_back(tri->mVertex[1]->mIdx);
+	new_indices.push_back(tri->mVertex[2]->mIdx);
+	tri->complete();
 
+	U32 breaks = 0;
+	for (U32 i = 1; i < mNumIndices/3; ++i)
+	{
+		cache.updateScores();
+		tri = cache.mBestTriangle;
+		if (!tri)
+		{
+			breaks++;
+			for (U32 j = 0; j < triangle_data.size(); ++j)
+			{
+				if (triangle_data[j].mActive)
+				{
+					tri = &(triangle_data[j]);
+					break;
+				}
+			}
+		}	
+		
+		cache.addTriangle(tri);
+		new_indices.push_back(tri->mVertex[0]->mIdx);
+		new_indices.push_back(tri->mVertex[1]->mIdx);
+		new_indices.push_back(tri->mVertex[2]->mIdx);
+		tri->complete();
+	}
 
-BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
-{
-	BOOL ret = FALSE ;
-	if (mTypeMask & CAP_MASK)
+	for (U32 i = 0; i < mNumIndices; ++i)
 	{
-		ret = createCap(volume, partial_build);
+		mIndices[i] = new_indices[i];
 	}
-	else if ((mTypeMask & END_MASK) || (mTypeMask & SIDE_MASK))
+
+	/*F32 post_acmr = 1.f;
+	//measure cache misses from after rebuild
+	{
+		LLVCacheFIFO test_cache;
+		for (U32 i = 0; i < mNumVertices; i++)
+		{
+			vertex_data[i].mCacheTag = -1;
+		}
+
+		for (U32 i = 0; i < mNumIndices; ++i)
+		{
+			test_cache.addVertex(&vertex_data[mIndices[i]]);
+		}
+		
+		post_acmr = (F32) test_cache.mMisses/(mNumIndices/3);
+	}*/
+
+	//optimize for pre-TnL cache
+	
+	//allocate space for new buffer
+	S32 num_verts = mNumVertices;
+	LLVector4a* pos = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+	LLVector4a* norm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+	S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
+	LLVector2* tc = (LLVector2*) malloc(size);
+
+	LLVector4a* wght = NULL;
+	if (mWeights)
 	{
-		ret = createSide(volume, partial_build);
+		wght = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
 	}
-	else
+
+	LLVector4a* binorm = NULL;
+	if (mBinormals)
 	{
-		llerrs << "Unknown/uninitialized face type!" << llendl;
+		binorm = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
 	}
 
-	//update the range of the texture coordinates
-	if(ret)
+	//allocate mapping of old indices to new indices
+	std::vector<S32> new_idx;
+	new_idx.resize(mNumVertices, -1);
+
+	S32 cur_idx = 0;
+	for (U32 i = 0; i < mNumIndices; ++i)
 	{
-		mTexCoordExtents[0].setVec(1.f, 1.f) ;
-		mTexCoordExtents[1].setVec(0.f, 0.f) ;
+		U16 idx = mIndices[i];
+		if (new_idx[idx] == -1)
+		{ //this vertex hasn't been added yet
+			new_idx[idx] = cur_idx;
 
-		U32 end = mVertices.size() ;
-		for(U32 i = 0 ; i < end ; i++)
-		{
-			if(mTexCoordExtents[0].mV[0] > mVertices[i].mTexCoord.mV[0])
+			//copy vertex data
+			pos[cur_idx] = mPositions[idx];
+			norm[cur_idx] = mNormals[idx];
+			tc[cur_idx] = mTexCoords[idx];
+			if (mWeights)
 			{
-				mTexCoordExtents[0].mV[0] = mVertices[i].mTexCoord.mV[0] ;
+				wght[cur_idx] = mWeights[idx];
 			}
-			if(mTexCoordExtents[1].mV[0] < mVertices[i].mTexCoord.mV[0])
+			if (mBinormals)
 			{
-				mTexCoordExtents[1].mV[0] = mVertices[i].mTexCoord.mV[0] ;
+				binorm[cur_idx] = mBinormals[idx];
 			}
 
-			if(mTexCoordExtents[0].mV[1] > mVertices[i].mTexCoord.mV[1])
-			{
-				mTexCoordExtents[0].mV[1] = mVertices[i].mTexCoord.mV[1] ;
-			}
-			if(mTexCoordExtents[1].mV[1] < mVertices[i].mTexCoord.mV[1])
-			{
-				mTexCoordExtents[1].mV[1] = mVertices[i].mTexCoord.mV[1] ;
-			}			
+			cur_idx++;
 		}
-		mTexCoordExtents[0].mV[0] = llmax(0.f, mTexCoordExtents[0].mV[0]) ;
-		mTexCoordExtents[0].mV[1] = llmax(0.f, mTexCoordExtents[0].mV[1]) ;
-		mTexCoordExtents[1].mV[0] = llmin(1.f, mTexCoordExtents[1].mV[0]) ;
-		mTexCoordExtents[1].mV[1] = llmin(1.f, mTexCoordExtents[1].mV[1]) ;
 	}
 
-	return ret ;
+	for (U32 i = 0; i < mNumIndices; ++i)
+	{
+		mIndices[i] = new_idx[mIndices[i]];
+	}
+	
+	free(mPositions);
+	free(mNormals);
+	free(mTexCoords);
+	free(mWeights);
+	free(mBinormals);
+
+	mPositions = pos;
+	mNormals = norm;
+	mTexCoords = tc;
+	mWeights = wght;
+	mBinormals = binorm;
+
+	//std::string result = llformat("ACMR pre/post: %.3f/%.3f  --  %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
+	//llinfos << result << llendl;
+
+}
+
+void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size)
+{
+	if (mOctree)
+	{
+		return;
+	}
+
+	mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL);
+	new LLVolumeOctreeListener(mOctree);
+
+	for (U32 i = 0; i < mNumIndices; i+= 3)
+	{ //for each triangle
+		LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle();
+				
+		const LLVector4a& v0 = mPositions[mIndices[i]];
+		const LLVector4a& v1 = mPositions[mIndices[i+1]];
+		const LLVector4a& v2 = mPositions[mIndices[i+2]];
+
+		//store pointers to vertex data
+		tri->mV[0] = &v0;
+		tri->mV[1] = &v1;
+		tri->mV[2] = &v2;
+
+		//store indices
+		tri->mIndex[0] = mIndices[i];
+		tri->mIndex[1] = mIndices[i+1];
+		tri->mIndex[2] = mIndices[i+2];
+
+		//get minimum point
+		LLVector4a min = v0;
+		min.setMin(min, v1);
+		min.setMin(min, v2);
+
+		//get maximum point
+		LLVector4a max = v0;
+		max.setMax(max, v1);
+		max.setMax(max, v2);
+
+		//compute center
+		LLVector4a center;
+		center.setAdd(min, max);
+		center.mul(0.5f);
+
+		tri->mPositionGroup = center;
+
+		//compute "radius"
+		LLVector4a size;
+		size.setSub(max,min);
+		
+		tri->mRadius = size.getLength3().getF32() * scaler;
+		
+		//insert
+		mOctree->insert(tri);
+	}
+
+	//remove unneeded octree layers
+	while (!mOctree->balance())	{ }
+
+	//calculate AABB for each node
+	LLVolumeOctreeRebound rebound(this);
+	rebound.traverse(mOctree);
+
+	if (gDebugGL)
+	{
+		LLVolumeOctreeValidate validate;
+		validate.traverse(mOctree);
+	}
+}
+
+
+void LLVolumeFace::swapData(LLVolumeFace& rhs)
+{
+	llswap(rhs.mPositions, mPositions);
+	llswap(rhs.mNormals, mNormals);
+	llswap(rhs.mBinormals, mBinormals);
+	llswap(rhs.mTexCoords, mTexCoords);
+	llswap(rhs.mIndices,mIndices);
+	llswap(rhs.mNumVertices, mNumVertices);
+	llswap(rhs.mNumIndices, mNumIndices);
 }
 
 void	LerpPlanarVertex(LLVolumeFace::VertexData& v0,
@@ -4463,10 +6019,21 @@ void	LerpPlanarVertex(LLVolumeFace::VertexData& v0,
 				   F32	coef01,
 				   F32	coef02)
 {
-	vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02);
+
+	LLVector4a lhs;
+	lhs.setSub(v1.getPosition(), v0.getPosition());
+	lhs.mul(coef01);
+	LLVector4a rhs;
+	rhs.setSub(v2.getPosition(), v0.getPosition());
+	rhs.mul(coef02);
+
+	rhs.add(lhs);
+	rhs.add(v0.getPosition());
+
+	vout.setPosition(rhs);
+		
 	vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02);
-	vout.mNormal = v0.mNormal;
-	vout.mBinormal = v0.mBinormal;
+	vout.setNormal(v0.getNormal());
 }
 
 BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
@@ -4486,84 +6053,113 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 	num_vertices = (grid_size+1)*(grid_size+1);
 	num_indices = quad_count * 4;
 
-	LLVector3& min = mExtents[0];
-	LLVector3& max = mExtents[1];
+	LLVector4a& min = mExtents[0];
+	LLVector4a& max = mExtents[1];
 
 	S32 offset = 0;
 	if (mTypeMask & TOP_MASK)
+	{
 		offset = (max_t-1) * max_s;
+	}
 	else
+	{
 		offset = mBeginS;
+	}
+
+	{
+		VertexData	corners[4];
+		VertexData baseVert;
+		for(S32 t = 0; t < 4; t++)
+		{
+			corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV);
+			corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
+			corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
+		}
+
+		{
+			LLVector4a lhs;
+			lhs.setSub(corners[1].getPosition(), corners[0].getPosition());
+			LLVector4a rhs;
+			rhs.setSub(corners[2].getPosition(), corners[1].getPosition());
+			baseVert.getNormal().setCross3(lhs, rhs); 
+			baseVert.getNormal().normalize3fast();
+		}
+
+		if(!(mTypeMask & TOP_MASK))
+		{
+			baseVert.getNormal().mul(-1.0f);
+		}
+		else
+		{
+			//Swap the UVs on the U(X) axis for top face
+			LLVector2 swap;
+			swap = corners[0].mTexCoord;
+			corners[0].mTexCoord=corners[3].mTexCoord;
+			corners[3].mTexCoord=swap;
+			swap = corners[1].mTexCoord;
+			corners[1].mTexCoord=corners[2].mTexCoord;
+			corners[2].mTexCoord=swap;
+		}
 
-	VertexData	corners[4];
-	VertexData baseVert;
-	for(int t = 0; t < 4; t++){
-		corners[t].mPosition = mesh[offset + (grid_size*t)].mPos;
-		corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
-		corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
-	}
-	baseVert.mNormal = 
-		((corners[1].mPosition-corners[0].mPosition) % 
-		(corners[2].mPosition-corners[1].mPosition));
-	baseVert.mNormal.normVec();
-	if(!(mTypeMask & TOP_MASK)){
-		baseVert.mNormal *= -1.0f;
-	}else{
-		//Swap the UVs on the U(X) axis for top face
-		LLVector2 swap;
-		swap = corners[0].mTexCoord;
-		corners[0].mTexCoord=corners[3].mTexCoord;
-		corners[3].mTexCoord=swap;
-		swap = corners[1].mTexCoord;
-		corners[1].mTexCoord=corners[2].mTexCoord;
-		corners[2].mTexCoord=swap;
-	}
-	baseVert.mBinormal = calc_binormal_from_triangle( 
-		corners[0].mPosition, corners[0].mTexCoord,
-		corners[1].mPosition, corners[1].mTexCoord,
-		corners[2].mPosition, corners[2].mTexCoord);
-	for(int t = 0; t < 4; t++){
-		corners[t].mBinormal = baseVert.mBinormal;
-		corners[t].mNormal = baseVert.mNormal;
-	}
-	mHasBinormals = TRUE;
+		LLVector4a binormal;
+		
+		calc_binormal_from_triangle( binormal,
+			corners[0].getPosition(), corners[0].mTexCoord,
+			corners[1].getPosition(), corners[1].mTexCoord,
+			corners[2].getPosition(), corners[2].mTexCoord);
+		
+		binormal.normalize3fast();
 
-	if (partial_build)
-	{
-		mVertices.clear();
-	}
+		S32 size = (grid_size+1)*(grid_size+1);
+		resizeVertices(size);
+		allocateBinormals(size);
 
-	S32	vtop = mVertices.size();
-	for(int gx = 0;gx<grid_size+1;gx++){
-		for(int gy = 0;gy<grid_size+1;gy++){
-			VertexData newVert;
-			LerpPlanarVertex(
-				corners[0],
-				corners[1],
-				corners[3],
-				newVert,
-				(F32)gx/(F32)grid_size,
-				(F32)gy/(F32)grid_size);
-			mVertices.push_back(newVert);
+		LLVector4a* pos = (LLVector4a*) mPositions;
+		LLVector4a* norm = (LLVector4a*) mNormals;
+		LLVector4a* binorm = (LLVector4a*) mBinormals;
+		LLVector2* tc = (LLVector2*) mTexCoords;
 
-			if (gx == 0 && gy == 0)
-			{
-				min = max = newVert.mPosition;
-			}
-			else
+		for(int gx = 0;gx<grid_size+1;gx++)
+		{
+			for(int gy = 0;gy<grid_size+1;gy++)
 			{
-				update_min_max(min,max,newVert.mPosition);
+				VertexData newVert;
+				LerpPlanarVertex(
+					corners[0],
+					corners[1],
+					corners[3],
+					newVert,
+					(F32)gx/(F32)grid_size,
+					(F32)gy/(F32)grid_size);
+
+				*pos++ = newVert.getPosition();
+				*norm++ = baseVert.getNormal();
+				*tc++ = newVert.mTexCoord;
+				*binorm++ = binormal;
+
+				if (gx == 0 && gy == 0)
+				{
+					min = newVert.getPosition();
+					max = min;
+				}
+				else
+				{
+					min.setMin(min, newVert.getPosition());
+					max.setMax(max, newVert.getPosition());
+				}
 			}
 		}
-	}
 	
-	mCenter = (min + max) * 0.5f;
+		mCenter->setAdd(min, max);
+		mCenter->mul(0.5f); 
+	}
 
 	if (!partial_build)
 	{
-#if GEN_TRI_STRIP
-		mTriStrip.clear();
-#endif
+		resizeIndices(grid_size*grid_size*6);
+
+		U16* out = mIndices;
+
 		S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
 		for(S32 gx = 0;gx<grid_size;gx++)
 		{
@@ -4574,61 +6170,18 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 				{
 					for(S32 i=5;i>=0;i--)
 					{
-						mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
-					}
-					
-#if GEN_TRI_STRIP
-					if (gy == 0)
-					{
-						mTriStrip.push_back((gx+1)*(grid_size+1));
-						mTriStrip.push_back((gx+1)*(grid_size+1));
-						mTriStrip.push_back(gx*(grid_size+1));
-					}
-
-					mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
-					mTriStrip.push_back(gy+1+gx*(grid_size+1));
-					
-					
-					if (gy == grid_size-1)
-					{
-						mTriStrip.push_back(gy+1+gx*(grid_size+1));
-					}
-#endif
+						*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
+					}		
 				}
 				else
 				{
 					for(S32 i=0;i<6;i++)
 					{
-						mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
-					}
-
-#if GEN_TRI_STRIP
-					if (gy == 0)
-					{
-						mTriStrip.push_back(gx*(grid_size+1));
-						mTriStrip.push_back(gx*(grid_size+1));
-						mTriStrip.push_back((gx+1)*(grid_size+1));
-					}
-
-					mTriStrip.push_back(gy+1+gx*(grid_size+1));
-					mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
-					
-					if (gy == grid_size-1)
-					{
-						mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
+						*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
 					}
-#endif
 				}
-			}
-			
-		}
-
-#if GEN_TRI_STRIP
-		if (mTriStrip.size()%2 == 1)
-		{
-			mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
+			}	
 		}
-#endif
 	}
 		
 	return TRUE;
@@ -4658,17 +6211,31 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 	num_vertices = profile.size();
 	num_indices = (profile.size() - 2)*3;
 
-	mVertices.resize(num_vertices);
+	if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
+	{
+		resizeVertices(num_vertices+1);
+		allocateBinormals(num_vertices+1);	
 
-	if (!partial_build)
+		if (!partial_build)
+		{
+			resizeIndices(num_indices+3);
+		}
+	}
+	else
 	{
-		mIndices.resize(num_indices);
+		resizeVertices(num_vertices);
+		allocateBinormals(num_vertices);
+
+		if (!partial_build)
+		{
+			resizeIndices(num_indices);
+		}
 	}
 
 	S32 max_s = volume->getProfile().getTotal();
 	S32 max_t = volume->getPath().mPath.size();
 
-	mCenter.clearVec();
+	mCenter->clear();
 
 	S32 offset = 0;
 	if (mTypeMask & TOP_MASK)
@@ -4686,82 +6253,91 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 	LLVector2 cuv;
 	LLVector2 min_uv, max_uv;
 
-	LLVector3& min = mExtents[0];
-	LLVector3& max = mExtents[1];
+	LLVector4a& min = mExtents[0];
+	LLVector4a& max = mExtents[1];
+
+	LLVector2* tc = (LLVector2*) mTexCoords;
+	LLVector4a* pos = (LLVector4a*) mPositions;
+	LLVector4a* norm = (LLVector4a*) mNormals;
+	LLVector4a* binorm = (LLVector4a*) mBinormals;
 
 	// Copy the vertices into the array
 	for (S32 i = 0; i < num_vertices; i++)
 	{
 		if (mTypeMask & TOP_MASK)
 		{
-			mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
-			mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f;
+			tc[i].mV[0] = profile[i].mV[0]+0.5f;
+			tc[i].mV[1] = profile[i].mV[1]+0.5f;
 		}
 		else
 		{
 			// Mirror for underside.
-			mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
-			mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1];
+			tc[i].mV[0] = profile[i].mV[0]+0.5f;
+			tc[i].mV[1] = 0.5f - profile[i].mV[1];
 		}
 
-		mVertices[i].mPosition = mesh[i + offset].mPos;
+		pos[i].load3(mesh[i + offset].mPos.mV);
 		
 		if (i == 0)
 		{
-			min = max = mVertices[i].mPosition;
-			min_uv = max_uv = mVertices[i].mTexCoord;
+			max = pos[i];
+			min = max;
+			min_uv = max_uv = tc[i];
 		}
 		else
 		{
-			update_min_max(min,max, mVertices[i].mPosition);
-			update_min_max(min_uv, max_uv, mVertices[i].mTexCoord);
+			update_min_max(min,max,pos[i]);
+			update_min_max(min_uv, max_uv, tc[i]);
 		}
 	}
 
-	mCenter = (min+max)*0.5f;
+	mCenter->setAdd(min, max);
+	mCenter->mul(0.5f); 
+
 	cuv = (min_uv + max_uv)*0.5f;
 
-	LLVector3 binormal = calc_binormal_from_triangle( 
-		mCenter, cuv,
-		mVertices[0].mPosition, mVertices[0].mTexCoord,
-		mVertices[1].mPosition, mVertices[1].mTexCoord);
-	binormal.normVec();
+	LLVector4a binormal;
+	calc_binormal_from_triangle(binormal,
+		*mCenter, cuv,
+		pos[0], tc[0],
+		pos[1], tc[1]);
+	binormal.normalize3fast();
+
+	LLVector4a normal;
+	LLVector4a d0, d1;
+	
 
-	LLVector3 d0;
-	LLVector3 d1;
-	LLVector3 normal;
+	d0.setSub(*mCenter, pos[0]);
+	d1.setSub(*mCenter, pos[1]);
 
-	d0 = mCenter-mVertices[0].mPosition;
-	d1 = mCenter-mVertices[1].mPosition;
+	if (mTypeMask & TOP_MASK)
+	{
+		normal.setCross3(d0, d1);
+	}
+	else
+	{
+		normal.setCross3(d1, d0);
+	}
 
-	normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0);
-	normal.normVec();
+	normal.normalize3fast();
 
 	VertexData vd;
-	vd.mPosition = mCenter;
-	vd.mNormal = normal;
-	vd.mBinormal = binormal;
+	vd.setPosition(*mCenter);
 	vd.mTexCoord = cuv;
 	
 	if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
 	{
-		mVertices.push_back(vd);
+		pos[num_vertices] = *mCenter;
+		tc[num_vertices] = cuv;
 		num_vertices++;
-		if (!partial_build)
-		{
-			vector_append(mIndices, 3);
-		}
 	}
 		
-	
 	for (S32 i = 0; i < num_vertices; i++)
 	{
-		mVertices[i].mBinormal = binormal;
-		mVertices[i].mNormal = normal;
+		binorm[i].load4a(binormal.getF32ptr());
+		norm[i].load4a(normal.getF32ptr());
 	}
 
-	mHasBinormals = TRUE;
-
 	if (partial_build)
 	{
 		return TRUE;
@@ -4869,8 +6445,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 					pt2--;
 				}
 			}
-
-			makeTriStrip();
 		}
 		else
 		{
@@ -4975,8 +6549,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 					pt2--;
 				}
 			}
-
-			makeTriStrip();
 		}
 	}
 	else
@@ -4998,131 +6570,277 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 			mIndices[3*i+v2] = i + 1;
 		}
 
-#if GEN_TRI_STRIP
-		//make tri strip
-		if (mTypeMask & OPEN_MASK)
-		{
-			makeTriStrip();
-		}
-		else
-		{
-			S32 j = num_vertices-2;
-			if (mTypeMask & TOP_MASK)
-			{
-				mTriStrip.push_back(0);
-				for (S32 i = 0; i <= j; ++i)
-				{
-					mTriStrip.push_back(i);
-					if (i != j)
-					{
-						mTriStrip.push_back(j);
-					}
-					--j;
-				}
-			}
-			else
-			{
-				mTriStrip.push_back(j);
-				for (S32 i = 0; i <= j; ++i)
-				{
-					if (i != j)
-					{
-						mTriStrip.push_back(j);
-					}
-					mTriStrip.push_back(i);
-					--j;
-				}
-			}
-			
-			mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
 
-			if (mTriStrip.size()%2 == 1)
-			{
-				mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
-			}
-		}
-#endif
 	}
 		
 	return TRUE;
 }
 
-void LLVolumeFace::makeTriStrip()
+void LLVolumeFace::createBinormals()
 {
-#if GEN_TRI_STRIP
-	for (U32 i = 0; i < mIndices.size(); i+=3)
+	LLMemType m1(LLMemType::MTYPE_VOLUME);
+	
+	if (!mBinormals)
 	{
-		U16 i0 = mIndices[i];
-		U16 i1 = mIndices[i+1];
-		U16 i2 = mIndices[i+2];
+		allocateBinormals(mNumVertices);
 
-		if ((i/3)%2 == 1)
-		{
-			mTriStrip.push_back(i0);
-			mTriStrip.push_back(i0);
-			mTriStrip.push_back(i1);
-			mTriStrip.push_back(i2);
-			mTriStrip.push_back(i2);
-		}
-		else
+		//generate binormals
+		LLVector4a* pos = mPositions;
+		LLVector2* tc = (LLVector2*) mTexCoords;
+		LLVector4a* binorm = (LLVector4a*) mBinormals;
+
+		LLVector4a* end = mBinormals+mNumVertices;
+		while (binorm < end)
 		{
-			mTriStrip.push_back(i2);
-			mTriStrip.push_back(i2);
-			mTriStrip.push_back(i1);
-			mTriStrip.push_back(i0);
-			mTriStrip.push_back(i0);
+			(*binorm++).clear();
 		}
-	}
 
-	if (mTriStrip.size()%2 == 1)
-	{
-		mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
-	}
-#endif
-}
+		binorm = mBinormals;
 
-void LLVolumeFace::createBinormals()
-{
-	LLMemType m1(LLMemType::MTYPE_VOLUME);
-	
-	if (!mHasBinormals)
-	{
-		//generate binormals
-		for (U32 i = 0; i < mIndices.size()/3; i++) 
+		for (U32 i = 0; i < mNumIndices/3; i++) 
 		{	//for each triangle
-			const VertexData& v0 = mVertices[mIndices[i*3+0]];
-			const VertexData& v1 = mVertices[mIndices[i*3+1]];
-			const VertexData& v2 = mVertices[mIndices[i*3+2]];
+			const U16& i0 = mIndices[i*3+0];
+			const U16& i1 = mIndices[i*3+1];
+			const U16& i2 = mIndices[i*3+2];
 						
 			//calculate binormal
-			LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord,
-															v1.mPosition, v1.mTexCoord,
-															v2.mPosition, v2.mTexCoord);
+			LLVector4a binormal;
+			calc_binormal_from_triangle(binormal,
+										pos[i0], tc[i0],
+										pos[i1], tc[i1],
+										pos[i2], tc[i2]);
 
-			for (U32 j = 0; j < 3; j++) 
-			{ //add triangle normal to vertices
-				mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum;
-			}
+
+			//add triangle normal to vertices
+			binorm[i0].add(binormal);
+			binorm[i1].add(binormal);
+			binorm[i2].add(binormal);
 
 			//even out quad contributions
 			if (i % 2 == 0) 
 			{
-				mVertices[mIndices[i*3+2]].mBinormal += binorm;
+				binorm[i2].add(binormal);
 			}
 			else 
 			{
-				mVertices[mIndices[i*3+1]].mBinormal += binorm;
+				binorm[i1].add(binormal);
 			}
 		}
 
 		//normalize binormals
-		for (U32 i = 0; i < mVertices.size(); i++) 
+		for (U32 i = 0; i < mNumVertices; i++) 
+		{
+			binorm[i].normalize3fast();
+			//bump map/planar projection code requires normals to be normalized
+			mNormals[i].normalize3fast();
+		}
+	}
+}
+
+void LLVolumeFace::resizeVertices(S32 num_verts)
+{
+	free(mPositions);
+	free(mNormals);
+	free(mBinormals);
+	free(mTexCoords);
+
+	mBinormals = NULL;
+
+	if (num_verts)
+	{
+		mPositions = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+		assert_aligned(mPositions, 16);
+		mNormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+		assert_aligned(mNormals, 16);
+
+		//pad texture coordinate block end to allow for QWORD reads
+		S32 size = ((num_verts*sizeof(LLVector2)) + 0xF) & ~0xF;
+		mTexCoords = (LLVector2*) malloc(size);
+		assert_aligned(mTexCoords, 16);
+	}
+	else
+	{
+		mPositions = NULL;
+		mNormals = NULL;
+		mTexCoords = NULL;
+	}
+
+	mNumVertices = num_verts;
+}
+
+void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
+{
+	pushVertex(cv.getPosition(), cv.getNormal(), cv.mTexCoord);
+}
+
+void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc)
+{
+	S32 new_verts = mNumVertices+1;
+	S32 new_size = new_verts*16;
+//	S32 old_size = mNumVertices*16;
+
+	//positions
+	mPositions = (LLVector4a*) realloc(mPositions, new_size);
+	
+	//normals
+	mNormals = (LLVector4a*) realloc(mNormals, new_size);
+	
+	//tex coords
+	new_size = ((new_verts*8)+0xF) & ~0xF;
+	mTexCoords = (LLVector2*) realloc(mTexCoords, new_size);
+	
+
+	//just clear binormals
+	free(mBinormals);
+	mBinormals = NULL;
+
+	mPositions[mNumVertices] = pos;
+	mNormals[mNumVertices] = norm;
+	mTexCoords[mNumVertices] = tc;
+
+	mNumVertices++;	
+}
+
+void LLVolumeFace::allocateBinormals(S32 num_verts)
+{
+	free(mBinormals);
+	mBinormals = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+}
+
+void LLVolumeFace::allocateWeights(S32 num_verts)
+{
+	free(mWeights);
+	mWeights = (LLVector4a*) malloc(sizeof(LLVector4a)*num_verts);
+}
+
+void LLVolumeFace::resizeIndices(S32 num_indices)
+{
+	free(mIndices);
+	
+	if (num_indices)
+	{
+		//pad index block end to allow for QWORD reads
+		S32 size = ((num_indices*sizeof(U16)) + 0xF) & ~0xF;
+		
+		mIndices = (U16*) malloc(size);
+	}
+	else
+	{
+		mIndices = NULL;
+	}
+
+	mNumIndices = num_indices;
+}
+
+void LLVolumeFace::pushIndex(const U16& idx)
+{
+	S32 new_count = mNumIndices + 1;
+	S32 new_size = ((new_count*2)+0xF) & ~0xF;
+
+	S32 old_size = ((mNumIndices*2)+0xF) & ~0xF;
+	if (new_size != old_size)
+	{
+		mIndices = (U16*) realloc(mIndices, new_size);
+	}
+	
+	mIndices[mNumIndices++] = idx;
+}
+
+void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx)
+{
+	resizeVertices(v.size());
+	resizeIndices(idx.size());
+
+	for (U32 i = 0; i < v.size(); ++i)
+	{
+		mPositions[i] = v[i].getPosition();
+		mNormals[i] = v[i].getNormal();
+		mTexCoords[i] = v[i].mTexCoord;
+	}
+
+	for (U32 i = 0; i < idx.size(); ++i)
+	{
+		mIndices[i] = idx[i];
+	}
+}
+
+void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in)
+{
+	U16 offset = mNumVertices;
+
+	S32 new_count = face.mNumVertices + mNumVertices;
+
+	if (new_count > 65536)
+	{
+		llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl;
+	}
+	
+	if (face.mNumVertices == 0)
+	{
+		llerrs << "Cannot append empty face." << llendl;
+	}
+
+	//allocate new buffer space
+	mPositions = (LLVector4a*) realloc(mPositions, new_count*sizeof(LLVector4a));
+	assert_aligned(mPositions, 16);
+	mNormals = (LLVector4a*) realloc(mNormals, new_count*sizeof(LLVector4a));
+	assert_aligned(mNormals, 16);
+	mTexCoords = (LLVector2*) realloc(mTexCoords, (new_count*sizeof(LLVector2)+0xF) & ~0xF);
+	assert_aligned(mTexCoords, 16);
+	
+	mNumVertices = new_count;
+
+	//get destination address of appended face
+	LLVector4a* dst_pos = mPositions+offset;
+	LLVector2* dst_tc = mTexCoords+offset;
+	LLVector4a* dst_norm = mNormals+offset;
+
+	//get source addresses of appended face
+	const LLVector4a* src_pos = face.mPositions;
+	const LLVector2* src_tc = face.mTexCoords;
+	const LLVector4a* src_norm = face.mNormals;
+
+	//load aligned matrices
+	LLMatrix4a mat, norm_mat;
+	mat.loadu(mat_in);
+	norm_mat.loadu(norm_mat_in);
+
+	for (U32 i = 0; i < face.mNumVertices; ++i)
+	{
+		//transform appended face position and store
+		mat.affineTransform(src_pos[i], dst_pos[i]);
+
+		//transform appended face normal and store
+		norm_mat.rotate(src_norm[i], dst_norm[i]);
+		dst_norm[i].normalize3fast();
+
+		//copy appended face texture coordinate
+		dst_tc[i] = src_tc[i];
+
+		if (offset == 0 && i == 0)
+		{ //initialize bounding box
+			mExtents[0] = mExtents[1] = dst_pos[i];
+		}
+		else
 		{
-			mVertices[i].mBinormal.normVec();
-			mVertices[i].mNormal.normVec();
+			//stretch bounding box
+			update_min_max(mExtents[0], mExtents[1], dst_pos[i]);
 		}
+	}
+
 
-		mHasBinormals = TRUE;
+	new_count = mNumIndices + face.mNumIndices;
+
+	//allocate new index buffer
+	mIndices = (U16*) realloc(mIndices, (new_count*sizeof(U16)+0xF) & ~0xF);
+	
+	//get destination address into new index buffer
+	U16* dst_idx = mIndices+mNumIndices;
+	mNumIndices = new_count;
+
+	for (U32 i = 0; i < face.mNumIndices; ++i)
+	{ //copy indices, offsetting by old vertex count
+		dst_idx[i] = face.mIndices[i]+offset;
 	}
 }
 
@@ -5152,18 +6870,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 	num_vertices = mNumS*mNumT;
 	num_indices = (mNumS-1)*(mNumT-1)*6;
 
-	mVertices.resize(num_vertices);
-
 	if (!partial_build)
 	{
-		mIndices.resize(num_indices);
-		mEdge.resize(num_indices);
-	}
-	else
-	{
-		mHasBinormals = FALSE;
+		resizeVertices(num_vertices);
+		resizeIndices(num_indices);
+
+		if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
+		{
+			mEdge.resize(num_indices);
+		}
 	}
 
+	LLVector4a* pos = (LLVector4a*) mPositions;
+	LLVector4a* norm = (LLVector4a*) mNormals;
+	LLVector2* tc = (LLVector2*) mTexCoords;
 	S32 begin_stex = llfloor( profile[mBeginS].mV[2] );
 	S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS;
 
@@ -5214,21 +6934,20 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 				i = mBeginS + s + max_s*t;
 			}
 
-			mVertices[cur_vertex].mPosition = mesh[i].mPos;
-			mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
+			pos[cur_vertex].load3(mesh[i].mPos.mV);
+			tc[cur_vertex] = LLVector2(ss,tt);
 		
-			mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
-			mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
-
+			norm[cur_vertex].clear();
 			cur_vertex++;
 
 			if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0)
 			{
-				mVertices[cur_vertex].mPosition = mesh[i].mPos;
-				mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
+
+				pos[cur_vertex].load3(mesh[i].mPos.mV);
+				tc[cur_vertex] = LLVector2(ss,tt);
 			
-				mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
-				mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
+				norm[cur_vertex].clear();
+				
 				cur_vertex++;
 			}
 		}
@@ -5246,29 +6965,29 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 			i = mBeginS + s + max_s*t;
 			ss = profile[mBeginS + s].mV[2] - begin_stex;
-			mVertices[cur_vertex].mPosition = mesh[i].mPos;
-			mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
-		
-			mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
-			mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
-
+			pos[cur_vertex].load3(mesh[i].mPos.mV);
+			tc[cur_vertex] = LLVector2(ss,tt);
+			norm[cur_vertex].clear(); 
+			
 			cur_vertex++;
 		}
 	}
 	
 
 	//get bounding box for this side
-	LLVector3& face_min = mExtents[0];
-	LLVector3& face_max = mExtents[1];
-	mCenter.clearVec();
+	LLVector4a& face_min = mExtents[0];
+	LLVector4a& face_max = mExtents[1];
+	mCenter->clear();
 
-	face_min = face_max = mVertices[0].mPosition;
-	for (U32 i = 1; i < mVertices.size(); ++i)
+	face_min = face_max = pos[0];
+
+	for (U32 i = 1; i < mNumVertices; ++i)
 	{
-		update_min_max(face_min, face_max, mVertices[i].mPosition);
+		update_min_max(face_min, face_max, pos[i]);
 	}
 
-	mCenter = (face_min + face_max) * 0.5f;
+	mCenter->setAdd(face_min, face_max);
+	mCenter->mul(0.5f);
 
 	S32 cur_index = 0;
 	S32 cur_edge = 0;
@@ -5276,18 +6995,9 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 	if (!partial_build)
 	{
-#if GEN_TRI_STRIP
-		mTriStrip.clear();
-#endif
-
 		// Now we generate the indices.
 		for (t = 0; t < (mNumT-1); t++)
 		{
-#if GEN_TRI_STRIP
-			//prepend terminating index to strip
-			mTriStrip.push_back(mNumS*t);
-#endif
-
 			for (s = 0; s < (mNumS-1); s++)
 			{	
 				mIndices[cur_index++] = s   + mNumS*t;			//bottom left
@@ -5297,16 +7007,6 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 				mIndices[cur_index++] = s+1 + mNumS*t;			//bottom right
 				mIndices[cur_index++] = s+1 + mNumS*(t+1);		//top right
 
-#if GEN_TRI_STRIP
-				if (s == 0)
-				{
-					mTriStrip.push_back(s+mNumS*t);
-					mTriStrip.push_back(s+mNumS*(t+1));
-				}
-				mTriStrip.push_back(s+1+mNumS*t);
-				mTriStrip.push_back(s+1+mNumS*(t+1));
-#endif
-				
 				mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1;						//bottom left/top right neighbor face 
 				if (t < mNumT-2) {												//top right/top left neighbor face 
 					mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
@@ -5347,52 +7047,61 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 				}
 				mEdge[cur_edge++] = (mNumS-1)*2*t+s*2;							//top right/bottom left neighbor face	
 			}
-#if GEN_TRI_STRIP
-			//append terminating vertex to strip
-			mTriStrip.push_back(mNumS-1+mNumS*(t+1));
-#endif
 		}
+	}
 
-#if GEN_TRI_STRIP
-		if (mTriStrip.size()%2 == 1)
-		{
-			mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
-		}
-#endif
+	//clear normals
+	for (U32 i = 0; i < mNumVertices; i++)
+	{
+		mNormals[i].clear();
 	}
 
 	//generate normals 
-	for (U32 i = 0; i < mIndices.size()/3; i++) //for each triangle
+	for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle
 	{
 		const U16* idx = &(mIndices[i*3]);
-			
-		VertexData* v[] = 
-		{	&mVertices[idx[0]], &mVertices[idx[1]], &mVertices[idx[2]] };
-					
-		//calculate triangle normal
-		LLVector3 norm = (v[0]->mPosition-v[1]->mPosition) % (v[0]->mPosition-v[2]->mPosition);
+		
 
-		v[0]->mNormal += norm;
-		v[1]->mNormal += norm;
-		v[2]->mNormal += norm;
+		LLVector4a* v[] = 
+		{	pos+idx[0], pos+idx[1], pos+idx[2] };
+		
+		LLVector4a* n[] = 
+		{	norm+idx[0], norm+idx[1], norm+idx[2] };
+		
+		//calculate triangle normal
+		LLVector4a a, b, c;
+		
+		a.setSub(*v[0], *v[1]);
+		b.setSub(*v[0], *v[2]);
+		c.setCross3(a,b);
 
+		n[0]->add(c);
+		n[1]->add(c);
+		n[2]->add(c);
+		
 		//even out quad contributions
-		v[i%2+1]->mNormal += norm;
+		n[i%2+1]->add(c);
 	}
 	
 	// adjust normals based on wrapping and stitching
 	
-	BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f);
-	BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f);
+	LLVector4a top;
+	top.setSub(pos[0], pos[mNumS*(mNumT-2)]);
+	BOOL s_bottom_converges = (top.dot3(top) < 0.000001f);
+
+	top.setSub(pos[mNumS-1], pos[mNumS*(mNumT-2)+mNumS-1]);
+	BOOL s_top_converges = (top.dot3(top) < 0.000001f);
+
 	if (sculpt_stitching == LL_SCULPT_TYPE_NONE)  // logic for non-sculpt volumes
 	{
 		if (volume->getPath().isOpen() == FALSE)
 		{ //wrap normals on T
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
-				mVertices[i].mNormal = norm;
-				mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
+				LLVector4a n;
+				n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+				norm[i] = n;
+				norm[mNumS*(mNumT-1)+i] = n;
 			}
 		}
 
@@ -5400,9 +7109,10 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		{ //wrap normals on S
 			for (S32 i = 0; i < mNumT; i++)
 			{
-				LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
-				mVertices[mNumS * i].mNormal = norm;
-				mVertices[mNumS * i+mNumS-1].mNormal = norm;
+				LLVector4a n;
+				n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+				norm[mNumS * i] = n;
+				norm[mNumS * i+mNumS-1] = n;
 			}
 		}
 	
@@ -5413,7 +7123,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 			{ //all lower S have same normal
 				for (S32 i = 0; i < mNumT; i++)
 				{
-					mVertices[mNumS*i].mNormal = LLVector3(1,0,0);
+					norm[mNumS*i].set(1,0,0);
 				}
 			}
 
@@ -5421,12 +7131,11 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 			{ //all upper S have same normal
 				for (S32 i = 0; i < mNumT; i++)
 				{
-					mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0);
+					norm[mNumS*i+mNumS-1].set(-1,0,0);
 				}
 			}
 		}
 	}
-	
 	else  // logic for sculpt volumes
 	{
 		BOOL average_poles = FALSE;
@@ -5449,30 +7158,33 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		{
 			// average normals for north pole
 		
-			LLVector3 average(0.0, 0.0, 0.0);
+			LLVector4a average;
+			average.clear();
+
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				average += mVertices[i].mNormal;
+				average.add(norm[i]);
 			}
 
 			// set average
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				mVertices[i].mNormal = average;
+				norm[i] = average;
 			}
 
 			// average normals for south pole
 		
-			average = LLVector3(0.0, 0.0, 0.0);
+			average.clear();
+
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				average += mVertices[i + mNumS * (mNumT - 1)].mNormal;
+				average.add(norm[i + mNumS * (mNumT - 1)]);
 			}
 
 			// set average
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				mVertices[i + mNumS * (mNumT - 1)].mNormal = average;
+				norm[i + mNumS * (mNumT - 1)] = average;
 			}
 
 		}
@@ -5482,23 +7194,22 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		{
 			for (S32 i = 0; i < mNumT; i++)
 			{
-				LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
-				mVertices[mNumS * i].mNormal = norm;
-				mVertices[mNumS * i+mNumS-1].mNormal = norm;
+				LLVector4a n;
+				n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+				norm[mNumS * i] = n;
+				norm[mNumS * i+mNumS-1] = n;
 			}
 		}
 
-
-		
 		if (wrap_t)
 		{
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
-				mVertices[i].mNormal = norm;
-				mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
+				LLVector4a n;
+				n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+				norm[i] = n;
+				norm[mNumS*(mNumT-1)+i] = n;
 			}
-			
 		}
 
 	}
@@ -5508,41 +7219,51 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 // Finds binormal based on three vertices with texture coordinates.
 // Fills in dummy values if the triangle has degenerate texture coordinates.
-LLVector3 calc_binormal_from_triangle( 
-	const LLVector3& pos0,
+void calc_binormal_from_triangle(LLVector4a& binormal,
+
+	const LLVector4a& pos0,
 	const LLVector2& tex0,
-	const LLVector3& pos1,
+	const LLVector4a& pos1,
 	const LLVector2& tex1,
-	const LLVector3& pos2,
+	const LLVector4a& pos2,
 	const LLVector2& tex2)
 {
-	LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] );
-	LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] );
-	LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] );
+	LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] );
+	LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] );
+	LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] );
 	
-	LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] );
-	LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] );
-	LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] );
+	LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] );
+	LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] );
+	LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] );
 
-	LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] );
-	LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] );
-	LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] );
+	LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] );
+	LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] );
+	LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] );
 	
-	LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2);
-	LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2);
-	LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2);
+	LLVector4a lhs, rhs;
+
+	LLVector4a r0; 
+	lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2);
+	r0.setCross3(lhs, rhs);
+		
+	LLVector4a r1;
+	lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2);
+	r1.setCross3(lhs, rhs);
+
+	LLVector4a r2;
+	lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2);
+	r2.setCross3(lhs, rhs);
 
-	if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] )
+	if( r0[VX] && r1[VX] && r2[VX] )
 	{
-		LLVector3 binormal(
-				-r0.mV[VZ] / r0.mV[VX],
-				-r1.mV[VZ] / r1.mV[VX],
-				-r2.mV[VZ] / r2.mV[VX]);
+		binormal.set(
+				-r0[VZ] / r0[VX],
+				-r1[VZ] / r1[VX],
+				-r2[VZ] / r2[VX]);
 		// binormal.normVec();
-		return binormal;
 	}
 	else
 	{
-		return LLVector3( 0, 1 , 0 );
+		binormal.set( 0, 1 , 0 );
 	}
 }
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 4a25f586da..eceaced9e2 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -1,1106 +1,1106 @@
-/** 
- * @file llvolume.h
- * @brief LLVolume base class.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLVOLUME_H
-#define LL_LLVOLUME_H
-
-#include <iostream>
-
-class LLProfileParams;
-class LLPathParams;
-class LLVolumeParams;
-class LLProfile;
-class LLPath;
-
-template <class T> class LLOctreeNode;
-
-class LLVector4a;
-class LLVolumeFace;
-class LLVolume;
-class LLVolumeTriangle;
-
-#include "lldarray.h"
-#include "lluuid.h"
-#include "v4color.h"
-//#include "vmath.h"
-#include "v2math.h"
-#include "v3math.h"
-#include "v3dmath.h"
-#include "v4math.h"
-#include "llquaternion.h"
-#include "llstrider.h"
-#include "v4coloru.h"
-#include "llrefcount.h"
-#include "llfile.h"
-
-//============================================================================
-
-const S32 MIN_DETAIL_FACES = 6;
-const S32 MIN_LOD = 0;
-const S32 MAX_LOD = 3;
-
-// These are defined here but are not enforced at this level,
-// rather they are here for the convenience of code that uses
-// the LLVolume class.
-const F32 MIN_VOLUME_PROFILE_WIDTH 	= 0.05f;
-const F32 MIN_VOLUME_PATH_WIDTH 	= 0.05f;
-
-const F32 CUT_QUANTA    = 0.00002f;
-const F32 SCALE_QUANTA  = 0.01f;
-const F32 SHEAR_QUANTA  = 0.01f;
-const F32 TAPER_QUANTA  = 0.01f;
-const F32 REV_QUANTA    = 0.015f;
-const F32 HOLLOW_QUANTA = 0.00002f;
-
-const S32 MAX_VOLUME_TRIANGLE_INDICES = 10000;
-
-//============================================================================
-
-// useful masks
-const LLPCode LL_PCODE_HOLLOW_MASK 	= 0x80;		// has a thickness
-const LLPCode LL_PCODE_SEGMENT_MASK = 0x40;		// segments (1 angle)
-const LLPCode LL_PCODE_PATCH_MASK 	= 0x20;		// segmented segments (2 angles)
-const LLPCode LL_PCODE_HEMI_MASK 	= 0x10;		// half-primitives get their own type per PR's dictum
-const LLPCode LL_PCODE_BASE_MASK 	= 0x0F;
-
-	// primitive shapes
-const LLPCode	LL_PCODE_CUBE 			= 1;
-const LLPCode	LL_PCODE_PRISM 			= 2;
-const LLPCode	LL_PCODE_TETRAHEDRON 	= 3;
-const LLPCode	LL_PCODE_PYRAMID 		= 4;
-const LLPCode	LL_PCODE_CYLINDER 		= 5;
-const LLPCode	LL_PCODE_CONE 			= 6;
-const LLPCode	LL_PCODE_SPHERE 		= 7;
-const LLPCode	LL_PCODE_TORUS 			= 8;
-const LLPCode	LL_PCODE_VOLUME			= 9;
-
-	// surfaces
-//const LLPCode	LL_PCODE_SURFACE_TRIANGLE 	= 10;
-//const LLPCode	LL_PCODE_SURFACE_SQUARE 	= 11;
-//const LLPCode	LL_PCODE_SURFACE_DISC 		= 12;
-
-const LLPCode	LL_PCODE_APP				= 14; // App specific pcode (for viewer/sim side only objects)
-const LLPCode	LL_PCODE_LEGACY				= 15;
-
-// Pcodes for legacy objects
-//const LLPCode	LL_PCODE_LEGACY_ATOR =				0x10 | LL_PCODE_LEGACY; // ATOR
-const LLPCode	LL_PCODE_LEGACY_AVATAR =			0x20 | LL_PCODE_LEGACY; // PLAYER
-//const LLPCode	LL_PCODE_LEGACY_BIRD =				0x30 | LL_PCODE_LEGACY; // BIRD
-//const LLPCode	LL_PCODE_LEGACY_DEMON =				0x40 | LL_PCODE_LEGACY; // DEMON
-const LLPCode	LL_PCODE_LEGACY_GRASS =				0x50 | LL_PCODE_LEGACY; // GRASS
-const LLPCode	LL_PCODE_TREE_NEW =					0x60 | LL_PCODE_LEGACY; // new trees
-//const LLPCode	LL_PCODE_LEGACY_ORACLE =			0x70 | LL_PCODE_LEGACY; // ORACLE
-const LLPCode	LL_PCODE_LEGACY_PART_SYS =			0x80 | LL_PCODE_LEGACY; // PART_SYS
-const LLPCode	LL_PCODE_LEGACY_ROCK =				0x90 | LL_PCODE_LEGACY; // ROCK
-//const LLPCode	LL_PCODE_LEGACY_SHOT =				0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT
-//const LLPCode	LL_PCODE_LEGACY_SHOT_BIG =			0xB0 | LL_PCODE_LEGACY;
-//const LLPCode	LL_PCODE_LEGACY_SMOKE =				0xC0 | LL_PCODE_LEGACY; // SMOKE
-//const LLPCode	LL_PCODE_LEGACY_SPARK =				0xD0 | LL_PCODE_LEGACY;// SPARK
-const LLPCode	LL_PCODE_LEGACY_TEXT_BUBBLE =		0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE
-const LLPCode	LL_PCODE_LEGACY_TREE =				0xF0 | LL_PCODE_LEGACY; // TREE
-
-	// hemis
-const LLPCode	LL_PCODE_CYLINDER_HEMI =		LL_PCODE_CYLINDER	| LL_PCODE_HEMI_MASK;
-const LLPCode	LL_PCODE_CONE_HEMI =			LL_PCODE_CONE		| LL_PCODE_HEMI_MASK;
-const LLPCode	LL_PCODE_SPHERE_HEMI =			LL_PCODE_SPHERE		| LL_PCODE_HEMI_MASK;
-const LLPCode	LL_PCODE_TORUS_HEMI =			LL_PCODE_TORUS		| LL_PCODE_HEMI_MASK;
-
-
-// Volumes consist of a profile at the base that is swept around
-// a path to make a volume.
-// The profile code
-const U8	LL_PCODE_PROFILE_MASK		= 0x0f;
-const U8	LL_PCODE_PROFILE_MIN		= 0x00;
-const U8    LL_PCODE_PROFILE_CIRCLE		= 0x00;
-const U8    LL_PCODE_PROFILE_SQUARE		= 0x01;
-const U8	LL_PCODE_PROFILE_ISOTRI		= 0x02;
-const U8    LL_PCODE_PROFILE_EQUALTRI	= 0x03;
-const U8    LL_PCODE_PROFILE_RIGHTTRI	= 0x04;
-const U8	LL_PCODE_PROFILE_CIRCLE_HALF = 0x05;
-const U8	LL_PCODE_PROFILE_MAX		= 0x05;
-
-// Stored in the profile byte
-const U8	LL_PCODE_HOLE_MASK		= 0xf0;
-const U8	LL_PCODE_HOLE_MIN		= 0x00;	  
-const U8	LL_PCODE_HOLE_SAME		= 0x00;		// same as outside profile
-const U8	LL_PCODE_HOLE_CIRCLE	= 0x10;
-const U8	LL_PCODE_HOLE_SQUARE	= 0x20;
-const U8	LL_PCODE_HOLE_TRIANGLE	= 0x30;
-const U8	LL_PCODE_HOLE_MAX		= 0x03;		// min/max needs to be >> 4 of real min/max
-
-const U8    LL_PCODE_PATH_IGNORE    = 0x00;
-const U8	LL_PCODE_PATH_MIN		= 0x01;		// min/max needs to be >> 4 of real min/max
-const U8    LL_PCODE_PATH_LINE      = 0x10;
-const U8    LL_PCODE_PATH_CIRCLE    = 0x20;
-const U8    LL_PCODE_PATH_CIRCLE2   = 0x30;
-const U8    LL_PCODE_PATH_TEST      = 0x40;
-const U8    LL_PCODE_PATH_FLEXIBLE  = 0x80;
-const U8	LL_PCODE_PATH_MAX		= 0x08;
-
-//============================================================================
-
-// face identifiers
-typedef U16 LLFaceID;
-
-const LLFaceID	LL_FACE_PATH_BEGIN		= 0x1 << 0;
-const LLFaceID	LL_FACE_PATH_END		= 0x1 << 1;
-const LLFaceID	LL_FACE_INNER_SIDE		= 0x1 << 2;
-const LLFaceID	LL_FACE_PROFILE_BEGIN	= 0x1 << 3;
-const LLFaceID	LL_FACE_PROFILE_END		= 0x1 << 4;
-const LLFaceID	LL_FACE_OUTER_SIDE_0	= 0x1 << 5;
-const LLFaceID	LL_FACE_OUTER_SIDE_1	= 0x1 << 6;
-const LLFaceID	LL_FACE_OUTER_SIDE_2	= 0x1 << 7;
-const LLFaceID	LL_FACE_OUTER_SIDE_3	= 0x1 << 8;
-
-//============================================================================
-
-// sculpt types + flags
-
-const U8 LL_SCULPT_TYPE_NONE      = 0;
-const U8 LL_SCULPT_TYPE_SPHERE    = 1;
-const U8 LL_SCULPT_TYPE_TORUS     = 2;
-const U8 LL_SCULPT_TYPE_PLANE     = 3;
-const U8 LL_SCULPT_TYPE_CYLINDER  = 4;
-const U8 LL_SCULPT_TYPE_MESH      = 5;
-const U8 LL_SCULPT_TYPE_MASK      = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
-	LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
-
-const U8 LL_SCULPT_FLAG_INVERT    = 64;
-const U8 LL_SCULPT_FLAG_MIRROR    = 128;
-
-const S32 LL_SCULPT_MESH_MAX_FACES = 8;
-
-class LLProfileParams
-{
-public:
-	LLProfileParams()
-		: mCurveType(LL_PCODE_PROFILE_SQUARE),
-		  mBegin(0.f),
-		  mEnd(1.f),
-		  mHollow(0.f),
-		  mCRC(0)
-	{
-	}
-
-	LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow)
-		: mCurveType(curve),
-		  mBegin(begin),
-		  mEnd(end),
-		  mHollow(hollow),
-		  mCRC(0)
-	{
-	}
-
-	LLProfileParams(U8 curve, U16 begin, U16 end, U16 hollow)
-	{
-		mCurveType = curve;
-		F32 temp_f32 = begin * CUT_QUANTA;
-		if (temp_f32 > 1.f)
-		{
-			temp_f32 = 1.f;
-		}
-		mBegin = temp_f32;
-		temp_f32 = end * CUT_QUANTA;
-		if (temp_f32 > 1.f)
-		{
-			temp_f32 = 1.f;
-		}
-		mEnd = 1.f - temp_f32;
-		temp_f32 = hollow * HOLLOW_QUANTA;
-		if (temp_f32 > 1.f)
-		{
-			temp_f32 = 1.f;
-		}
-		mHollow = temp_f32;
-		mCRC = 0;
-	}
-
-	bool operator==(const LLProfileParams &params) const;
-	bool operator!=(const LLProfileParams &params) const;
-	bool operator<(const LLProfileParams &params) const;
-	
-	void copyParams(const LLProfileParams &params);
-
-	BOOL importFile(LLFILE *fp);
-	BOOL exportFile(LLFILE *fp) const;
-
-	BOOL importLegacyStream(std::istream& input_stream);
-	BOOL exportLegacyStream(std::ostream& output_stream) const;
-
-	LLSD asLLSD() const;
-	operator LLSD() const { return asLLSD(); }
-	bool fromLLSD(LLSD& sd);
-
-	const F32&  getBegin () const				{ return mBegin; }
-	const F32&  getEnd   () const				{ return mEnd;   }
-	const F32&  getHollow() const				{ return mHollow; }
-	const U8&   getCurveType () const			{ return mCurveType; }
-
-	void setCurveType(const U32 type)			{ mCurveType = type;}
-	void setBegin(const F32 begin)				{ mBegin = (begin >= 1.0f) ? 0.0f : ((int) (begin * 100000))/100000.0f;}
-	void setEnd(const F32 end)					{ mEnd   = (end   <= 0.0f) ? 1.0f : ((int) (end * 100000))/100000.0f;}
-	void setHollow(const F32 hollow)			{ mHollow = ((int) (hollow * 100000))/100000.0f;}
-
-	friend std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params);
-
-protected:
-	// Profile params
-	U8			  mCurveType;
-	F32           mBegin;
-	F32           mEnd;
-	F32			  mHollow;
-
-	U32           mCRC;
-};
-
-inline bool LLProfileParams::operator==(const LLProfileParams &params) const
-{
-	return 
-		(getCurveType() == params.getCurveType()) &&
-		(getBegin() == params.getBegin()) &&
-		(getEnd() == params.getEnd()) &&
-		(getHollow() == params.getHollow());
-}
-
-inline bool LLProfileParams::operator!=(const LLProfileParams &params) const
-{
-	return 
-		(getCurveType() != params.getCurveType()) ||
-		(getBegin() != params.getBegin()) ||
-		(getEnd() != params.getEnd()) ||
-		(getHollow() != params.getHollow());
-}
-
-
-inline bool LLProfileParams::operator<(const LLProfileParams &params) const
-{
-	if (getCurveType() != params.getCurveType())
-	{
-		return getCurveType() < params.getCurveType();
-	}
-	else
-	if (getBegin() != params.getBegin())
-	{
-		return getBegin() < params.getBegin();
-	}
-	else
-	if (getEnd() != params.getEnd())
-	{
-		return getEnd() < params.getEnd();
-	}
-	else
-	{
-		return getHollow() < params.getHollow();
-	}
-}
-
-#define U8_TO_F32(x) (F32)(*((S8 *)&x))
-
-class LLPathParams
-{
-public:
-	LLPathParams()
-		:
-		mCurveType(LL_PCODE_PATH_LINE),
-		mBegin(0.f),
-		mEnd(1.f),
-		mScale(1.f,1.f),
-		mShear(0.f,0.f),
-		mTwistBegin(0.f),
-		mTwistEnd(0.f),
-		mRadiusOffset(0.f),
-		mTaper(0.f,0.f),
-		mRevolutions(1.f),
-		mSkew(0.f),
-		mCRC(0)
-	{
-	}
-
-	LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew)
-		: mCurveType(curve),
-		  mBegin(begin),
-		  mEnd(end),
-		  mScale(scx,scy),
-		  mShear(shx,shy),
-		  mTwistBegin(twistbegin),
-		  mTwistEnd(twistend), 
-		  mRadiusOffset(radiusoffset),
-		  mTaper(tx,ty),
-		  mRevolutions(revolutions),
-		  mSkew(skew),
-		  mCRC(0)
-	{
-	}
-
-	LLPathParams(U8 curve, U16 begin, U16 end, U8 scx, U8 scy, U8 shx, U8 shy, U8 twistend, U8 twistbegin, U8 radiusoffset, U8 tx, U8 ty, U8 revolutions, U8 skew)
-	{
-		mCurveType = curve;
-		mBegin = (F32)(begin * CUT_QUANTA);
-		mEnd = (F32)(100.f - end) * CUT_QUANTA;
-		if (mEnd > 1.f)
-			mEnd = 1.f;
-		mScale.setVec((F32) (200 - scx) * SCALE_QUANTA,(F32) (200 - scy) * SCALE_QUANTA);
-		mShear.setVec(U8_TO_F32(shx) * SHEAR_QUANTA,U8_TO_F32(shy) * SHEAR_QUANTA);
-		mTwistBegin = U8_TO_F32(twistbegin) * SCALE_QUANTA;
-		mTwistEnd = U8_TO_F32(twistend) * SCALE_QUANTA;
-		mRadiusOffset = U8_TO_F32(radiusoffset) * SCALE_QUANTA;
-		mTaper.setVec(U8_TO_F32(tx) * TAPER_QUANTA,U8_TO_F32(ty) * TAPER_QUANTA);
-		mRevolutions = ((F32)revolutions) * REV_QUANTA + 1.0f;
-		mSkew = U8_TO_F32(skew) * SCALE_QUANTA;
-
-		mCRC = 0;
-	}
-
-	bool operator==(const LLPathParams &params) const;
-	bool operator!=(const LLPathParams &params) const;
-	bool operator<(const LLPathParams &params) const;
-
-	void copyParams(const LLPathParams &params);
-
-	BOOL importFile(LLFILE *fp);
-	BOOL exportFile(LLFILE *fp) const;
-
-	BOOL importLegacyStream(std::istream& input_stream);
-	BOOL exportLegacyStream(std::ostream& output_stream) const;
-
-	LLSD asLLSD() const;
-	operator LLSD() const { return asLLSD(); }
-	bool fromLLSD(LLSD& sd);
-
-	const F32& getBegin() const			{ return mBegin; }
-	const F32& getEnd() const			{ return mEnd; }
-	const LLVector2 &getScale() const	{ return mScale; }
-	const F32& getScaleX() const		{ return mScale.mV[0]; }
-	const F32& getScaleY() const		{ return mScale.mV[1]; }
-	const LLVector2 getBeginScale() const;
-	const LLVector2 getEndScale() const;
-	const LLVector2 &getShear() const	{ return mShear; }
-	const F32& getShearX() const		{ return mShear.mV[0]; }
-	const F32& getShearY() const		{ return mShear.mV[1]; }
-	const U8& getCurveType () const		{ return mCurveType; }
-
-	const F32& getTwistBegin() const	{ return mTwistBegin;	}
-	const F32& getTwistEnd() const		{ return mTwistEnd;	}
-	const F32& getTwist() const			{ return mTwistEnd; }	// deprecated
-	const F32& getRadiusOffset() const	{ return mRadiusOffset; }
-	const LLVector2 &getTaper() const	{ return mTaper;		}
-	const F32& getTaperX() const		{ return mTaper.mV[0];	}
-	const F32& getTaperY() const		{ return mTaper.mV[1];	}
-	const F32& getRevolutions() const	{ return mRevolutions;	}
-	const F32& getSkew() const			{ return mSkew;			}
-
-	void setCurveType(const U8 type)	{ mCurveType = type;	}
-	void setBegin(const F32 begin)		{ mBegin     = begin;	}
-	void setEnd(const F32 end)			{ mEnd       = end;	}
-
-	void setScale(const F32 x, const F32 y)		{ mScale.setVec(x,y); }
-	void setScaleX(const F32 v)					{ mScale.mV[VX] = v; }
-	void setScaleY(const F32 v)					{ mScale.mV[VY] = v; }
-	void setShear(const F32 x, const F32 y)		{ mShear.setVec(x,y); }
-	void setShearX(const F32 v)					{ mShear.mV[VX] = v; }
-	void setShearY(const F32 v)					{ mShear.mV[VY] = v; }
-
-	void setTwistBegin(const F32 twist_begin)	{ mTwistBegin	= twist_begin;	}
-	void setTwistEnd(const F32 twist_end)		{ mTwistEnd		= twist_end;	}
-	void setTwist(const F32 twist)				{ setTwistEnd(twist); }	// deprecated
-	void setRadiusOffset(const F32 radius_offset){ mRadiusOffset	= radius_offset; }
-	void setTaper(const F32 x, const F32 y)		{ mTaper.setVec(x,y);			}
-	void setTaperX(const F32 v)					{ mTaper.mV[VX]	= v;			}
-	void setTaperY(const F32 v)					{ mTaper.mV[VY]	= v;			}
-	void setRevolutions(const F32 revolutions)	{ mRevolutions	= revolutions;	}
-	void setSkew(const F32 skew)				{ mSkew			= skew;			}
-
-	friend std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params);
-
-protected:
-	// Path params
-	U8			  mCurveType;
-	F32           mBegin;
-	F32           mEnd;
-	LLVector2	  mScale;
-	LLVector2     mShear;
-
-	F32			  mTwistBegin;
-	F32			  mTwistEnd;
-	F32			  mRadiusOffset;
-	LLVector2	  mTaper;
-	F32			  mRevolutions;
-	F32			  mSkew;
-
-	U32           mCRC;
-};
-
-inline bool LLPathParams::operator==(const LLPathParams &params) const
-{
-	return
-		(getCurveType() == params.getCurveType()) && 
-		(getScale() == params.getScale()) &&
-		(getBegin() == params.getBegin()) && 
-		(getEnd() == params.getEnd()) && 
-		(getShear() == params.getShear()) &&
-		(getTwist() == params.getTwist()) &&
-		(getTwistBegin() == params.getTwistBegin()) &&
-		(getRadiusOffset() == params.getRadiusOffset()) &&
-		(getTaper() == params.getTaper()) &&
-		(getRevolutions() == params.getRevolutions()) &&
-		(getSkew() == params.getSkew());
-}
-
-inline bool LLPathParams::operator!=(const LLPathParams &params) const
-{
-	return
-		(getCurveType() != params.getCurveType()) ||
-		(getScale() != params.getScale()) ||
-		(getBegin() != params.getBegin()) || 
-		(getEnd() != params.getEnd()) || 
-		(getShear() != params.getShear()) ||
-		(getTwist() != params.getTwist()) ||
-		(getTwistBegin() !=params.getTwistBegin()) ||
-		(getRadiusOffset() != params.getRadiusOffset()) ||
-		(getTaper() != params.getTaper()) ||
-		(getRevolutions() != params.getRevolutions()) ||
-		(getSkew() != params.getSkew());
-}
-
-
-inline bool LLPathParams::operator<(const LLPathParams &params) const
-{
-	if( getCurveType() != params.getCurveType()) 
-	{
-		return getCurveType() < params.getCurveType();
-	}
-	else
-	if( getScale() != params.getScale()) 
-	{
-		return getScale() < params.getScale();
-	}
-	else
-	if( getBegin() != params.getBegin()) 
-	{
-		return getBegin() < params.getBegin();
-	}
-	else
-	if( getEnd() != params.getEnd()) 
-	{
-		return getEnd() < params.getEnd();
-	}
-	else
-	if( getShear() != params.getShear()) 
-	{
-		return getShear() < params.getShear();
-	}
-	else
-	if( getTwist() != params.getTwist())
-	{
-		return getTwist() < params.getTwist();
-	}
-	else
-	if( getTwistBegin() != params.getTwistBegin())
-	{
-		return getTwistBegin() < params.getTwistBegin();
-	}
-	else
-	if( getRadiusOffset() != params.getRadiusOffset())
-	{
-		return getRadiusOffset() < params.getRadiusOffset();
-	}
-	else
-	if( getTaper() != params.getTaper())
-	{
-		return getTaper() < params.getTaper();
-	}
-	else
-	if( getRevolutions() != params.getRevolutions())
-	{
-		return getRevolutions() < params.getRevolutions();
-	}
-	else
-	{
-		return getSkew() < params.getSkew();
-	}
-}
-
-typedef LLVolumeParams* LLVolumeParamsPtr;
-typedef const LLVolumeParams* const_LLVolumeParamsPtr;
-
-class LLVolumeParams
-{
-public:
-	LLVolumeParams()
-		: mSculptType(LL_SCULPT_TYPE_NONE)
-	{
-	}
-
-	LLVolumeParams(LLProfileParams &profile, LLPathParams &path,
-				   LLUUID sculpt_id = LLUUID::null, U8 sculpt_type = LL_SCULPT_TYPE_NONE)
-		: mProfileParams(profile), mPathParams(path), mSculptID(sculpt_id), mSculptType(sculpt_type)
-	{
-	}
-
-	bool operator==(const LLVolumeParams &params) const;
-	bool operator!=(const LLVolumeParams &params) const;
-	bool operator<(const LLVolumeParams &params) const;
-
-
-	void copyParams(const LLVolumeParams &params);
-	
-	const LLProfileParams &getProfileParams() const {return mProfileParams;}
-	LLProfileParams &getProfileParams() {return mProfileParams;}
-	const LLPathParams &getPathParams() const {return mPathParams;}
-	LLPathParams &getPathParams() {return mPathParams;}
-
-	BOOL importFile(LLFILE *fp);
-	BOOL exportFile(LLFILE *fp) const;
-
-	BOOL importLegacyStream(std::istream& input_stream);
-	BOOL exportLegacyStream(std::ostream& output_stream) const;
-
-	LLSD sculptAsLLSD() const;
-	bool sculptFromLLSD(LLSD& sd);
-	
-	LLSD asLLSD() const;
-	operator LLSD() const { return asLLSD(); }
-	bool fromLLSD(LLSD& sd);
-
-	bool setType(U8 profile, U8 path);
-
-	//void setBeginS(const F32 beginS)			{ mProfileParams.setBegin(beginS); }	// range 0 to 1
-	//void setBeginT(const F32 beginT)			{ mPathParams.setBegin(beginT); }		// range 0 to 1
-	//void setEndS(const F32 endS)				{ mProfileParams.setEnd(endS); }		// range 0 to 1, must be greater than begin
-	//void setEndT(const F32 endT)				{ mPathParams.setEnd(endT); }			// range 0 to 1, must be greater than begin
-
-	bool setBeginAndEndS(const F32 begin, const F32 end);			// both range from 0 to 1, begin must be less than end
-	bool setBeginAndEndT(const F32 begin, const F32 end);			// both range from 0 to 1, begin must be less than end
-
-	bool setHollow(const F32 hollow);	// range 0 to 1
-	bool setRatio(const F32 x)					{ return setRatio(x,x); }			// 0 = point, 1 = same as base
-	bool setShear(const F32 x)					{ return setShear(x,x); }			// 0 = no movement, 
-	bool setRatio(const F32 x, const F32 y);			// 0 = point, 1 = same as base
-	bool setShear(const F32 x, const F32 y);			// 0 = no movement
-
-	bool setTwistBegin(const F32 twist_begin);	// range -1 to 1
-	bool setTwistEnd(const F32 twist_end);		// range -1 to 1
-	bool setTwist(const F32 twist)				{ return setTwistEnd(twist); }		// deprecated
-	bool setTaper(const F32 x, const F32 y)		{ bool pass_x = setTaperX(x); bool pass_y = setTaperY(y); return pass_x && pass_y; }
-	bool setTaperX(const F32 v);				// -1 to 1
-	bool setTaperY(const F32 v);				// -1 to 1
-	bool setRevolutions(const F32 revolutions);	// 1 to 4
-	bool setRadiusOffset(const F32 radius_offset);
-	bool setSkew(const F32 skew);
-	bool setSculptID(const LLUUID sculpt_id, U8 sculpt_type);
-
-	static bool validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
-		U8 path_curve, F32 path_begin, F32 path_end,
-		F32 scx, F32 scy, F32 shx, F32 shy,
-		F32 twistend, F32 twistbegin, F32 radiusoffset,
-		F32 tx, F32 ty, F32 revolutions, F32 skew);
-	
-	const F32&  getBeginS() 	const	{ return mProfileParams.getBegin(); }
- 	const F32&  getBeginT() 	const	{ return mPathParams.getBegin(); }
- 	const F32&  getEndS() 		const	{ return mProfileParams.getEnd(); }
- 	const F32&  getEndT() 		const	{ return mPathParams.getEnd(); }
- 
- 	const F32&  getHollow() 	const   { return mProfileParams.getHollow(); }
- 	const F32&  getTwist() 	const   	{ return mPathParams.getTwist(); }
- 	const F32&  getRatio() 	const		{ return mPathParams.getScaleX(); }
- 	const F32&  getRatioX() 	const   { return mPathParams.getScaleX(); }
- 	const F32&  getRatioY() 	const   { return mPathParams.getScaleY(); }
- 	const F32&  getShearX() 	const   { return mPathParams.getShearX(); }
- 	const F32&  getShearY() 	const   { return mPathParams.getShearY(); }
-
-	const F32&	getTwistBegin()const	{ return mPathParams.getTwistBegin();	}
-	const F32&  getRadiusOffset() const	{ return mPathParams.getRadiusOffset();	}
-	const F32&  getTaper() const		{ return mPathParams.getTaperX();		}
-	const F32&	getTaperX() const		{ return mPathParams.getTaperX();		}
-	const F32&  getTaperY() const		{ return mPathParams.getTaperY();		}
-	const F32&  getRevolutions() const	{ return mPathParams.getRevolutions();	}
-	const F32&  getSkew() const			{ return mPathParams.getSkew();			}
-	const LLUUID& getSculptID() const	{ return mSculptID;						}
-	const U8& getSculptType() const     { return mSculptType;                   }
-	bool isSculpt() const;
-	bool isMeshSculpt() const;
-	BOOL isConvex() const;
-
-	// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
-	// (begin, end) = (0, 1) will not change the volume
-	// (begin, end) = (0, 0.5) will reduce the volume to the first half of its profile/path (S/T)
-	void reduceS(F32 begin, F32 end);
-	void reduceT(F32 begin, F32 end);
-
-	struct compare
-	{
-		bool operator()( const const_LLVolumeParamsPtr& first, const const_LLVolumeParamsPtr& second) const
-		{
-			return (*first < *second);
-		}
-	};
-	
-	friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
-
-	// debug helper functions
-	void setCube();
-
-protected:
-	LLProfileParams mProfileParams;
-	LLPathParams	mPathParams;
-	LLUUID mSculptID;
-	U8 mSculptType;
-};
-
-
-class LLProfile
-{
-public:
-	LLProfile()
-		: mOpen(FALSE),
-		  mConcave(FALSE),
-		  mDirty(TRUE),
-		  mTotalOut(0),
-		  mTotal(2)
-	{
-	}
-
-	~LLProfile();
-
-	S32	 getTotal() const								{ return mTotal; }
-	S32	 getTotalOut() const							{ return mTotalOut; }	// Total number of outside points
-	BOOL isFlat(S32 face) const							{ return (mFaces[face].mCount == 2); }
-	BOOL isOpen() const									{ return mOpen; }
-	void setDirty()										{ mDirty     = TRUE; }
-	BOOL generate(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0,
-				  BOOL is_sculpted = FALSE, S32 sculpt_size = 0);
-	BOOL isConcave() const								{ return mConcave; }
-public:
-	struct Face
-	{
-		S32       mIndex;
-		S32       mCount;
-		F32       mScaleU;
-		BOOL      mCap;
-		BOOL      mFlat;
-		LLFaceID  mFaceID;
-	};
-	
-	std::vector<LLVector3> mProfile;	
-	std::vector<LLVector2> mNormals;
-	std::vector<Face>      mFaces;
-	std::vector<LLVector3> mEdgeNormals;
-	std::vector<LLVector3> mEdgeCenters;
-
-	friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile);
-
-protected:
-	void genNormals(const LLProfileParams& params);
-	void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0);
-
-	Face* addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0);
-	Face* addCap (S16 faceID);
-	Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, BOOL flat);
-
-protected:
-	BOOL		  mOpen;
-	BOOL		  mConcave;
-	BOOL          mDirty;
-
-	S32			  mTotalOut;
-	S32			  mTotal;
-};
-
-//-------------------------------------------------------------------
-// SWEEP/EXTRUDE PATHS
-//-------------------------------------------------------------------
-
-class LLPath
-{
-public:
-	struct PathPt
-	{
-		LLVector3	 mPos;
-		LLVector2    mScale;
-		LLQuaternion mRot;
-		F32			 mTexT;
-		PathPt() { mPos.setVec(0,0,0); mTexT = 0; mScale.setVec(0,0); mRot.loadIdentity(); }
-	};
-
-public:
-	LLPath()
-		: mOpen(FALSE),
-		  mTotal(0),
-		  mDirty(TRUE),
-		  mStep(1)
-	{
-	}
-
-	virtual ~LLPath();
-
-	void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f);
-	virtual BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0,
-						  BOOL is_sculpted = FALSE, S32 sculpt_size = 0);
-
-	BOOL isOpen() const						{ return mOpen; }
-	F32 getStep() const						{ return mStep; }
-	void setDirty()							{ mDirty     = TRUE; }
-
-	S32 getPathLength() const				{ return (S32)mPath.size(); }
-
-	void resizePath(S32 length) { mPath.resize(length); }
-
-	friend std::ostream& operator<<(std::ostream &s, const LLPath &path);
-
-public:
-	std::vector<PathPt> mPath;
-
-protected:
-	BOOL		  mOpen;
-	S32			  mTotal;
-	BOOL          mDirty;
-	F32           mStep;
-};
-
-class LLDynamicPath : public LLPath
-{
-public:
-	LLDynamicPath() : LLPath() { }
-	/*virtual*/ BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0,
-							  BOOL is_sculpted = FALSE, S32 sculpt_size = 0);
-};
-
-// Yet another "face" class - caches volume-specific, but not instance-specific data for faces)
-class LLVolumeFace
-{
-public:
-	class VertexData
-	{
-		enum 
-		{
-			POSITION = 0,
-			NORMAL = 1
-		};
-
-	private:
-		void init();
-	public:
-		VertexData();
-		VertexData(const VertexData& rhs);
-		const VertexData& operator=(const VertexData& rhs);
-
-		~VertexData();
-		LLVector4a& getPosition();
-		LLVector4a& getNormal();
-		const LLVector4a& getPosition() const;
-		const LLVector4a& getNormal() const;
-		void setPosition(const LLVector4a& pos);
-		void setNormal(const LLVector4a& norm);
-		
-
-		LLVector2 mTexCoord;
-
-		bool operator<(const VertexData& rhs) const;
-		bool operator==(const VertexData& rhs) const;
-		bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const;
-
-	private:
-		LLVector4a* mData;
-	};
-
-	LLVolumeFace();
-	LLVolumeFace(const LLVolumeFace& src);
-	LLVolumeFace& operator=(const LLVolumeFace& rhs);
-
-	~LLVolumeFace();
-private:
-	void freeData();
-public:
-
-	BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
-	void createBinormals();
-	
-	void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform);
-
-	void resizeVertices(S32 num_verts);
-	void allocateBinormals(S32 num_verts);
-	void allocateWeights(S32 num_verts);
-	void resizeIndices(S32 num_indices);
-	void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
-
-	void pushVertex(const VertexData& cv);
-	void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc);
-	void pushIndex(const U16& idx);
-
-	void swapData(LLVolumeFace& rhs);
-
-	void getVertexData(U16 indx, LLVolumeFace::VertexData& cv);
-
-	class VertexMapData : public LLVolumeFace::VertexData
-	{
-	public:
-		U16 mIndex;
-
-		bool operator==(const LLVolumeFace::VertexData& rhs) const;
-
-		struct ComparePosition
-		{
-			bool operator()(const LLVector3& a, const LLVector3& b) const;
-		};
-
-		typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
-	};
-
-	void optimize(F32 angle_cutoff = 2.f);
-	void cacheOptimize();
-
-	void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
-
-	enum
-	{
-		SINGLE_MASK =	0x0001,
-		CAP_MASK =		0x0002,
-		END_MASK =		0x0004,
-		SIDE_MASK =		0x0008,
-		INNER_MASK =	0x0010,
-		OUTER_MASK =	0x0020,
-		HOLLOW_MASK =	0x0040,
-		OPEN_MASK =		0x0080,
-		FLAT_MASK =		0x0100,
-		TOP_MASK =		0x0200,
-		BOTTOM_MASK =	0x0400
-	};
-	
-public:
-	S32 mID;
-	U32 mTypeMask;
-	
-	// Only used for INNER/OUTER faces
-	S32 mBeginS;
-	S32 mBeginT;
-	S32 mNumS;
-	S32 mNumT;
-
-	LLVector4a* mExtents; //minimum and maximum point of face
-	LLVector4a* mCenter;
-	LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
-
-	S32 mNumVertices;
-	S32 mNumIndices;
-
-	LLVector4a* mPositions;
-	LLVector4a* mNormals;
-	LLVector4a* mBinormals;
-	LLVector2* mTexCoords;
-	U16* mIndices;
-
-	std::vector<S32>	mEdge;
-
-	//list of skin weights for rigged volumes
-	// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
-	// mWeights.size() should be empty or match mVertices.size()  
-	LLVector4a* mWeights;
-
-	LLOctreeNode<LLVolumeTriangle>* mOctree;
-
-private:
-	BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
-	BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
-	BOOL createSide(LLVolume* volume, BOOL partial_build = FALSE);
-};
-
-class LLVolume : public LLRefCount
-{
-	friend class LLVolumeLODGroup;
-
-protected:
-	~LLVolume(); // use unref
-
-public:
-	struct Point
-	{
-		LLVector3 mPos;
-	};
-
-	struct FaceParams
-	{
-		LLFaceID mFaceID;
-		S32 mBeginS;
-		S32 mCountS;
-		S32 mBeginT;
-		S32 mCountT;
-	};
-
-	LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL generate_single_face = FALSE, const BOOL is_unique = FALSE);
-	
-	U8 getProfileType()	const								{ return mParams.getProfileParams().getCurveType(); }
-	U8 getPathType() const									{ return mParams.getPathParams().getCurveType(); }
-	S32	getNumFaces() const;
-	S32 getNumVolumeFaces() const							{ return mVolumeFaces.size(); }
-	F32 getDetail() const									{ return mDetail; }
-	const LLVolumeParams& getParams() const					{ return mParams; }
-	LLVolumeParams getCopyOfParams() const					{ return mParams; }
-	const LLProfile& getProfile() const						{ return *mProfilep; }
-	LLPath& getPath() const									{ return *mPathp; }
-	void resizePath(S32 length);
-	const std::vector<Point>& getMesh() const				{ return mMesh; }
-	const LLVector3& getMeshPt(const U32 i) const			{ return mMesh[i].mPos; }
-
-	void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); }
-
-	void regen();
-	void genBinormals(S32 face);
-
-	BOOL isConvex() const;
-	BOOL isCap(S32 face);
-	BOOL isFlat(S32 face);
-	BOOL isUnique() const									{ return mUnique; }
-
-	S32 getSculptLevel() const                              { return mSculptLevel; }
-	void setSculptLevel(S32 level)							{ mSculptLevel = level; }
-
-	S32 *getTriangleIndices(U32 &num_indices) const;
-
-	// returns number of triangle indeces required for path/profile mesh
-	S32 getNumTriangleIndices() const;
-
-	S32 getNumTriangles() const;
-
-	void generateSilhouetteVertices(std::vector<LLVector3> &vertices, 
-									std::vector<LLVector3> &normals, 
-									std::vector<S32> &segments, 
-									const LLVector3& view_vec,
-									const LLMatrix4& mat,
-									const LLMatrix3& norm_mat,
-									S32 face_index);
-
-	//get the face index of the face that intersects with the given line segment at the point 
-	//closest to start.  Moves end to the point of intersection.  Returns -1 if no intersection.
-	//Line segment must be in volume space.
-	S32 lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
-							 S32 face = -1,                          // which face to check, -1 = ALL_SIDES
-							 LLVector3* intersection = NULL,         // return the intersection point
-							 LLVector2* tex_coord = NULL,            // return the texture coordinates of the intersection point
-							 LLVector3* normal = NULL,               // return the surface normal at the intersection point
-							 LLVector3* bi_normal = NULL             // return the surface bi-normal at the intersection point
-		);
-
-	S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
-								   S32 face = 1,
-								   LLVector3* intersection = NULL,
-								   LLVector2* tex_coord = NULL,
-								   LLVector3* normal = NULL,
-								   LLVector3* bi_normal = NULL);
-	
-	// The following cleans up vertices and triangles,
-	// getting rid of degenerate triangles and duplicate vertices,
-	// and allocates new arrays with the clean data.
-	static BOOL cleanupTriangleData( const S32 num_input_vertices,
-								const std::vector<Point> &input_vertices,
-								const S32 num_input_triangles,
-								S32 *input_triangles,
-								S32 &num_output_vertices,
-								LLVector3 **output_vertices,
-								S32 &num_output_triangles,
-								S32 **output_triangles);
-	LLFaceID generateFaceMask();
-
-	BOOL isFaceMaskValid(LLFaceID face_mask);
-	static S32 sNumMeshPoints;
-
-	friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume);
-	friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep);		// HACK to bypass Windoze confusion over 
-																				// conversion if *(LLVolume*) to LLVolume&
-	const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE
-	
-	U32					mFaceMask;			// bit array of which faces exist in this volume
-	LLVector3			mLODScaleBias;		// vector for biasing LOD based on scale
-	
-	void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level);
-	void copyVolumeFaces(const LLVolume* volume);
-	void cacheOptimize();
-
-private:
-	void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type);
-	F32 sculptGetSurfaceArea();
-	void sculptGeneratePlaceholder();
-	void sculptCalcMeshResolution(U16 width, U16 height, U8 type, S32& s, S32& t);
-
-	
-protected:
-	BOOL generate();
-	void createVolumeFaces();
-public:
-	virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
-	virtual BOOL createVolumeFacesFromStream(std::istream& is);
-	virtual bool unpackVolumeFaces(std::istream& is, S32 size);
-
-	virtual void makeTetrahedron();
-	virtual BOOL isTetrahedron();
-
- protected:
-	BOOL mUnique;
-	F32 mDetail;
-	S32 mSculptLevel;
-	BOOL mIsTetrahedron;
-	
-	LLVolumeParams mParams;
-	LLPath *mPathp;
-	LLProfile *mProfilep;
-	std::vector<Point> mMesh;
-	
-	BOOL mGenerateSingleFace;
-	typedef std::vector<LLVolumeFace> face_list_t;
-	face_list_t mVolumeFaces;
-
-public:
-	LLVector4a* mHullPoints;
-	U16* mHullIndices;
-	S32 mNumHullPoints;
-	S32 mNumHullIndices;
-};
-
-std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
-
-void calc_binormal_from_triangle(
-		LLVector4a& binormal,
-		const LLVector4a& pos0,
-		const LLVector2& tex0,
-		const LLVector4a& pos1,
-		const LLVector2& tex1,
-		const LLVector4a& pos2,
-		const LLVector2& tex2);
-
-BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size);
-BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
-BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size);
-
-BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
-							F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided);
-
-BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
-							F32& intersection_a, F32& intersection_b, F32& intersection_t);
-BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
-							F32& intersection_a, F32& intersection_b, F32& intersection_t);
-	
-	
-
-#endif
+/** 
+ * @file llvolume.h
+ * @brief LLVolume base class.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLVOLUME_H
+#define LL_LLVOLUME_H
+
+#include <iostream>
+
+class LLProfileParams;
+class LLPathParams;
+class LLVolumeParams;
+class LLProfile;
+class LLPath;
+
+template <class T> class LLOctreeNode;
+
+class LLVector4a;
+class LLVolumeFace;
+class LLVolume;
+class LLVolumeTriangle;
+
+#include "lldarray.h"
+#include "lluuid.h"
+#include "v4color.h"
+//#include "vmath.h"
+#include "v2math.h"
+#include "v3math.h"
+#include "v3dmath.h"
+#include "v4math.h"
+#include "llquaternion.h"
+#include "llstrider.h"
+#include "v4coloru.h"
+#include "llrefcount.h"
+#include "llfile.h"
+
+//============================================================================
+
+const S32 MIN_DETAIL_FACES = 6;
+const S32 MIN_LOD = 0;
+const S32 MAX_LOD = 3;
+
+// These are defined here but are not enforced at this level,
+// rather they are here for the convenience of code that uses
+// the LLVolume class.
+const F32 MIN_VOLUME_PROFILE_WIDTH 	= 0.05f;
+const F32 MIN_VOLUME_PATH_WIDTH 	= 0.05f;
+
+const F32 CUT_QUANTA    = 0.00002f;
+const F32 SCALE_QUANTA  = 0.01f;
+const F32 SHEAR_QUANTA  = 0.01f;
+const F32 TAPER_QUANTA  = 0.01f;
+const F32 REV_QUANTA    = 0.015f;
+const F32 HOLLOW_QUANTA = 0.00002f;
+
+const S32 MAX_VOLUME_TRIANGLE_INDICES = 10000;
+
+//============================================================================
+
+// useful masks
+const LLPCode LL_PCODE_HOLLOW_MASK 	= 0x80;		// has a thickness
+const LLPCode LL_PCODE_SEGMENT_MASK = 0x40;		// segments (1 angle)
+const LLPCode LL_PCODE_PATCH_MASK 	= 0x20;		// segmented segments (2 angles)
+const LLPCode LL_PCODE_HEMI_MASK 	= 0x10;		// half-primitives get their own type per PR's dictum
+const LLPCode LL_PCODE_BASE_MASK 	= 0x0F;
+
+	// primitive shapes
+const LLPCode	LL_PCODE_CUBE 			= 1;
+const LLPCode	LL_PCODE_PRISM 			= 2;
+const LLPCode	LL_PCODE_TETRAHEDRON 	= 3;
+const LLPCode	LL_PCODE_PYRAMID 		= 4;
+const LLPCode	LL_PCODE_CYLINDER 		= 5;
+const LLPCode	LL_PCODE_CONE 			= 6;
+const LLPCode	LL_PCODE_SPHERE 		= 7;
+const LLPCode	LL_PCODE_TORUS 			= 8;
+const LLPCode	LL_PCODE_VOLUME			= 9;
+
+	// surfaces
+//const LLPCode	LL_PCODE_SURFACE_TRIANGLE 	= 10;
+//const LLPCode	LL_PCODE_SURFACE_SQUARE 	= 11;
+//const LLPCode	LL_PCODE_SURFACE_DISC 		= 12;
+
+const LLPCode	LL_PCODE_APP				= 14; // App specific pcode (for viewer/sim side only objects)
+const LLPCode	LL_PCODE_LEGACY				= 15;
+
+// Pcodes for legacy objects
+//const LLPCode	LL_PCODE_LEGACY_ATOR =				0x10 | LL_PCODE_LEGACY; // ATOR
+const LLPCode	LL_PCODE_LEGACY_AVATAR =			0x20 | LL_PCODE_LEGACY; // PLAYER
+//const LLPCode	LL_PCODE_LEGACY_BIRD =				0x30 | LL_PCODE_LEGACY; // BIRD
+//const LLPCode	LL_PCODE_LEGACY_DEMON =				0x40 | LL_PCODE_LEGACY; // DEMON
+const LLPCode	LL_PCODE_LEGACY_GRASS =				0x50 | LL_PCODE_LEGACY; // GRASS
+const LLPCode	LL_PCODE_TREE_NEW =					0x60 | LL_PCODE_LEGACY; // new trees
+//const LLPCode	LL_PCODE_LEGACY_ORACLE =			0x70 | LL_PCODE_LEGACY; // ORACLE
+const LLPCode	LL_PCODE_LEGACY_PART_SYS =			0x80 | LL_PCODE_LEGACY; // PART_SYS
+const LLPCode	LL_PCODE_LEGACY_ROCK =				0x90 | LL_PCODE_LEGACY; // ROCK
+//const LLPCode	LL_PCODE_LEGACY_SHOT =				0xA0 | LL_PCODE_LEGACY; // BASIC_SHOT
+//const LLPCode	LL_PCODE_LEGACY_SHOT_BIG =			0xB0 | LL_PCODE_LEGACY;
+//const LLPCode	LL_PCODE_LEGACY_SMOKE =				0xC0 | LL_PCODE_LEGACY; // SMOKE
+//const LLPCode	LL_PCODE_LEGACY_SPARK =				0xD0 | LL_PCODE_LEGACY;// SPARK
+const LLPCode	LL_PCODE_LEGACY_TEXT_BUBBLE =		0xE0 | LL_PCODE_LEGACY; // TEXTBUBBLE
+const LLPCode	LL_PCODE_LEGACY_TREE =				0xF0 | LL_PCODE_LEGACY; // TREE
+
+	// hemis
+const LLPCode	LL_PCODE_CYLINDER_HEMI =		LL_PCODE_CYLINDER	| LL_PCODE_HEMI_MASK;
+const LLPCode	LL_PCODE_CONE_HEMI =			LL_PCODE_CONE		| LL_PCODE_HEMI_MASK;
+const LLPCode	LL_PCODE_SPHERE_HEMI =			LL_PCODE_SPHERE		| LL_PCODE_HEMI_MASK;
+const LLPCode	LL_PCODE_TORUS_HEMI =			LL_PCODE_TORUS		| LL_PCODE_HEMI_MASK;
+
+
+// Volumes consist of a profile at the base that is swept around
+// a path to make a volume.
+// The profile code
+const U8	LL_PCODE_PROFILE_MASK		= 0x0f;
+const U8	LL_PCODE_PROFILE_MIN		= 0x00;
+const U8    LL_PCODE_PROFILE_CIRCLE		= 0x00;
+const U8    LL_PCODE_PROFILE_SQUARE		= 0x01;
+const U8	LL_PCODE_PROFILE_ISOTRI		= 0x02;
+const U8    LL_PCODE_PROFILE_EQUALTRI	= 0x03;
+const U8    LL_PCODE_PROFILE_RIGHTTRI	= 0x04;
+const U8	LL_PCODE_PROFILE_CIRCLE_HALF = 0x05;
+const U8	LL_PCODE_PROFILE_MAX		= 0x05;
+
+// Stored in the profile byte
+const U8	LL_PCODE_HOLE_MASK		= 0xf0;
+const U8	LL_PCODE_HOLE_MIN		= 0x00;	  
+const U8	LL_PCODE_HOLE_SAME		= 0x00;		// same as outside profile
+const U8	LL_PCODE_HOLE_CIRCLE	= 0x10;
+const U8	LL_PCODE_HOLE_SQUARE	= 0x20;
+const U8	LL_PCODE_HOLE_TRIANGLE	= 0x30;
+const U8	LL_PCODE_HOLE_MAX		= 0x03;		// min/max needs to be >> 4 of real min/max
+
+const U8    LL_PCODE_PATH_IGNORE    = 0x00;
+const U8	LL_PCODE_PATH_MIN		= 0x01;		// min/max needs to be >> 4 of real min/max
+const U8    LL_PCODE_PATH_LINE      = 0x10;
+const U8    LL_PCODE_PATH_CIRCLE    = 0x20;
+const U8    LL_PCODE_PATH_CIRCLE2   = 0x30;
+const U8    LL_PCODE_PATH_TEST      = 0x40;
+const U8    LL_PCODE_PATH_FLEXIBLE  = 0x80;
+const U8	LL_PCODE_PATH_MAX		= 0x08;
+
+//============================================================================
+
+// face identifiers
+typedef U16 LLFaceID;
+
+const LLFaceID	LL_FACE_PATH_BEGIN		= 0x1 << 0;
+const LLFaceID	LL_FACE_PATH_END		= 0x1 << 1;
+const LLFaceID	LL_FACE_INNER_SIDE		= 0x1 << 2;
+const LLFaceID	LL_FACE_PROFILE_BEGIN	= 0x1 << 3;
+const LLFaceID	LL_FACE_PROFILE_END		= 0x1 << 4;
+const LLFaceID	LL_FACE_OUTER_SIDE_0	= 0x1 << 5;
+const LLFaceID	LL_FACE_OUTER_SIDE_1	= 0x1 << 6;
+const LLFaceID	LL_FACE_OUTER_SIDE_2	= 0x1 << 7;
+const LLFaceID	LL_FACE_OUTER_SIDE_3	= 0x1 << 8;
+
+//============================================================================
+
+// sculpt types + flags
+
+const U8 LL_SCULPT_TYPE_NONE      = 0;
+const U8 LL_SCULPT_TYPE_SPHERE    = 1;
+const U8 LL_SCULPT_TYPE_TORUS     = 2;
+const U8 LL_SCULPT_TYPE_PLANE     = 3;
+const U8 LL_SCULPT_TYPE_CYLINDER  = 4;
+const U8 LL_SCULPT_TYPE_MESH      = 5;
+const U8 LL_SCULPT_TYPE_MASK      = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
+	LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
+
+const U8 LL_SCULPT_FLAG_INVERT    = 64;
+const U8 LL_SCULPT_FLAG_MIRROR    = 128;
+
+const S32 LL_SCULPT_MESH_MAX_FACES = 8;
+
+class LLProfileParams
+{
+public:
+	LLProfileParams()
+		: mCurveType(LL_PCODE_PROFILE_SQUARE),
+		  mBegin(0.f),
+		  mEnd(1.f),
+		  mHollow(0.f),
+		  mCRC(0)
+	{
+	}
+
+	LLProfileParams(U8 curve, F32 begin, F32 end, F32 hollow)
+		: mCurveType(curve),
+		  mBegin(begin),
+		  mEnd(end),
+		  mHollow(hollow),
+		  mCRC(0)
+	{
+	}
+
+	LLProfileParams(U8 curve, U16 begin, U16 end, U16 hollow)
+	{
+		mCurveType = curve;
+		F32 temp_f32 = begin * CUT_QUANTA;
+		if (temp_f32 > 1.f)
+		{
+			temp_f32 = 1.f;
+		}
+		mBegin = temp_f32;
+		temp_f32 = end * CUT_QUANTA;
+		if (temp_f32 > 1.f)
+		{
+			temp_f32 = 1.f;
+		}
+		mEnd = 1.f - temp_f32;
+		temp_f32 = hollow * HOLLOW_QUANTA;
+		if (temp_f32 > 1.f)
+		{
+			temp_f32 = 1.f;
+		}
+		mHollow = temp_f32;
+		mCRC = 0;
+	}
+
+	bool operator==(const LLProfileParams &params) const;
+	bool operator!=(const LLProfileParams &params) const;
+	bool operator<(const LLProfileParams &params) const;
+	
+	void copyParams(const LLProfileParams &params);
+
+	BOOL importFile(LLFILE *fp);
+	BOOL exportFile(LLFILE *fp) const;
+
+	BOOL importLegacyStream(std::istream& input_stream);
+	BOOL exportLegacyStream(std::ostream& output_stream) const;
+
+	LLSD asLLSD() const;
+	operator LLSD() const { return asLLSD(); }
+	bool fromLLSD(LLSD& sd);
+
+	const F32&  getBegin () const				{ return mBegin; }
+	const F32&  getEnd   () const				{ return mEnd;   }
+	const F32&  getHollow() const				{ return mHollow; }
+	const U8&   getCurveType () const			{ return mCurveType; }
+
+	void setCurveType(const U32 type)			{ mCurveType = type;}
+	void setBegin(const F32 begin)				{ mBegin = (begin >= 1.0f) ? 0.0f : ((int) (begin * 100000))/100000.0f;}
+	void setEnd(const F32 end)					{ mEnd   = (end   <= 0.0f) ? 1.0f : ((int) (end * 100000))/100000.0f;}
+	void setHollow(const F32 hollow)			{ mHollow = ((int) (hollow * 100000))/100000.0f;}
+
+	friend std::ostream& operator<<(std::ostream &s, const LLProfileParams &profile_params);
+
+protected:
+	// Profile params
+	U8			  mCurveType;
+	F32           mBegin;
+	F32           mEnd;
+	F32			  mHollow;
+
+	U32           mCRC;
+};
+
+inline bool LLProfileParams::operator==(const LLProfileParams &params) const
+{
+	return 
+		(getCurveType() == params.getCurveType()) &&
+		(getBegin() == params.getBegin()) &&
+		(getEnd() == params.getEnd()) &&
+		(getHollow() == params.getHollow());
+}
+
+inline bool LLProfileParams::operator!=(const LLProfileParams &params) const
+{
+	return 
+		(getCurveType() != params.getCurveType()) ||
+		(getBegin() != params.getBegin()) ||
+		(getEnd() != params.getEnd()) ||
+		(getHollow() != params.getHollow());
+}
+
+
+inline bool LLProfileParams::operator<(const LLProfileParams &params) const
+{
+	if (getCurveType() != params.getCurveType())
+	{
+		return getCurveType() < params.getCurveType();
+	}
+	else
+	if (getBegin() != params.getBegin())
+	{
+		return getBegin() < params.getBegin();
+	}
+	else
+	if (getEnd() != params.getEnd())
+	{
+		return getEnd() < params.getEnd();
+	}
+	else
+	{
+		return getHollow() < params.getHollow();
+	}
+}
+
+#define U8_TO_F32(x) (F32)(*((S8 *)&x))
+
+class LLPathParams
+{
+public:
+	LLPathParams()
+		:
+		mCurveType(LL_PCODE_PATH_LINE),
+		mBegin(0.f),
+		mEnd(1.f),
+		mScale(1.f,1.f),
+		mShear(0.f,0.f),
+		mTwistBegin(0.f),
+		mTwistEnd(0.f),
+		mRadiusOffset(0.f),
+		mTaper(0.f,0.f),
+		mRevolutions(1.f),
+		mSkew(0.f),
+		mCRC(0)
+	{
+	}
+
+	LLPathParams(U8 curve, F32 begin, F32 end, F32 scx, F32 scy, F32 shx, F32 shy, F32 twistend, F32 twistbegin, F32 radiusoffset, F32 tx, F32 ty, F32 revolutions, F32 skew)
+		: mCurveType(curve),
+		  mBegin(begin),
+		  mEnd(end),
+		  mScale(scx,scy),
+		  mShear(shx,shy),
+		  mTwistBegin(twistbegin),
+		  mTwistEnd(twistend), 
+		  mRadiusOffset(radiusoffset),
+		  mTaper(tx,ty),
+		  mRevolutions(revolutions),
+		  mSkew(skew),
+		  mCRC(0)
+	{
+	}
+
+	LLPathParams(U8 curve, U16 begin, U16 end, U8 scx, U8 scy, U8 shx, U8 shy, U8 twistend, U8 twistbegin, U8 radiusoffset, U8 tx, U8 ty, U8 revolutions, U8 skew)
+	{
+		mCurveType = curve;
+		mBegin = (F32)(begin * CUT_QUANTA);
+		mEnd = (F32)(100.f - end) * CUT_QUANTA;
+		if (mEnd > 1.f)
+			mEnd = 1.f;
+		mScale.setVec((F32) (200 - scx) * SCALE_QUANTA,(F32) (200 - scy) * SCALE_QUANTA);
+		mShear.setVec(U8_TO_F32(shx) * SHEAR_QUANTA,U8_TO_F32(shy) * SHEAR_QUANTA);
+		mTwistBegin = U8_TO_F32(twistbegin) * SCALE_QUANTA;
+		mTwistEnd = U8_TO_F32(twistend) * SCALE_QUANTA;
+		mRadiusOffset = U8_TO_F32(radiusoffset) * SCALE_QUANTA;
+		mTaper.setVec(U8_TO_F32(tx) * TAPER_QUANTA,U8_TO_F32(ty) * TAPER_QUANTA);
+		mRevolutions = ((F32)revolutions) * REV_QUANTA + 1.0f;
+		mSkew = U8_TO_F32(skew) * SCALE_QUANTA;
+
+		mCRC = 0;
+	}
+
+	bool operator==(const LLPathParams &params) const;
+	bool operator!=(const LLPathParams &params) const;
+	bool operator<(const LLPathParams &params) const;
+
+	void copyParams(const LLPathParams &params);
+
+	BOOL importFile(LLFILE *fp);
+	BOOL exportFile(LLFILE *fp) const;
+
+	BOOL importLegacyStream(std::istream& input_stream);
+	BOOL exportLegacyStream(std::ostream& output_stream) const;
+
+	LLSD asLLSD() const;
+	operator LLSD() const { return asLLSD(); }
+	bool fromLLSD(LLSD& sd);
+
+	const F32& getBegin() const			{ return mBegin; }
+	const F32& getEnd() const			{ return mEnd; }
+	const LLVector2 &getScale() const	{ return mScale; }
+	const F32& getScaleX() const		{ return mScale.mV[0]; }
+	const F32& getScaleY() const		{ return mScale.mV[1]; }
+	const LLVector2 getBeginScale() const;
+	const LLVector2 getEndScale() const;
+	const LLVector2 &getShear() const	{ return mShear; }
+	const F32& getShearX() const		{ return mShear.mV[0]; }
+	const F32& getShearY() const		{ return mShear.mV[1]; }
+	const U8& getCurveType () const		{ return mCurveType; }
+
+	const F32& getTwistBegin() const	{ return mTwistBegin;	}
+	const F32& getTwistEnd() const		{ return mTwistEnd;	}
+	const F32& getTwist() const			{ return mTwistEnd; }	// deprecated
+	const F32& getRadiusOffset() const	{ return mRadiusOffset; }
+	const LLVector2 &getTaper() const	{ return mTaper;		}
+	const F32& getTaperX() const		{ return mTaper.mV[0];	}
+	const F32& getTaperY() const		{ return mTaper.mV[1];	}
+	const F32& getRevolutions() const	{ return mRevolutions;	}
+	const F32& getSkew() const			{ return mSkew;			}
+
+	void setCurveType(const U8 type)	{ mCurveType = type;	}
+	void setBegin(const F32 begin)		{ mBegin     = begin;	}
+	void setEnd(const F32 end)			{ mEnd       = end;	}
+
+	void setScale(const F32 x, const F32 y)		{ mScale.setVec(x,y); }
+	void setScaleX(const F32 v)					{ mScale.mV[VX] = v; }
+	void setScaleY(const F32 v)					{ mScale.mV[VY] = v; }
+	void setShear(const F32 x, const F32 y)		{ mShear.setVec(x,y); }
+	void setShearX(const F32 v)					{ mShear.mV[VX] = v; }
+	void setShearY(const F32 v)					{ mShear.mV[VY] = v; }
+
+	void setTwistBegin(const F32 twist_begin)	{ mTwistBegin	= twist_begin;	}
+	void setTwistEnd(const F32 twist_end)		{ mTwistEnd		= twist_end;	}
+	void setTwist(const F32 twist)				{ setTwistEnd(twist); }	// deprecated
+	void setRadiusOffset(const F32 radius_offset){ mRadiusOffset	= radius_offset; }
+	void setTaper(const F32 x, const F32 y)		{ mTaper.setVec(x,y);			}
+	void setTaperX(const F32 v)					{ mTaper.mV[VX]	= v;			}
+	void setTaperY(const F32 v)					{ mTaper.mV[VY]	= v;			}
+	void setRevolutions(const F32 revolutions)	{ mRevolutions	= revolutions;	}
+	void setSkew(const F32 skew)				{ mSkew			= skew;			}
+
+	friend std::ostream& operator<<(std::ostream &s, const LLPathParams &path_params);
+
+protected:
+	// Path params
+	U8			  mCurveType;
+	F32           mBegin;
+	F32           mEnd;
+	LLVector2	  mScale;
+	LLVector2     mShear;
+
+	F32			  mTwistBegin;
+	F32			  mTwistEnd;
+	F32			  mRadiusOffset;
+	LLVector2	  mTaper;
+	F32			  mRevolutions;
+	F32			  mSkew;
+
+	U32           mCRC;
+};
+
+inline bool LLPathParams::operator==(const LLPathParams &params) const
+{
+	return
+		(getCurveType() == params.getCurveType()) && 
+		(getScale() == params.getScale()) &&
+		(getBegin() == params.getBegin()) && 
+		(getEnd() == params.getEnd()) && 
+		(getShear() == params.getShear()) &&
+		(getTwist() == params.getTwist()) &&
+		(getTwistBegin() == params.getTwistBegin()) &&
+		(getRadiusOffset() == params.getRadiusOffset()) &&
+		(getTaper() == params.getTaper()) &&
+		(getRevolutions() == params.getRevolutions()) &&
+		(getSkew() == params.getSkew());
+}
+
+inline bool LLPathParams::operator!=(const LLPathParams &params) const
+{
+	return
+		(getCurveType() != params.getCurveType()) ||
+		(getScale() != params.getScale()) ||
+		(getBegin() != params.getBegin()) || 
+		(getEnd() != params.getEnd()) || 
+		(getShear() != params.getShear()) ||
+		(getTwist() != params.getTwist()) ||
+		(getTwistBegin() !=params.getTwistBegin()) ||
+		(getRadiusOffset() != params.getRadiusOffset()) ||
+		(getTaper() != params.getTaper()) ||
+		(getRevolutions() != params.getRevolutions()) ||
+		(getSkew() != params.getSkew());
+}
+
+
+inline bool LLPathParams::operator<(const LLPathParams &params) const
+{
+	if( getCurveType() != params.getCurveType()) 
+	{
+		return getCurveType() < params.getCurveType();
+	}
+	else
+	if( getScale() != params.getScale()) 
+	{
+		return getScale() < params.getScale();
+	}
+	else
+	if( getBegin() != params.getBegin()) 
+	{
+		return getBegin() < params.getBegin();
+	}
+	else
+	if( getEnd() != params.getEnd()) 
+	{
+		return getEnd() < params.getEnd();
+	}
+	else
+	if( getShear() != params.getShear()) 
+	{
+		return getShear() < params.getShear();
+	}
+	else
+	if( getTwist() != params.getTwist())
+	{
+		return getTwist() < params.getTwist();
+	}
+	else
+	if( getTwistBegin() != params.getTwistBegin())
+	{
+		return getTwistBegin() < params.getTwistBegin();
+	}
+	else
+	if( getRadiusOffset() != params.getRadiusOffset())
+	{
+		return getRadiusOffset() < params.getRadiusOffset();
+	}
+	else
+	if( getTaper() != params.getTaper())
+	{
+		return getTaper() < params.getTaper();
+	}
+	else
+	if( getRevolutions() != params.getRevolutions())
+	{
+		return getRevolutions() < params.getRevolutions();
+	}
+	else
+	{
+		return getSkew() < params.getSkew();
+	}
+}
+
+typedef LLVolumeParams* LLVolumeParamsPtr;
+typedef const LLVolumeParams* const_LLVolumeParamsPtr;
+
+class LLVolumeParams
+{
+public:
+	LLVolumeParams()
+		: mSculptType(LL_SCULPT_TYPE_NONE)
+	{
+	}
+
+	LLVolumeParams(LLProfileParams &profile, LLPathParams &path,
+				   LLUUID sculpt_id = LLUUID::null, U8 sculpt_type = LL_SCULPT_TYPE_NONE)
+		: mProfileParams(profile), mPathParams(path), mSculptID(sculpt_id), mSculptType(sculpt_type)
+	{
+	}
+
+	bool operator==(const LLVolumeParams &params) const;
+	bool operator!=(const LLVolumeParams &params) const;
+	bool operator<(const LLVolumeParams &params) const;
+
+
+	void copyParams(const LLVolumeParams &params);
+	
+	const LLProfileParams &getProfileParams() const {return mProfileParams;}
+	LLProfileParams &getProfileParams() {return mProfileParams;}
+	const LLPathParams &getPathParams() const {return mPathParams;}
+	LLPathParams &getPathParams() {return mPathParams;}
+
+	BOOL importFile(LLFILE *fp);
+	BOOL exportFile(LLFILE *fp) const;
+
+	BOOL importLegacyStream(std::istream& input_stream);
+	BOOL exportLegacyStream(std::ostream& output_stream) const;
+
+	LLSD sculptAsLLSD() const;
+	bool sculptFromLLSD(LLSD& sd);
+	
+	LLSD asLLSD() const;
+	operator LLSD() const { return asLLSD(); }
+	bool fromLLSD(LLSD& sd);
+
+	bool setType(U8 profile, U8 path);
+
+	//void setBeginS(const F32 beginS)			{ mProfileParams.setBegin(beginS); }	// range 0 to 1
+	//void setBeginT(const F32 beginT)			{ mPathParams.setBegin(beginT); }		// range 0 to 1
+	//void setEndS(const F32 endS)				{ mProfileParams.setEnd(endS); }		// range 0 to 1, must be greater than begin
+	//void setEndT(const F32 endT)				{ mPathParams.setEnd(endT); }			// range 0 to 1, must be greater than begin
+
+	bool setBeginAndEndS(const F32 begin, const F32 end);			// both range from 0 to 1, begin must be less than end
+	bool setBeginAndEndT(const F32 begin, const F32 end);			// both range from 0 to 1, begin must be less than end
+
+	bool setHollow(const F32 hollow);	// range 0 to 1
+	bool setRatio(const F32 x)					{ return setRatio(x,x); }			// 0 = point, 1 = same as base
+	bool setShear(const F32 x)					{ return setShear(x,x); }			// 0 = no movement, 
+	bool setRatio(const F32 x, const F32 y);			// 0 = point, 1 = same as base
+	bool setShear(const F32 x, const F32 y);			// 0 = no movement
+
+	bool setTwistBegin(const F32 twist_begin);	// range -1 to 1
+	bool setTwistEnd(const F32 twist_end);		// range -1 to 1
+	bool setTwist(const F32 twist)				{ return setTwistEnd(twist); }		// deprecated
+	bool setTaper(const F32 x, const F32 y)		{ bool pass_x = setTaperX(x); bool pass_y = setTaperY(y); return pass_x && pass_y; }
+	bool setTaperX(const F32 v);				// -1 to 1
+	bool setTaperY(const F32 v);				// -1 to 1
+	bool setRevolutions(const F32 revolutions);	// 1 to 4
+	bool setRadiusOffset(const F32 radius_offset);
+	bool setSkew(const F32 skew);
+	bool setSculptID(const LLUUID sculpt_id, U8 sculpt_type);
+
+	static bool validate(U8 prof_curve, F32 prof_begin, F32 prof_end, F32 hollow,
+		U8 path_curve, F32 path_begin, F32 path_end,
+		F32 scx, F32 scy, F32 shx, F32 shy,
+		F32 twistend, F32 twistbegin, F32 radiusoffset,
+		F32 tx, F32 ty, F32 revolutions, F32 skew);
+	
+	const F32&  getBeginS() 	const	{ return mProfileParams.getBegin(); }
+ 	const F32&  getBeginT() 	const	{ return mPathParams.getBegin(); }
+ 	const F32&  getEndS() 		const	{ return mProfileParams.getEnd(); }
+ 	const F32&  getEndT() 		const	{ return mPathParams.getEnd(); }
+ 
+ 	const F32&  getHollow() 	const   { return mProfileParams.getHollow(); }
+ 	const F32&  getTwist() 	const   	{ return mPathParams.getTwist(); }
+ 	const F32&  getRatio() 	const		{ return mPathParams.getScaleX(); }
+ 	const F32&  getRatioX() 	const   { return mPathParams.getScaleX(); }
+ 	const F32&  getRatioY() 	const   { return mPathParams.getScaleY(); }
+ 	const F32&  getShearX() 	const   { return mPathParams.getShearX(); }
+ 	const F32&  getShearY() 	const   { return mPathParams.getShearY(); }
+
+	const F32&	getTwistBegin()const	{ return mPathParams.getTwistBegin();	}
+	const F32&  getRadiusOffset() const	{ return mPathParams.getRadiusOffset();	}
+	const F32&  getTaper() const		{ return mPathParams.getTaperX();		}
+	const F32&	getTaperX() const		{ return mPathParams.getTaperX();		}
+	const F32&  getTaperY() const		{ return mPathParams.getTaperY();		}
+	const F32&  getRevolutions() const	{ return mPathParams.getRevolutions();	}
+	const F32&  getSkew() const			{ return mPathParams.getSkew();			}
+	const LLUUID& getSculptID() const	{ return mSculptID;						}
+	const U8& getSculptType() const     { return mSculptType;                   }
+	bool isSculpt() const;
+	bool isMeshSculpt() const;
+	BOOL isConvex() const;
+
+	// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
+	// (begin, end) = (0, 1) will not change the volume
+	// (begin, end) = (0, 0.5) will reduce the volume to the first half of its profile/path (S/T)
+	void reduceS(F32 begin, F32 end);
+	void reduceT(F32 begin, F32 end);
+
+	struct compare
+	{
+		bool operator()( const const_LLVolumeParamsPtr& first, const const_LLVolumeParamsPtr& second) const
+		{
+			return (*first < *second);
+		}
+	};
+	
+	friend std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
+
+	// debug helper functions
+	void setCube();
+
+protected:
+	LLProfileParams mProfileParams;
+	LLPathParams	mPathParams;
+	LLUUID mSculptID;
+	U8 mSculptType;
+};
+
+
+class LLProfile
+{
+public:
+	LLProfile()
+		: mOpen(FALSE),
+		  mConcave(FALSE),
+		  mDirty(TRUE),
+		  mTotalOut(0),
+		  mTotal(2)
+	{
+	}
+
+	~LLProfile();
+
+	S32	 getTotal() const								{ return mTotal; }
+	S32	 getTotalOut() const							{ return mTotalOut; }	// Total number of outside points
+	BOOL isFlat(S32 face) const							{ return (mFaces[face].mCount == 2); }
+	BOOL isOpen() const									{ return mOpen; }
+	void setDirty()										{ mDirty     = TRUE; }
+	BOOL generate(const LLProfileParams& params, BOOL path_open, F32 detail = 1.0f, S32 split = 0,
+				  BOOL is_sculpted = FALSE, S32 sculpt_size = 0);
+	BOOL isConcave() const								{ return mConcave; }
+public:
+	struct Face
+	{
+		S32       mIndex;
+		S32       mCount;
+		F32       mScaleU;
+		BOOL      mCap;
+		BOOL      mFlat;
+		LLFaceID  mFaceID;
+	};
+	
+	std::vector<LLVector3> mProfile;	
+	std::vector<LLVector2> mNormals;
+	std::vector<Face>      mFaces;
+	std::vector<LLVector3> mEdgeNormals;
+	std::vector<LLVector3> mEdgeCenters;
+
+	friend std::ostream& operator<<(std::ostream &s, const LLProfile &profile);
+
+protected:
+	void genNormals(const LLProfileParams& params);
+	void genNGon(const LLProfileParams& params, S32 sides, F32 offset=0.0f, F32 bevel = 0.0f, F32 ang_scale = 1.f, S32 split = 0);
+
+	Face* addHole(const LLProfileParams& params, BOOL flat, F32 sides, F32 offset, F32 box_hollow, F32 ang_scale, S32 split = 0);
+	Face* addCap (S16 faceID);
+	Face* addFace(S32 index, S32 count, F32 scaleU, S16 faceID, BOOL flat);
+
+protected:
+	BOOL		  mOpen;
+	BOOL		  mConcave;
+	BOOL          mDirty;
+
+	S32			  mTotalOut;
+	S32			  mTotal;
+};
+
+//-------------------------------------------------------------------
+// SWEEP/EXTRUDE PATHS
+//-------------------------------------------------------------------
+
+class LLPath
+{
+public:
+	struct PathPt
+	{
+		LLVector3	 mPos;
+		LLVector2    mScale;
+		LLQuaternion mRot;
+		F32			 mTexT;
+		PathPt() { mPos.setVec(0,0,0); mTexT = 0; mScale.setVec(0,0); mRot.loadIdentity(); }
+	};
+
+public:
+	LLPath()
+		: mOpen(FALSE),
+		  mTotal(0),
+		  mDirty(TRUE),
+		  mStep(1)
+	{
+	}
+
+	virtual ~LLPath();
+
+	void genNGon(const LLPathParams& params, S32 sides, F32 offset=0.0f, F32 end_scale = 1.f, F32 twist_scale = 1.f);
+	virtual BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0,
+						  BOOL is_sculpted = FALSE, S32 sculpt_size = 0);
+
+	BOOL isOpen() const						{ return mOpen; }
+	F32 getStep() const						{ return mStep; }
+	void setDirty()							{ mDirty     = TRUE; }
+
+	S32 getPathLength() const				{ return (S32)mPath.size(); }
+
+	void resizePath(S32 length) { mPath.resize(length); }
+
+	friend std::ostream& operator<<(std::ostream &s, const LLPath &path);
+
+public:
+	std::vector<PathPt> mPath;
+
+protected:
+	BOOL		  mOpen;
+	S32			  mTotal;
+	BOOL          mDirty;
+	F32           mStep;
+};
+
+class LLDynamicPath : public LLPath
+{
+public:
+	LLDynamicPath() : LLPath() { }
+	/*virtual*/ BOOL generate(const LLPathParams& params, F32 detail=1.0f, S32 split = 0,
+							  BOOL is_sculpted = FALSE, S32 sculpt_size = 0);
+};
+
+// Yet another "face" class - caches volume-specific, but not instance-specific data for faces)
+class LLVolumeFace
+{
+public:
+	class VertexData
+	{
+		enum 
+		{
+			POSITION = 0,
+			NORMAL = 1
+		};
+
+	private:
+		void init();
+	public:
+		VertexData();
+		VertexData(const VertexData& rhs);
+		const VertexData& operator=(const VertexData& rhs);
+
+		~VertexData();
+		LLVector4a& getPosition();
+		LLVector4a& getNormal();
+		const LLVector4a& getPosition() const;
+		const LLVector4a& getNormal() const;
+		void setPosition(const LLVector4a& pos);
+		void setNormal(const LLVector4a& norm);
+		
+
+		LLVector2 mTexCoord;
+
+		bool operator<(const VertexData& rhs) const;
+		bool operator==(const VertexData& rhs) const;
+		bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const;
+
+	private:
+		LLVector4a* mData;
+	};
+
+	LLVolumeFace();
+	LLVolumeFace(const LLVolumeFace& src);
+	LLVolumeFace& operator=(const LLVolumeFace& rhs);
+
+	~LLVolumeFace();
+private:
+	void freeData();
+public:
+
+	BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
+	void createBinormals();
+	
+	void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform);
+
+	void resizeVertices(S32 num_verts);
+	void allocateBinormals(S32 num_verts);
+	void allocateWeights(S32 num_verts);
+	void resizeIndices(S32 num_indices);
+	void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
+
+	void pushVertex(const VertexData& cv);
+	void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc);
+	void pushIndex(const U16& idx);
+
+	void swapData(LLVolumeFace& rhs);
+
+	void getVertexData(U16 indx, LLVolumeFace::VertexData& cv);
+
+	class VertexMapData : public LLVolumeFace::VertexData
+	{
+	public:
+		U16 mIndex;
+
+		bool operator==(const LLVolumeFace::VertexData& rhs) const;
+
+		struct ComparePosition
+		{
+			bool operator()(const LLVector3& a, const LLVector3& b) const;
+		};
+
+		typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
+	};
+
+	void optimize(F32 angle_cutoff = 2.f);
+	void cacheOptimize();
+
+	void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
+
+	enum
+	{
+		SINGLE_MASK =	0x0001,
+		CAP_MASK =		0x0002,
+		END_MASK =		0x0004,
+		SIDE_MASK =		0x0008,
+		INNER_MASK =	0x0010,
+		OUTER_MASK =	0x0020,
+		HOLLOW_MASK =	0x0040,
+		OPEN_MASK =		0x0080,
+		FLAT_MASK =		0x0100,
+		TOP_MASK =		0x0200,
+		BOTTOM_MASK =	0x0400
+	};
+	
+public:
+	S32 mID;
+	U32 mTypeMask;
+	
+	// Only used for INNER/OUTER faces
+	S32 mBeginS;
+	S32 mBeginT;
+	S32 mNumS;
+	S32 mNumT;
+
+	LLVector4a* mExtents; //minimum and maximum point of face
+	LLVector4a* mCenter;
+	LLVector2 mTexCoordExtents[2]; //minimum and maximum of texture coordinates of the face.
+
+	S32 mNumVertices;
+	S32 mNumIndices;
+
+	LLVector4a* mPositions;
+	LLVector4a* mNormals;
+	LLVector4a* mBinormals;
+	LLVector2* mTexCoords;
+	U16* mIndices;
+
+	std::vector<S32>	mEdge;
+
+	//list of skin weights for rigged volumes
+	// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
+	// mWeights.size() should be empty or match mVertices.size()  
+	LLVector4a* mWeights;
+
+	LLOctreeNode<LLVolumeTriangle>* mOctree;
+
+private:
+	BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
+	BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
+	BOOL createSide(LLVolume* volume, BOOL partial_build = FALSE);
+};
+
+class LLVolume : public LLRefCount
+{
+	friend class LLVolumeLODGroup;
+
+protected:
+	~LLVolume(); // use unref
+
+public:
+	struct Point
+	{
+		LLVector3 mPos;
+	};
+
+	struct FaceParams
+	{
+		LLFaceID mFaceID;
+		S32 mBeginS;
+		S32 mCountS;
+		S32 mBeginT;
+		S32 mCountT;
+	};
+
+	LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL generate_single_face = FALSE, const BOOL is_unique = FALSE);
+	
+	U8 getProfileType()	const								{ return mParams.getProfileParams().getCurveType(); }
+	U8 getPathType() const									{ return mParams.getPathParams().getCurveType(); }
+	S32	getNumFaces() const;
+	S32 getNumVolumeFaces() const							{ return mVolumeFaces.size(); }
+	F32 getDetail() const									{ return mDetail; }
+	const LLVolumeParams& getParams() const					{ return mParams; }
+	LLVolumeParams getCopyOfParams() const					{ return mParams; }
+	const LLProfile& getProfile() const						{ return *mProfilep; }
+	LLPath& getPath() const									{ return *mPathp; }
+	void resizePath(S32 length);
+	const std::vector<Point>& getMesh() const				{ return mMesh; }
+	const LLVector3& getMeshPt(const U32 i) const			{ return mMesh[i].mPos; }
+
+	void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); }
+
+	void regen();
+	void genBinormals(S32 face);
+
+	BOOL isConvex() const;
+	BOOL isCap(S32 face);
+	BOOL isFlat(S32 face);
+	BOOL isUnique() const									{ return mUnique; }
+
+	S32 getSculptLevel() const                              { return mSculptLevel; }
+	void setSculptLevel(S32 level)							{ mSculptLevel = level; }
+
+	S32 *getTriangleIndices(U32 &num_indices) const;
+
+	// returns number of triangle indeces required for path/profile mesh
+	S32 getNumTriangleIndices() const;
+
+	S32 getNumTriangles() const;
+
+	void generateSilhouetteVertices(std::vector<LLVector3> &vertices, 
+									std::vector<LLVector3> &normals, 
+									std::vector<S32> &segments, 
+									const LLVector3& view_vec,
+									const LLMatrix4& mat,
+									const LLMatrix3& norm_mat,
+									S32 face_index);
+
+	//get the face index of the face that intersects with the given line segment at the point 
+	//closest to start.  Moves end to the point of intersection.  Returns -1 if no intersection.
+	//Line segment must be in volume space.
+	S32 lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+							 S32 face = -1,                          // which face to check, -1 = ALL_SIDES
+							 LLVector3* intersection = NULL,         // return the intersection point
+							 LLVector2* tex_coord = NULL,            // return the texture coordinates of the intersection point
+							 LLVector3* normal = NULL,               // return the surface normal at the intersection point
+							 LLVector3* bi_normal = NULL             // return the surface bi-normal at the intersection point
+		);
+
+	S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
+								   S32 face = 1,
+								   LLVector3* intersection = NULL,
+								   LLVector2* tex_coord = NULL,
+								   LLVector3* normal = NULL,
+								   LLVector3* bi_normal = NULL);
+	
+	// The following cleans up vertices and triangles,
+	// getting rid of degenerate triangles and duplicate vertices,
+	// and allocates new arrays with the clean data.
+	static BOOL cleanupTriangleData( const S32 num_input_vertices,
+								const std::vector<Point> &input_vertices,
+								const S32 num_input_triangles,
+								S32 *input_triangles,
+								S32 &num_output_vertices,
+								LLVector3 **output_vertices,
+								S32 &num_output_triangles,
+								S32 **output_triangles);
+	LLFaceID generateFaceMask();
+
+	BOOL isFaceMaskValid(LLFaceID face_mask);
+	static S32 sNumMeshPoints;
+
+	friend std::ostream& operator<<(std::ostream &s, const LLVolume &volume);
+	friend std::ostream& operator<<(std::ostream &s, const LLVolume *volumep);		// HACK to bypass Windoze confusion over 
+																				// conversion if *(LLVolume*) to LLVolume&
+	const LLVolumeFace &getVolumeFace(const S32 f) const {return mVolumeFaces[f];} // DO NOT DELETE VOLUME WHILE USING THIS REFERENCE, OR HOLD A POINTER TO THIS VOLUMEFACE
+	
+	U32					mFaceMask;			// bit array of which faces exist in this volume
+	LLVector3			mLODScaleBias;		// vector for biasing LOD based on scale
+	
+	void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level);
+	void copyVolumeFaces(const LLVolume* volume);
+	void cacheOptimize();
+
+private:
+	void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type);
+	F32 sculptGetSurfaceArea();
+	void sculptGeneratePlaceholder();
+	void sculptCalcMeshResolution(U16 width, U16 height, U8 type, S32& s, S32& t);
+
+	
+protected:
+	BOOL generate();
+	void createVolumeFaces();
+public:
+	virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
+	virtual BOOL createVolumeFacesFromStream(std::istream& is);
+	virtual bool unpackVolumeFaces(std::istream& is, S32 size);
+
+	virtual void makeTetrahedron();
+	virtual BOOL isTetrahedron();
+
+ protected:
+	BOOL mUnique;
+	F32 mDetail;
+	S32 mSculptLevel;
+	BOOL mIsTetrahedron;
+	
+	LLVolumeParams mParams;
+	LLPath *mPathp;
+	LLProfile *mProfilep;
+	std::vector<Point> mMesh;
+	
+	BOOL mGenerateSingleFace;
+	typedef std::vector<LLVolumeFace> face_list_t;
+	face_list_t mVolumeFaces;
+
+public:
+	LLVector4a* mHullPoints;
+	U16* mHullIndices;
+	S32 mNumHullPoints;
+	S32 mNumHullIndices;
+};
+
+std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
+
+void calc_binormal_from_triangle(
+		LLVector4a& binormal,
+		const LLVector4a& pos0,
+		const LLVector2& tex0,
+		const LLVector4a& pos1,
+		const LLVector2& tex1,
+		const LLVector4a& pos2,
+		const LLVector2& tex2);
+
+BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size);
+BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
+BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size);
+
+BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided);
+
+BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t);
+BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t);
+	
+	
+
+#endif
diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h
index f696cbd976..688d91dc40 100644
--- a/indra/llmath/llvolumeoctree.h
+++ b/indra/llmath/llvolumeoctree.h
@@ -34,6 +34,41 @@
 #include "llvolume.h"
 #include "llvector4a.h"
 
+class LLVolumeTriangle : public LLRefCount
+{
+public:
+	LLVolumeTriangle()
+	{
+		
+	}
+
+	LLVolumeTriangle(const LLVolumeTriangle& rhs)
+	{
+		*this = rhs;
+	}
+
+	const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs)
+	{
+		llerrs << "Illegal operation!" << llendl;
+		return *this;
+	}
+
+	~LLVolumeTriangle()
+	{
+	
+	}
+
+	LLVector4a mPositionGroup;
+
+	const LLVector4a* mV[3];
+	U16 mIndex[3];
+
+	F32 mRadius;
+
+	virtual const LLVector4a& getPositionGroup() const;
+	virtual const F32& getBinRadius() const;
+};
+
 class LLVolumeOctreeListener : public LLOctreeListener<LLVolumeTriangle>
 {
 public:
@@ -91,41 +126,6 @@ public:
 	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* node);
 };
 
-class LLVolumeTriangle : public LLRefCount
-{
-public:
-	LLVolumeTriangle()
-	{
-		
-	}
-
-	LLVolumeTriangle(const LLVolumeTriangle& rhs)
-	{
-		*this = rhs;
-	}
-
-	const LLVolumeTriangle& operator=(const LLVolumeTriangle& rhs)
-	{
-		llerrs << "Illegal operation!" << llendl;
-		return *this;
-	}
-
-	~LLVolumeTriangle()
-	{
-	
-	}
-
-	LLVector4a mPositionGroup;
-
-	const LLVector4a* mV[3];
-	U16 mIndex[3];
-
-	F32 mRadius;
-
-	virtual const LLVector4a& getPositionGroup() const;
-	virtual const F32& getBinRadius() const;
-};
-
 class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle>
 {
 	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch);
-- 
cgit v1.2.3