diff --git a/.hgignore b/.hgignore
index 53ddf71bb79ecb63c743d8f67bd5f8271400142a..94127df2d11488aa57c392edbfc98ab9980940a9 100644
--- a/.hgignore
+++ b/.hgignore
@@ -9,6 +9,7 @@ syntax: glob
 .*.swp
 #OSX image cache file
 *.DS_Store
+*.orig
 LICENSES
 indra/.distcc
 indra/build-darwin-*
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 592e9fc901b5dbd73581320c256c33c77823df6c..113e21a715507b7e8473a93adfd8966a9ccf34f8 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -35,10 +35,10 @@ if (WINDOWS)
   # Don't build DLLs.
   set(BUILD_SHARED_LIBS OFF)
 
-  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP"
+  set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /ZI /MDd /MP"
       CACHE STRING "C++ compiler debug options" FORCE)
   set(CMAKE_CXX_FLAGS_RELWITHDEBINFO 
-      "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP"
+      "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /ZI /MD /MP"
       CACHE STRING "C++ compiler release-with-debug options" FORCE)
   set(CMAKE_CXX_FLAGS_RELEASE
       "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP"
@@ -49,11 +49,12 @@ if (WINDOWS)
 
   add_definitions(
       /DLL_WINDOWS=1
+      /DDOM_DYNAMIC
       /DUNICODE
       /D_UNICODE 
       /GS
       /TP
-      /W3
+      /W2
       /c
       /Zc:forScope
       /nologo
@@ -207,7 +208,7 @@ if (LINUX OR DARWIN)
     set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
   endif (NOT GCC_DISABLE_FATAL_WARNINGS)
 
-  set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor -Woverloaded-virtual")
+  set(GCC_CXX_WARNINGS "${GCC_WARNINGS} -Wno-reorder -Wno-non-virtual-dtor")
 
   set(CMAKE_C_FLAGS "${GCC_WARNINGS} ${CMAKE_C_FLAGS}")
   set(CMAKE_CXX_FLAGS "${GCC_CXX_WARNINGS} ${CMAKE_CXX_FLAGS}")
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index faf9da8b148e96f3b7c1d34d93c5d365be6f0db6..c9dc301b8be7a93ded3b616a685d06080e1c15c0 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -19,7 +19,7 @@ if(WINDOWS)
     set(vivox_src_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-win32")
     set(vivox_files
         SLVoice.exe
-	libsndfile-1.dll
+        libsndfile-1.dll
         vivoxplatform.dll
         vivoxsdk.dll
         ortp.dll
@@ -38,6 +38,8 @@ if(WINDOWS)
         libapr-1.dll
         libaprutil-1.dll
         libapriconv-1.dll
+        libcollada14dom21.dll
+        glod.dll
         )
 
     # *TODO - update this to use LIBS_PREBUILT_DIR and LL_ARCH_DIR variables
@@ -48,6 +50,8 @@ if(WINDOWS)
         libapr-1.dll
         libaprutil-1.dll
         libapriconv-1.dll
+        libcollada14dom21.dll
+        glod.dll
         )
 
     if(USE_GOOGLE_PERFTOOLS)
diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake
index d397b78f1c91109bc6638aa31037ae38bc4ba2fd..9f8d99a0bf02c005c23555cfb5820a5ab0e5ef40 100644
--- a/indra/cmake/LLPrimitive.cmake
+++ b/indra/cmake/LLPrimitive.cmake
@@ -1,7 +1,27 @@
 # -*- cmake -*-
 
+# these should be moved to their own cmake file
+include(Prebuilt)
+use_prebuilt_binary(colladadom)
+use_prebuilt_binary(pcre)
+use_prebuilt_binary(libxml)
+
 set(LLPRIMITIVE_INCLUDE_DIRS
     ${LIBS_OPEN_DIR}/llprimitive
     )
 
-set(LLPRIMITIVE_LIBRARIES llprimitive)
+if (WINDOWS)
+    set(LLPRIMITIVE_LIBRARIES 
+        llprimitive
+        libcollada14dom21
+        )
+else (WINDOWS)
+    set(LLPRIMITIVE_LIBRARIES 
+        llprimitive
+        collada14dom
+        xml2
+        pcrecpp
+        pcre
+        )
+endif (WINDOWS)
+
diff --git a/indra/cmake/Variables.cmake b/indra/cmake/Variables.cmake
index db0b44eb8f0104a236aa823bf3f8f07758258043..9b1f7024bfddd9679891dc658dc7fd73698c34ee 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -79,7 +79,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
   # NOTE: wont have a distributable build unless you add this on the configure line with:
   # -DCMAKE_OSX_ARCHITECTURES:STRING='i386;ppc'
   #set(CMAKE_OSX_ARCHITECTURES i386;ppc)
-  set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.4u.sdk)
+  set(CMAKE_OSX_SYSROOT /Developer/SDKs/MacOSX10.5.sdk)
   if (CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc")
     set(ARCH universal)
   else (CMAKE_OSX_ARCHITECTURES MATCHES "i386" AND CMAKE_OSX_ARCHITECTURES MATCHES "ppc")
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 1c664e093b78ed35970968afb3242a6fd5c8e6da..9dab9d9582e694b86b80302fde6a2ac753be508a 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -100,7 +100,10 @@ LLAssetDictionary::LLAssetDictionary()
 	addEntry(LLAssetType::AT_LINK, 				new AssetEntry("LINK",				"link",		"sym link",			false,		false,		true));
 	addEntry(LLAssetType::AT_LINK_FOLDER, 		new AssetEntry("FOLDER_LINK",		"link_f", 	"sym folder link",	false,		false,		true));
 
-	addEntry(LLAssetType::AT_NONE, 				new AssetEntry("NONE",				"-1",		NULL,		  		false,		false,		false));
+	addEntry(LLAssetType::AT_MESH,              new AssetEntry("MESH",              "mesh",     "mesh",             false, false, false));
+	
+	addEntry(LLAssetType::AT_NONE, 				new AssetEntry("NONE",				"-1",		NULL,		  		FALSE,		FALSE,		FALSE));
+
 };
 
 // static
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 2c2dc27aaa47806d6ccd7e56e05c218a084e4276..90cd03c43344d4fb4898a45bacb4bb1fa738662e 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -114,8 +114,11 @@ class LL_COMMON_API LLAssetType
 
 		AT_LINK_FOLDER = 25,
 			// Inventory folder link
-		
-		AT_COUNT = 26,
+
+		AT_MESH = 49,
+		    // Mesh data in our proprietary SLM format
+
+		AT_COUNT = 50,
 
 			// +*********************************************************+
 			// |  TO ADD AN ELEMENT TO THIS ENUM:                        |
diff --git a/indra/llcommon/lldarray.h b/indra/llcommon/lldarray.h
index 0e56a11d530f99e640a5b1cddb559e6463b4ad93..af647c7e7afff743fb6f40d03ccc15321e8391d8 100644
--- a/indra/llcommon/lldarray.h
+++ b/indra/llcommon/lldarray.h
@@ -202,7 +202,7 @@ class LLDynamicArrayIndexed
 		{
 			U32 n = mVector.size();
 			mIndexMap[k] = n;
-			mVector.resize(n+1);
+			mVector.push_back(Type());
 			llassert(mVector.size() == mIndexMap.size());
 			return mVector[n];
 		}
diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp
index 2610fe9e6a0f249066d8312de00c2feb9531eb0a..16ae4cddde4cdb0d20213aa4c30b59cca883edca 100644
--- a/indra/llcommon/llfoldertype.cpp
+++ b/indra/llcommon/llfoldertype.cpp
@@ -95,6 +95,9 @@ LLFolderDictionary::LLFolderDictionary()
 	addEntry(LLFolderType::FT_CURRENT_OUTFIT, 		new FolderEntry("current",	TRUE));
 	addEntry(LLFolderType::FT_OUTFIT, 				new FolderEntry("outfit",	FALSE));
 	addEntry(LLFolderType::FT_MY_OUTFITS, 			new FolderEntry("my_otfts",	TRUE));
+
+	addEntry(LLFolderType::FT_MESH, 				new FolderEntry("mesh",	TRUE));
+
 	addEntry(LLFolderType::FT_INBOX, 				new FolderEntry("inbox",	TRUE));
 		 
 	addEntry(LLFolderType::FT_NONE, 				new FolderEntry("-1",		FALSE));
diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h
index 7aa77f7f7e43fac7144c045f083ed15772a0737f..409112a04ee5631d5fb2f7d61a1dcf390519a482 100644
--- a/indra/llcommon/llfoldertype.h
+++ b/indra/llcommon/llfoldertype.h
@@ -86,9 +86,11 @@ class LL_COMMON_API LLFolderType
 		FT_OUTFIT = 47,
 		FT_MY_OUTFITS = 48,
 		
-		FT_INBOX = 49,
+		FT_MESH = 49,
 
-		FT_COUNT = 50,
+		FT_INBOX = 50,
+
+		FT_COUNT = 51,
 
 		FT_NONE = -1
 	};
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 37370e44e785c8f44f7265673e66b99d2806de08..0385569a02e1e4cdcb3acac727879419199c0680 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -62,6 +62,12 @@
 // 
 //----------------------------------------------------------------------------
 
+#if !LL_DARWIN
+U32 ll_thread_local sThreadID = 0;
+#endif 
+
+U32 LLThread::sIDIter = 0;
+
 //
 // Handed to the APR thread creation function
 //
@@ -72,10 +78,14 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
 	// Set thread state to running
 	threadp->mStatus = RUNNING;
 
+#if !LL_DARWIN
+	sThreadID = threadp->mID;
+#endif
+
 	// Run the user supplied function
 	threadp->run();
 
-	llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;
+	//llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;
 	
 	// We're done with the run function, this thread is done executing now.
 	threadp->mStatus = STOPPED;
@@ -90,6 +100,8 @@ LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
 	mAPRThreadp(NULL),
 	mStatus(STOPPED)
 {
+	mID = ++sIDIter;
+
 	// Thread creation probably CAN be paranoid about APR being initialized, if necessary
 	if (poolp)
 	{
@@ -273,7 +285,7 @@ void LLThread::wakeLocked()
 //============================================================================
 
 LLMutex::LLMutex(apr_pool_t *poolp) :
-	mAPRMutexp(NULL)
+	mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD)
 {
 	//if (poolp)
 	//{
@@ -305,7 +317,18 @@ LLMutex::~LLMutex()
 
 void LLMutex::lock()
 {
+#if LL_DARWIN
+	if (mLockingThread == LLThread::currentID())
+#else
+	if (mLockingThread == sThreadID)
+#endif
+	{ //redundant lock
+		mCount++;
+		return;
+	}
+	
 	apr_thread_mutex_lock(mAPRMutexp);
+	
 #if MUTEX_DEBUG
 	// Have to have the lock before we can access the debug info
 	U32 id = LLThread::currentID();
@@ -313,10 +336,22 @@ void LLMutex::lock()
 		llerrs << "Already locked in Thread: " << id << llendl;
 	mIsLocked[id] = TRUE;
 #endif
+
+#if LL_DARWIN
+	mLockingThread = LLThread::currentID();
+#else
+	mLockingThread = sThreadID;
+#endif
 }
 
 void LLMutex::unlock()
 {
+	if (mCount > 0)
+	{ //not the root unlock
+		mCount--;
+		return;
+	}
+	
 #if MUTEX_DEBUG
 	// Access the debug info while we have the lock
 	U32 id = LLThread::currentID();
@@ -324,6 +359,8 @@ void LLMutex::unlock()
 		llerrs << "Not locked in Thread: " << id << llendl;	
 	mIsLocked[id] = FALSE;
 #endif
+
+	mLockingThread = NO_THREAD;
 	apr_thread_mutex_unlock(mAPRMutexp);
 }
 
@@ -341,6 +378,11 @@ bool LLMutex::isLocked()
 	}
 }
 
+U32 LLMutex::lockingThread() const
+{
+	return mLockingThread;
+}
+
 //============================================================================
 
 LLCondition::LLCondition(apr_pool_t *poolp) :
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index adef1a91926609acc3ad75878afb485ec27093ee..4b6c3df10554fe9a0e345c2a9f884b447207bec4 100644
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -41,8 +41,17 @@ class LLThread;
 class LLMutex;
 class LLCondition;
 
+#if LL_WINDOWS
+#define ll_thread_local __declspec(thread)
+#else
+#define ll_thread_local __thread
+#endif
+
 class LL_COMMON_API LLThread
 {
+private:
+	static U32 sIDIter;
+
 public:
 	typedef enum e_thread_status
 	{
@@ -83,6 +92,8 @@ class LL_COMMON_API LLThread
 	apr_pool_t *getAPRPool() { return mAPRPoolp; }
 	LLVolatileAPRPool* getLocalAPRFilePool() { return mLocalAPRFilePoolp ; }
 
+	U32 getID() const { return mID; }
+
 private:
 	BOOL				mPaused;
 	
@@ -97,6 +108,7 @@ class LL_COMMON_API LLThread
 	apr_pool_t			*mAPRPoolp;
 	BOOL				mIsLocalPool;
 	EThreadStatus		mStatus;
+	U32					mID;
 
 	//a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used.
 	//Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes.
@@ -134,17 +146,27 @@ class LL_COMMON_API LLThread
 class LL_COMMON_API LLMutex
 {
 public:
+	typedef enum
+	{
+		NO_THREAD = 0xFFFFFFFF
+	} e_locking_thread;
+
 	LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex
 	~LLMutex();
 	
 	void lock();		// blocks
 	void unlock();
 	bool isLocked(); 	// non-blocking, but does do a lock/unlock so not free
+	U32 lockingThread() const; //get ID of locking thread
 	
 protected:
 	apr_thread_mutex_t *mAPRMutexp;
+	mutable U32			mCount;
+	mutable U32			mLockingThread;
+	
 	apr_pool_t			*mAPRPoolp;
 	BOOL				mIsLocalPool;
+	
 #if MUTEX_DEBUG
 	std::map<U32, BOOL> mIsLocked;
 #endif
diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h
index 1a5678dde1340fc0c78d2d1d178418c7cf0214c1..6eead924dadf217f812750335ce928cb4d6c8f07 100644
--- a/indra/llcommon/stdenums.h
+++ b/indra/llcommon/stdenums.h
@@ -55,7 +55,8 @@ enum EDragAndDropType
 	DAD_ANIMATION		= 12,
 	DAD_GESTURE			= 13,
 	DAD_LINK			= 14,
-	DAD_COUNT			= 15,   // number of types in this enum
+	DAD_MESH           		= 15,
+	DAD_COUNT			= 16,   // number of types in this enum
 };
 
 // Reasons for drags to be denied.
diff --git a/indra/llcrashlogger/llcrashlogger.cpp b/indra/llcrashlogger/llcrashlogger.cpp
index c1022c1195ec62bed7ed615276ca1da1ce3f274f..4bda00ed86865b780f04a73ecf79f29b3e4cbad8 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -370,6 +370,8 @@ void LLCrashLogger::updateApplication(const std::string& message)
 
 bool LLCrashLogger::init()
 {
+	LLCurl::initClass();
+
 	// We assume that all the logs we're looking for reside on the current drive
 	gDirUtilp->initAppDirs("SecondLife");
 
diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp
index 4ef5df0b2897fc429ff47d15bddbc6f9b8526a49..c2686250645aebfced17357b68471488ed2a1abd 100644
--- a/indra/llinventory/llinventorytype.cpp
+++ b/indra/llinventory/llinventorytype.cpp
@@ -89,6 +89,8 @@ LLInventoryDictionary::LLInventoryDictionary()
 	addEntry(LLInventoryType::IT_WEARABLE,            new InventoryEntry("wearable",  "wearable",      2, LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART));
 	addEntry(LLInventoryType::IT_ANIMATION,           new InventoryEntry("animation", "animation",     1, LLAssetType::AT_ANIMATION));  
 	addEntry(LLInventoryType::IT_GESTURE,             new InventoryEntry("gesture",   "gesture",       1, LLAssetType::AT_GESTURE)); 
+	addEntry(LLInventoryType::IT_MESH,                new InventoryEntry("mesh",      "mesh",          1, LLAssetType::AT_MESH));
+
 }
 
 
@@ -123,6 +125,33 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
 
 	LLInventoryType::IT_NONE,			// AT_LINK
 	LLInventoryType::IT_NONE,			// AT_LINK_FOLDER
+
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	LLInventoryType::IT_NONE,			// AT_NONE
+	
+	LLInventoryType::IT_MESH            // AT_MESH
 };
 
 // static
diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h
index e515b8a304b3396d4524c5f638e579181ec2f66b..af426b9007d098cf2ec5a16fa3400ce026e16378 100644
--- a/indra/llinventory/llinventorytype.h
+++ b/indra/llinventory/llinventorytype.h
@@ -67,7 +67,9 @@ class LLInventoryType
 		IT_WEARABLE = 18,
 		IT_ANIMATION = 19,
 		IT_GESTURE = 20,
-		IT_COUNT = 21,
+
+		IT_MESH = 22,
+		IT_COUNT = 23,
 
 		IT_NONE = -1
 	};
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 34348230b6a1ecdedb156b0d5e5f91512504d555..52a3fb21955b8ff7d142c37416d25847328fe9ff 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -46,6 +46,9 @@
 #include "lldarray.h"
 #include "llvolume.h"
 #include "llstl.h"
+#include "llsdserialize.h"
+#include "zlib/zlib.h"
+
 
 #define DEBUG_SILHOUETTE_BINORMALS 0
 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
@@ -1673,7 +1676,9 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
 	mFaceMask = 0x0;
 	mDetail = detail;
 	mSculptLevel = -2;
-	
+	mIsTetrahedron = FALSE;
+	mLODScaleBias.setVec(1,1,1);
+
 	// set defaults
 	if (mParams.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE)
 	{
@@ -1688,7 +1693,8 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
 	mGenerateSingleFace = generate_single_face;
 
 	generate();
-	if (mParams.getSculptID().isNull())
+	
+	if (mParams.getSculptID().isNull() && mParams.getSculptType() == LL_SCULPT_TYPE_NONE)
 	{
 		createVolumeFaces();
 	}
@@ -1839,6 +1845,482 @@ BOOL LLVolume::generate()
 	return FALSE;
 }
 
+bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const
+{
+	const U8* l = (const U8*) this;
+	const U8* r = (const U8*) &rhs;
+
+	for (U32 i = 0; i < sizeof(VertexData); ++i)
+	{
+		if (l[i] != r[i])
+		{
+			return r[i] < l[i];
+		}
+	}
+	
+	return false;
+}
+
+bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const
+{
+	const U8* l = (const U8*) this;
+	const U8* r = (const U8*) &rhs;
+
+	for (U32 i = 0; i < sizeof(VertexData); ++i)
+	{
+		if (l[i] != r[i])
+		{
+			return false;
+		}
+	}
+	
+	return true;
+}
+
+bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const
+{
+	bool retval = false;
+	if (rhs.mPosition == mPosition && rhs.mTexCoord == mTexCoord)
+	{
+		if (angle_cutoff > 1.f)
+		{
+			retval = (mNormal == rhs.mNormal);
+		}
+		else
+		{
+			F32 cur_angle = rhs.mNormal*mNormal;
+			retval = cur_angle > angle_cutoff;
+		}
+	}
+
+	return retval;
+}
+
+BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name)
+{
+	std::ifstream is;
+	
+	is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary);
+
+	BOOL success = createVolumeFacesFromStream(is);
+	
+	is.close();
+
+	return success;
+}
+
+BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
+{
+	mSculptLevel = -1;  // default is an error occured
+
+	LLSD header;
+	{
+		if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024))
+		{
+			llwarns << "Mesh header parse error.  Not a valid mesh asset!" << llendl;
+			return FALSE;
+		}
+	}
+	
+	std::string nm[] = 
+	{
+		"lowest_lod",
+		"low_lod",
+		"medium_lod",
+		"high_lod"
+	};
+
+	S32 lod = llclamp((S32) mDetail, 0, 3);
+
+	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;
+		}
+	}
+
+	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+
+	return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger());
+}
+
+bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
+{
+	U8* result = NULL;
+	U32 cur_size = 0;
+
+	{
+		//input stream is now pointing at a zlib compressed block of LLSD
+		//decompress block
+		z_stream strm;
+		
+		const U32 CHUNK = 65536;
+
+		U8 *in = new U8[size];
+		is.read((char*) in, size); 
+
+		U8 out[CHUNK];
+			
+		strm.zalloc = Z_NULL;
+		strm.zfree = Z_NULL;
+		strm.opaque = Z_NULL;
+		strm.avail_in = size;
+		strm.next_in = in;
+
+		S32 ret = inflateInit(&strm);
+
+		if (ret != Z_OK)
+		{
+			llerrs << "WTF?" << llendl;
+		}
+		
+		do
+		{
+			strm.avail_out = CHUNK;
+			strm.next_out = out;
+			ret = inflate(&strm, Z_NO_FLUSH);
+			if (ret == Z_STREAM_ERROR)
+			{
+				inflateEnd(&strm);
+				free(result);
+				delete [] in;
+				return false;
+			}
+			
+			switch (ret)
+			{
+			case Z_NEED_DICT:
+				ret = Z_DATA_ERROR;
+			case Z_DATA_ERROR:
+			case Z_MEM_ERROR:
+				inflateEnd(&strm);
+				free(result);
+				delete [] in;
+				return false;
+				break;
+			}
+
+			U32 have = CHUNK-strm.avail_out;
+
+			result = (U8*) realloc(result, cur_size + have);
+			memcpy(result+cur_size, out, have);
+			cur_size += have;
+
+		} while (strm.avail_out == 0);
+
+		inflateEnd(&strm);
+		delete [] in;
+
+		if (ret != Z_STREAM_END)
+		{
+			free(result);
+			return false;
+		}
+	}
+
+	//result now points to the decompressed LLSD block
+
+	LLSD mdl;
+
+	{
+		std::string res_str((char*) result, cur_size);
+		std::istringstream istr(res_str);
+
+		if (!LLSDSerialize::deserialize(mdl, istr, cur_size))
+		{
+			llwarns << "not a valid mesh asset!" << llendl;
+			return false;
+		}
+	}
+
+
+	free(result);
+
+
+	{
+		U32 face_count = mdl.size();
+
+		if (face_count == 0)
+		{
+			llerrs << "WTF?" << llendl;
+		}
+
+		mVolumeFaces.resize(face_count);
+
+		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];
+
+			face.mHasBinormals = false;
+
+			//copy out indices
+			face.mIndices.resize(idx.size()/2);
+			if (idx.empty() || face.mIndices.size() < 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)
+			{
+				face.mIndices[j] = indices[j];
+			}
+
+			//copy out vertices
+			U32 num_verts = pos.size()/(3*2);
+			face.mVertices.resize(num_verts);
+
+			LLVector3 min_pos;
+			LLVector3 max_pos;
+			LLVector2 min_tc; 
+			LLVector2 max_tc; 
+
+			min_pos.setValue(mdl[i]["PositionDomain"]["Min"]);
+			max_pos.setValue(mdl[i]["PositionDomain"]["Max"]);
+			min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
+			max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
+
+			LLVector3 pos_range = max_pos - min_pos;
+			LLVector2 tc_range = max_tc - min_tc;
+
+			LLVector3& min = face.mExtents[0];
+			LLVector3& max = face.mExtents[1];
+
+			min = max = LLVector3(0,0,0);
+
+			for (U32 j = 0; j < num_verts; ++j)
+			{
+				U16* v = (U16*) &(pos[j*3*2]);
+
+				face.mVertices[j].mPosition.setVec(
+					(F32) v[0] / 65535.f * pos_range.mV[0] + min_pos.mV[0],
+					(F32) v[1] / 65535.f * pos_range.mV[1] + min_pos.mV[1],
+					(F32) v[2] / 65535.f * pos_range.mV[2] + min_pos.mV[2]);
+
+				if (j == 0)
+				{
+					min = max = face.mVertices[j].mPosition;
+				}
+				else
+				{
+					update_min_max(min,max,face.mVertices[j].mPosition);
+				}
+
+				U16* n = (U16*) &(norm[j*3*2]);
+
+				face.mVertices[j].mNormal.setVec(
+					(F32) n[0] / 65535.f * 2.f - 1.f,
+					(F32) n[1] / 65535.f * 2.f - 1.f,
+					(F32) n[2] / 65535.f * 2.f - 1.f);
+
+				U16* t = (U16*) &(tc[j*2*2]);
+
+				face.mVertices[j].mTexCoord.setVec(
+					(F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0],
+					(F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1]);
+			}
+
+			
+			// 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)
+			{
+				for (S32 i = 0; i < face.mVertices.size(); i++)
+				{
+					face.mVertices[i].mPosition.mV[VX] *= -1.0f;
+					face.mVertices[i].mNormal.mV[VX] *= -1.0f;
+				}
+			}
+
+			if (do_invert_normals)
+			{
+				for (S32 i = 0; i < face.mVertices.size(); i++)
+				{
+					face.mVertices[i].mNormal *= -1.0f;
+				}
+			}
+
+			if (do_reverse_triangles)
+			{
+				for (U32 j = 0; j < face.mIndices.size(); j += 3)
+				{
+					// 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;
+				}
+			}
+
+		}
+	}
+
+	mSculptLevel = 0;  // success!
+	return true;
+}
+
+void tetrahedron_set_normal(LLVolumeFace::VertexData* cv)
+{
+	LLVector3 nrm = (cv[1].mPosition-cv[0].mPosition)%(cv[2].mPosition-cv[0].mPosition);
+
+	nrm.normVec();
+
+	cv[0].mNormal = nrm;
+	cv[1].mNormal = nrm;
+	cv[2].mNormal = nrm;
+}
+
+BOOL LLVolume::isTetrahedron()
+{
+	return mIsTetrahedron;
+}
+
+void LLVolume::makeTetrahedron()
+{
+	mVolumeFaces.clear();
+
+	LLVolumeFace face;
+
+	F32 x = 0.25f;
+	LLVector3 p[] = 
+	{ //unit tetrahedron corners
+		LLVector3(x,x,x),
+		LLVector3(-x,-x,x),
+		LLVector3(-x,x,-x),
+		LLVector3(x,-x,-x)
+	};
+
+	face.mExtents[0].setVec(-x,-x,-x);
+	face.mExtents[1].setVec(x,x,x);
+	
+	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].mPosition = p[1];
+	cv[1].mPosition = p[0];
+	cv[2].mPosition = p[2];
+
+	tetrahedron_set_normal(cv);
+
+	face.mVertices.push_back(cv[0]);
+	face.mVertices.push_back(cv[1]);
+	face.mVertices.push_back(cv[2]);
+	
+	//side 2
+	cv[0].mPosition = p[3];
+	cv[1].mPosition = p[0];
+	cv[2].mPosition = p[1];
+
+	tetrahedron_set_normal(cv);
+
+	face.mVertices.push_back(cv[0]);
+	face.mVertices.push_back(cv[1]);
+	face.mVertices.push_back(cv[2]);
+	
+	//side 3
+	cv[0].mPosition = p[3];
+	cv[1].mPosition = p[1];
+	cv[2].mPosition = p[2];
+
+	tetrahedron_set_normal(cv);
+
+	face.mVertices.push_back(cv[0]);
+	face.mVertices.push_back(cv[1]);
+	face.mVertices.push_back(cv[2]);
+	
+	//side 4
+	cv[0].mPosition = p[2];
+	cv[1].mPosition = p[0];
+	cv[2].mPosition = p[3];
+
+	tetrahedron_set_normal(cv);
+
+	face.mVertices.push_back(cv[0]);
+	face.mVertices.push_back(cv[1]);
+	face.mVertices.push_back(cv[2]);
+	
+	//set index buffer
+	for (U32 i = 0; i < 12; i++)
+	{
+		face.mIndices.push_back(i);
+	}
+	
+	mVolumeFaces.push_back(face);
+	mSculptLevel = 0;
+	mIsTetrahedron = TRUE;
+}
+
+void LLVolume::copyVolumeFaces(LLVolume* volume)
+{
+	mVolumeFaces = volume->mVolumeFaces;
+	mSculptLevel = 0;
+	mIsTetrahedron = FALSE;
+}
+
+
+S32	LLVolume::getNumFaces() const
+{
+	U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
+
+	if (sculpt_type == LL_SCULPT_TYPE_MESH)
+	{
+		return LL_SCULPT_MESH_MAX_FACES;
+	}
+
+	return (S32)mProfilep->mFaces.size();
+}
+
 
 void LLVolume::createVolumeFaces()
 {
@@ -1864,6 +2346,11 @@ void LLVolume::createVolumeFaces()
 			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;
@@ -1907,6 +2394,10 @@ void LLVolume::createVolumeFaces()
 					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
@@ -2198,6 +2689,11 @@ void LLVolume::sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components,
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
     U8 sculpt_type = mParams.getSculptType();
 
+	if (sculpt_type & LL_SCULPT_TYPE_MASK == LL_SCULPT_TYPE_MESH)
+	{
+		llerrs << "WTF?" << llendl;
+	}
+
 	BOOL data_is_empty = FALSE;
 
 	if (sculpt_width == 0 || sculpt_height == 0 || sculpt_components < 3 || sculpt_data == NULL)
@@ -2309,7 +2805,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams &params) const
 		return mSculptID < params.mSculptID;
 	}
 
-
 	return mSculptType < params.mSculptType;
 
 
@@ -3367,6 +3862,20 @@ S32 LLVolume::getNumTriangleIndices() const
 	return count;
 }
 
+
+S32 LLVolume::getNumTriangles() const
+{
+	U32 triangle_count = 0;
+
+	for (S32 i = 0; i < getNumVolumeFaces(); ++i)
+	{
+		triangle_count += getVolumeFace(i).mIndices.size()/3;
+	}
+
+	return triangle_count;
+}
+
+
 //-----------------------------------------------------------------------------
 // generateSilhouetteVertices()
 //-----------------------------------------------------------------------------
@@ -3379,22 +3888,29 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 										  S32 face_mask)
 {
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
-	
+
 	vertices.clear();
 	normals.clear();
 	segments.clear();
 
+	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)
 	{
-		const LLVolumeFace& face = *iter;
+		LLVolumeFace& face = *iter;
 	
-		if (!(face_mask & (0x1 << cur_index++)))
+		if (!(face_mask & (0x1 << cur_index++)) ||
+		     face.mIndices.empty() || face.mEdge.empty())
 		{
 			continue;
 		}
+
 		if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
 	
 		}
@@ -3594,6 +4110,8 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
 
 	F32 closest_t = 2.f; // must be larger than 1
 	
+	end_face = llmin(end_face, getNumVolumeFaces()-1);
+
 	for (S32 i = start_face; i <= end_face; i++)
 	{
 		const LLVolumeFace &face = getVolumeFace((U32)i);
@@ -4104,11 +4622,28 @@ BOOL LLVolumeParams::exportLegacyStream(std::ostream& output_stream) const
 	return TRUE;
 }
 
+LLSD LLVolumeParams::sculptAsLLSD() const
+{
+	LLSD sd = LLSD();
+	sd["id"] = getSculptID();
+	sd["type"] = getSculptType();
+
+	return sd;
+}
+
+bool LLVolumeParams::sculptFromLLSD(LLSD& sd)
+{
+	setSculptID(sd["id"].asUUID(), (U8)sd["type"].asInteger());
+	return true;
+}
+
 LLSD LLVolumeParams::asLLSD() const
 {
 	LLSD sd = LLSD();
 	sd["path"] = mPathParams;
 	sd["profile"] = mProfileParams;
+	sd["sculpt"] = sculptAsLLSD();
+	
 	return sd;
 }
 
@@ -4116,6 +4651,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd)
 {
 	mPathParams.fromLLSD(sd["path"]);
 	mProfileParams.fromLLSD(sd["profile"]);
+	sculptFromLLSD(sd["sculpt"]);
+		
 	return true;
 }
 
@@ -4158,6 +4695,12 @@ const F32 MIN_CONCAVE_PATH_WEDGE = 0.111111f;	// 1/9 unity
 // for collison purposes
 BOOL LLVolumeParams::isConvex() const
 {
+	if (!getSculptID().isNull())
+	{
+		// can't determine, be safe and say no:
+		return FALSE;
+	}
+	
 	F32 path_length = mPathParams.getEnd() - mPathParams.getBegin();
 	F32 hollow = mProfileParams.getHollow();
 	 
@@ -4416,6 +4959,61 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 	}
 }
 
+void LLVolumeFace::optimize(F32 angle_cutoff)
+{
+	LLVolumeFace new_face;
+
+	VertexMapData::PointMap point_map;
+
+	//remove redundant vertices
+	for (U32 i = 0; i < mIndices.size(); ++i)
+	{
+		U16 index = mIndices[i];
+
+		LLVolumeFace::VertexData cv = mVertices[index];
+
+		BOOL found = FALSE;
+		VertexMapData::PointMap::iterator point_iter = point_map.find(cv.mPosition);
+		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.mIndices.push_back((point_iter->second)[j].mIndex);
+					break;
+				}
+			}
+		}
+
+		if (!found)
+		{
+			new_face.mVertices.push_back(cv);
+			U16 index = (U16) new_face.mVertices.size()-1;
+			new_face.mIndices.push_back(index);
+
+			VertexMapData d;
+			d.mPosition = cv.mPosition;
+			d.mTexCoord = cv.mTexCoord;
+			d.mNormal = cv.mNormal;
+			d.mIndex = index;
+			if (point_iter != point_map.end())
+			{
+				point_iter->second.push_back(d);
+			}
+			else
+			{
+				point_map[d.mPosition].push_back(d);
+			}
+		}
+	}
+
+	mVertices = new_face.mVertices;
+	mIndices = new_face.mIndices;
+}
+
 void	LerpPlanarVertex(LLVolumeFace::VertexData& v0,
 				   LLVolumeFace::VertexData& v1,
 				   LLVolumeFace::VertexData& v2,
@@ -5074,6 +5672,42 @@ void LLVolumeFace::createBinormals()
 	}
 }
 
+void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat, LLMatrix4& norm_mat)
+{
+	U16 offset = mVertices.size();
+
+	if (face.mVertices.size() + mVertices.size() > 65536)
+	{
+		llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl;
+	}
+	
+	for (U32 i = 0; i < face.mVertices.size(); ++i)
+	{
+		VertexData v = face.mVertices[i];
+		v.mPosition = v.mPosition*mat;
+		v.mNormal = v.mNormal * norm_mat;
+
+		v.mNormal.normalize();
+
+		mVertices.push_back(v);
+
+		if (offset == 0 && i == 0)
+		{
+			mExtents[0] = mExtents[1] = v.mPosition;
+		}
+		else
+		{
+			update_min_max(mExtents[0], mExtents[1], v.mPosition);
+		}
+	}
+
+	
+	for (U32 i = 0; i < face.mIndices.size(); ++i)
+	{
+		mIndices.push_back(face.mIndices[i]+offset);
+	}
+}
+
 BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 {
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
@@ -5105,7 +5739,11 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 	if (!partial_build)
 	{
 		mIndices.resize(num_indices);
-		mEdge.resize(num_indices);
+
+		if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
+		{
+			mEdge.resize(num_indices);
+		}
 	}
 	else
 	{
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index d9f80f0e30e5d099294b0862aa187d94409e1446..60c1569e550f6a98c31085c9ba929623d7c57b79 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -183,12 +183,15 @@ 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;
+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
 {
@@ -575,6 +578,9 @@ class LLVolumeParams
 	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);
@@ -634,7 +640,6 @@ class LLVolumeParams
 	const F32&  getSkew() const			{ return mPathParams.getSkew();			}
 	const LLUUID& getSculptID() const	{ return mSculptID;						}
 	const U8& getSculptType() const     { return mSculptType;                   }
-
 	BOOL isConvex() const;
 
 	// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
@@ -800,6 +805,8 @@ class LLVolumeFace
 	void createBinormals();
 	void makeTriStrip();
 	
+	void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform);
+
 	class VertexData
 	{
 	public:
@@ -807,8 +814,45 @@ class LLVolumeFace
 		LLVector3 mNormal;
 		LLVector3 mBinormal;
 		LLVector2 mTexCoord;
+
+		bool operator<(const VertexData& rhs) const;
+		bool operator==(const VertexData& rhs) const;
+		bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const;
+	};
+
+	class VertexMapData : public LLVolumeFace::VertexData
+	{
+	public:
+		U16 mIndex;
+
+		bool operator==(const LLVolumeFace::VertexData& rhs) const
+		{
+			return mPosition == rhs.mPosition &&
+				mTexCoord == rhs.mTexCoord &&
+				mNormal == rhs.mNormal;
+		}
+
+		struct ComparePosition
+		{
+			bool operator()(const LLVector3& a, const LLVector3& b) const
+			{
+				if (a.mV[0] != b.mV[0])
+				{
+					return a.mV[0] < b.mV[0];
+				}
+				if (a.mV[1] != b.mV[1])
+				{
+					return a.mV[1] < b.mV[1];
+				}
+				return a.mV[2] < b.mV[2];
+			}
+		};
+
+		typedef std::map<LLVector3, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
 	};
 
+	void optimize(F32 angle_cutoff = 2.f);
+	
 	enum
 	{
 		SINGLE_MASK =	0x0001,
@@ -853,8 +897,7 @@ class LLVolume : public LLRefCount
 {
 	friend class LLVolumeLODGroup;
 
-private:
-	LLVolume(const LLVolume&);  // Don't implement
+protected:
 	~LLVolume(); // use unref
 
 public:
@@ -876,7 +919,7 @@ class LLVolume : public LLRefCount
 	
 	U8 getProfileType()	const								{ return mParams.getProfileParams().getCurveType(); }
 	U8 getPathType() const									{ return mParams.getPathParams().getCurveType(); }
-	S32	getNumFaces() const									{ return (S32)mProfilep->mFaces.size(); }
+	S32	getNumFaces() const;
 	S32 getNumVolumeFaces() const							{ return mVolumeFaces.size(); }
 	F32 getDetail() const									{ return mDetail; }
 	const LLVolumeParams& getParams() const					{ return mParams; }
@@ -898,12 +941,15 @@ class LLVolume : public LLRefCount
 	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, 
@@ -948,6 +994,8 @@ class LLVolume : public LLRefCount
 	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(LLVolume* volume);
+
 private:
 	void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type);
 	F32 sculptGetSurfaceArea();
@@ -958,11 +1006,19 @@ class LLVolume : public LLRefCount
 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;
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index 53641fceab1eec1076bb411787b9d8d47c5a0321..419e0015ba78faaf435806f5c4ba9c3f048b2e5b 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -320,7 +320,7 @@ BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
 		{
 			llassert_always(mLODRefs[i] > 0);
 			mLODRefs[i]--;
-#if 1 // SJB: Possible opt: keep other lods around
+#if 0 // SJB: Possible opt: keep other lods around
 			if (!mLODRefs[i])
 			{
 				mVolumeLODs[i] = NULL;
@@ -375,6 +375,19 @@ F32 LLVolumeLODGroup::getVolumeScaleFromDetail(const S32 detail)
 	return mDetailScales[detail];
 }
 
+S32 LLVolumeLODGroup::getVolumeDetailFromScale(const F32 detail)
+{
+	for (S32 i = 1; i < 4; i++)
+	{
+		if (mDetailScales[i] > detail)
+		{
+			return i-1;
+		}
+	}
+
+	return 3;
+}
+
 F32 LLVolumeLODGroup::dump()
 {
 	F32 usage = 0.f;
diff --git a/indra/llmath/llvolumemgr.h b/indra/llmath/llvolumemgr.h
index a78ea76a1a8d05c67191b2b47e67cbe57452c133..f5dc4cd748dce183608c8debbd66f8eccef60092 100644
--- a/indra/llmath/llvolumemgr.h
+++ b/indra/llmath/llvolumemgr.h
@@ -59,6 +59,7 @@ class LLVolumeLODGroup
 	static S32 getDetailFromTan(const F32 tan_angle);
 	static void getDetailProximity(const F32 tan_angle, F32 &to_lower, F32& to_higher);
 	static F32 getVolumeScaleFromDetail(const S32 detail);
+	static S32 getVolumeDetailFromScale(F32 scale);
 
 	LLVolume* refLOD(const S32 detail);
 	BOOL derefLOD(LLVolume *volumep);
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index d8e7b4aaf9c4f917bf6213c8c3b142a7e060cc59..ce5428f0e172d88483d0f2e5753b22a4ae17003a 100644
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -221,8 +221,33 @@ const LLMatrix4&	LLMatrix4::transpose()
 
 F32 LLMatrix4::determinant() const
 {
-	llerrs << "Not implemented!" << llendl;
-	return 0.f;
+	F32 value =
+	    mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][0] -
+	    mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][0] -
+	    mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][0] +
+	    mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][0] +
+	    mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][0] -
+	    mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][0] -
+	    mMatrix[0][3] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][1] +
+	    mMatrix[0][2] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][1] +
+	    mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][1] -
+	    mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][2] * mMatrix[3][1] -
+	    mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][1] +
+	    mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][3] * mMatrix[3][1] +
+	    mMatrix[0][3] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][2] -
+	    mMatrix[0][1] * mMatrix[1][3] * mMatrix[2][0] * mMatrix[3][2] -
+	    mMatrix[0][3] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][2] +
+	    mMatrix[0][0] * mMatrix[1][3] * mMatrix[2][1] * mMatrix[3][2] +
+	    mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][3] * mMatrix[3][2] -
+	    mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][3] * mMatrix[3][2] -
+	    mMatrix[0][2] * mMatrix[1][1] * mMatrix[2][0] * mMatrix[3][3] +
+	    mMatrix[0][1] * mMatrix[1][2] * mMatrix[2][0] * mMatrix[3][3] +
+	    mMatrix[0][2] * mMatrix[1][0] * mMatrix[2][1] * mMatrix[3][3] -
+	    mMatrix[0][0] * mMatrix[1][2] * mMatrix[2][1] * mMatrix[3][3] -
+	    mMatrix[0][1] * mMatrix[1][0] * mMatrix[2][2] * mMatrix[3][3] +
+		mMatrix[0][0] * mMatrix[1][1] * mMatrix[2][2] * mMatrix[3][3];
+
+	return value;
 }
 
 // Only works for pure orthonormal, homogeneous transform matrices.
@@ -428,6 +453,17 @@ const LLMatrix4&  	LLMatrix4::initRotTrans(const LLQuaternion &q, const LLVector
 	return (*this);
 }
 
+const LLMatrix4& LLMatrix4::initScale(const LLVector3 &scale)
+{
+	setIdentity();
+
+	mMatrix[VX][VX] = scale.mV[VX];
+	mMatrix[VY][VY] = scale.mV[VY];
+	mMatrix[VZ][VZ] = scale.mV[VZ];
+	
+	return (*this);
+}
+
 const LLMatrix4& LLMatrix4::initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos)
 {
 	F32		sx, sy, sz;
@@ -648,37 +684,6 @@ const LLMatrix4&  	LLMatrix4::initMatrix(const LLMatrix3 &mat, const LLVector4 &
 
 // LLMatrix4 Operators
 
-
-/* Not implemented to help enforce code consistency with the syntax of
-   row-major notation.  This is a Good Thing.
-LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b)
-{
-	// Operate "to the right" on column-vector b
-	LLVector4	vec;
-	vec.mV[VX] = a.mMatrix[VX][VX] * b.mV[VX] + 
-				 a.mMatrix[VY][VX] * b.mV[VY] + 
- 				 a.mMatrix[VZ][VX] * b.mV[VZ] +
-				 a.mMatrix[VW][VX] * b.mV[VW];
-
-	vec.mV[VY] = a.mMatrix[VX][VY] * b.mV[VX] + 
-				 a.mMatrix[VY][VY] * b.mV[VY] + 
-				 a.mMatrix[VZ][VY] * b.mV[VZ] +
-				 a.mMatrix[VW][VY] * b.mV[VW];
-
-	vec.mV[VZ] = a.mMatrix[VX][VZ] * b.mV[VX] + 
-			  	 a.mMatrix[VY][VZ] * b.mV[VY] + 
-				 a.mMatrix[VZ][VZ] * b.mV[VZ] +
-				 a.mMatrix[VW][VZ] * b.mV[VW];
-
-	vec.mV[VW] = a.mMatrix[VX][VW] * b.mV[VX] + 
-				 a.mMatrix[VY][VW] * b.mV[VY] + 
-				 a.mMatrix[VZ][VW] * b.mV[VZ] +
-				 a.mMatrix[VW][VW] * b.mV[VW];
-	return vec;
-}
-*/
-
-
 LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b)
 {
 	// Operate "to the left" on row-vector a
@@ -774,6 +779,23 @@ bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b)
 	return FALSE;
 }
 
+bool operator<(const LLMatrix4& a, const LLMatrix4 &b)
+{
+	U32		i, j;
+	for (i = 0; i < NUM_VALUES_IN_MAT4; i++)
+	{
+		for (j = 0; j < NUM_VALUES_IN_MAT4; j++)
+		{
+			if (a.mMatrix[i][j] != b.mMatrix[i][j])
+			{
+				return a.mMatrix[i][j] < b.mMatrix[i][j];
+			}
+		}
+	}
+
+	return false;
+}
+
 const LLMatrix4& operator*=(LLMatrix4 &a, F32 k)
 {
 	U32		i, j;
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index e74b7afe9bd9bf99befc4992c58b0440bf198123..40599a08865b29df8a9a9244c93d34d39d00ff53 100644
--- a/indra/llmath/m4math.h
+++ b/indra/llmath/m4math.h
@@ -159,6 +159,7 @@ class LLMatrix4
 	const LLMatrix4& initRotTrans(const F32 roll, const F32 pitch, const F32 yaw, const LLVector4 &pos); // Rotation from Euler + translation
 	const LLMatrix4& initRotTrans(const LLQuaternion &q, const LLVector4 &pos);	// Set with Quaternion and position
 
+	const LLMatrix4& initScale(const LLVector3 &scale);
 
 	// Set all
 	const LLMatrix4& initAll(const LLVector3 &scale, const LLQuaternion &q, const LLVector3 &pos);	
@@ -225,10 +226,7 @@ class LLMatrix4
 	// Operators
 	//
 
-// Not implemented to enforce code that agrees with symbolic syntax
-//		friend LLVector4 operator*(const LLMatrix4 &a, const LLVector4 &b);		// Apply rotation a to vector b
-
-//	friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b);		// Return a * b
+	//	friend inline LLMatrix4 operator*(const LLMatrix4 &a, const LLMatrix4 &b);		// Return a * b
 	friend LLVector4 operator*(const LLVector4 &a, const LLMatrix4 &b);		// Return transform of vector a by matrix b
 	friend const LLVector3 operator*(const LLVector3 &a, const LLMatrix4 &b);		// Return full transform of a by matrix b
 	friend LLVector4 rotate_vector(const LLVector4 &a, const LLMatrix4 &b);	// Rotates a but does not translate
@@ -236,6 +234,7 @@ class LLMatrix4
 
 	friend bool operator==(const LLMatrix4 &a, const LLMatrix4 &b);			// Return a == b
 	friend bool operator!=(const LLMatrix4 &a, const LLMatrix4 &b);			// Return a != b
+	friend bool operator<(const LLMatrix4 &a, const LLMatrix4& b);			// Return a < b
 
 	friend const LLMatrix4& operator+=(LLMatrix4 &a, const LLMatrix4 &b);	// Return a + b
 	friend const LLMatrix4& operator-=(LLMatrix4 &a, const LLMatrix4 &b);	// Return a - b
diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp
index 555e1f92bbb7a1a31e910c501ab0e5e64e233046..220336e0c2a5f82d8d5a3146db6fd6be381c1a4a 100644
--- a/indra/llmath/v2math.cpp
+++ b/indra/llmath/v2math.cpp
@@ -115,3 +115,18 @@ LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u)
 		a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
 		a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u );
 }
+
+LLSD LLVector2::getValue() const
+{
+	LLSD ret;
+	ret[0] = mV[0];
+	ret[1] = mV[1];
+	return ret;
+}
+
+void LLVector2::setValue(LLSD& sd)
+{
+	mV[0] = (F32) sd[0].asReal();
+	mV[1] = (F32) sd[1].asReal();
+}
+
diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h
index 9fef8851cc6bd3ab952d64c6422e0c939c65730d..f9f1c024f2a9ab162cd74a7d65d68344e15b1e55 100644
--- a/indra/llmath/v2math.h
+++ b/indra/llmath/v2math.h
@@ -66,6 +66,9 @@ class LLVector2
 		void	set(const LLVector2 &vec);	// Sets LLVector2 to vec
 		void	set(const F32 *vec);			// Sets LLVector2 to vec
 
+		LLSD	getValue() const;
+		void	setValue(LLSD& sd);
+
 		void	setVec(F32 x, F32 y);	        // deprecated
 		void	setVec(const LLVector2 &vec);	// deprecated
 		void	setVec(const F32 *vec);			// deprecated
diff --git a/indra/llmath/v3math.cpp b/indra/llmath/v3math.cpp
index 63683ed49622ba053059e3e5ae6971784337cc40..82aad6550b025ac8cc195df2c1325cd09928d957 100644
--- a/indra/llmath/v3math.cpp
+++ b/indra/llmath/v3math.cpp
@@ -197,6 +197,28 @@ const LLVector3&	LLVector3::rotVec(const LLQuaternion &q)
 	return *this;
 }
 
+const LLVector3& LLVector3::transVec(const LLMatrix4& mat)
+{
+	setVec(
+			mV[VX] * mat.mMatrix[VX][VX] + 
+			mV[VY] * mat.mMatrix[VX][VY] + 
+			mV[VZ] * mat.mMatrix[VX][VZ] +
+			mat.mMatrix[VX][VW],
+			 
+			mV[VX] * mat.mMatrix[VY][VX] + 
+			mV[VY] * mat.mMatrix[VY][VY] + 
+			mV[VZ] * mat.mMatrix[VY][VZ] +
+			mat.mMatrix[VY][VW],
+
+			mV[VX] * mat.mMatrix[VZ][VX] + 
+			mV[VY] * mat.mMatrix[VZ][VY] + 
+			mV[VZ] * mat.mMatrix[VZ][VZ] +
+			mat.mMatrix[VZ][VW]);
+
+	return *this;
+}
+
+
 const LLVector3&	LLVector3::rotVec(F32 angle, const LLVector3 &vec)
 {
 	if ( !vec.isExactlyZero() && angle )
diff --git a/indra/llmath/v3math.h b/indra/llmath/v3math.h
index 73738cffd25cdf3a4b053fad6ade6657179326e9..76dd938887c60219fbcaf215ce35134f32fe59d5 100644
--- a/indra/llmath/v3math.h
+++ b/indra/llmath/v3math.h
@@ -36,10 +36,12 @@
 #include "llerror.h"
 #include "llmath.h"
 
+
 #include "llsd.h"
 class LLVector2;
 class LLVector4;
 class LLMatrix3;
+class LLMatrix4;
 class LLVector3d;
 class LLQuaternion;
 
@@ -115,6 +117,7 @@ class LLVector3
 		const LLVector3&	rotVec(F32 angle, F32 x, F32 y, F32 z);		// Rotates about x,y,z by angle radians
 		const LLVector3&	rotVec(const LLMatrix3 &mat);				// Rotates by LLMatrix4 mat
 		const LLVector3&	rotVec(const LLQuaternion &q);				// Rotates by LLQuaternion q
+		const LLVector3&	transVec(const LLMatrix4& mat);				// Transforms by LLMatrix4 mat (mat * v)
 
 		const LLVector3&	scaleVec(const LLVector3& vec);				// scales per component by vec
 		LLVector3			scaledVec(const LLVector3& vec) const;			// get a copy of this vector scaled by vec
diff --git a/indra/llmath/v4color.h b/indra/llmath/v4color.h
index d6fbdec61e16234bfb9536ea3de0c780a2635b39..6b63b976b02d71ef05b72a84763b67baf2fe2aee 100644
--- a/indra/llmath/v4color.h
+++ b/indra/llmath/v4color.h
@@ -114,6 +114,7 @@ class LLColor4
 	
 	    const LLColor4& operator=(const LLColor3 &a);	// Assigns vec3 to vec4 and returns vec4
 		
+		bool operator<(const LLColor4& rhs) const;
 		friend std::ostream&	 operator<<(std::ostream& s, const LLColor4 &a);		// Print a
 		friend LLColor4 operator+(const LLColor4 &a, const LLColor4 &b);	// Return vector a + b
 		friend LLColor4 operator-(const LLColor4 &a, const LLColor4 &b);	// Return vector a minus b
@@ -595,6 +596,23 @@ inline LLColor4 lerp(const LLColor4 &a, const LLColor4 &b, F32 u)
 		a.mV[VW] + (b.mV[VW] - a.mV[VW]) * u);
 }
 
+inline bool LLColor4::operator<(const LLColor4& rhs) const
+{
+	if (mV[0] != rhs.mV[0])
+	{
+		return mV[0] < rhs.mV[0];
+	}
+	if (mV[1] != rhs.mV[1])
+	{
+		return mV[1] < rhs.mV[1];
+	}
+	if (mV[2] != rhs.mV[2])
+	{
+		return mV[2] < rhs.mV[2];
+	}
+
+	return mV[3] < rhs.mV[3];
+}
 
 void LLColor4::clamp()
 {
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index 02523467e839be212ed8760b7dd4add619aaf968..e7527b1e7812a2f0e899320741296d5106c55a93 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -509,7 +509,7 @@ void LLAssetStorage::_queueDataRequest(const LLUUID& uuid, LLAssetType::EType at
 			tpvf.setAsset(uuid, atype);
 			tpvf.setCallback(downloadCompleteCallback, req);
 
-			llinfos << "Starting transfer for " << uuid << llendl;
+			//llinfos << "Starting transfer for " << uuid << llendl;
 			LLTransferTargetChannel *ttcp = gTransferManager.getTargetChannel(mUpstreamHost, LLTCT_ASSET);
 			ttcp->requestTransfer(spa, tpvf, 100.f + (is_priority ? 1.f : 0.f));
 		}
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index 024e17a7779a487ef8e9022e3ec5cda7104a4327..f8a7eb04170fad82edde94c5f893a7a3cfcae5e1 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -55,6 +55,7 @@
 #include "llstl.h"
 #include "llsdserialize.h"
 #include "llthread.h"
+#include "lltimer.h"
 
 //////////////////////////////////////////////////////////////////////////////
 /*
@@ -256,7 +257,12 @@ class LLCurl::Easy
 	
 	void resetState();
 
+	static CURL* allocEasyHandle();
+	static void releaseEasyHandle(CURL* handle);
+
 private:	
+	friend class LLCurl;
+
 	CURL*				mCurlEasyHandle;
 	struct curl_slist*	mHeaders;
 	
@@ -271,8 +277,62 @@ class LLCurl::Easy
 	std::vector<char*>	mStrings;
 	
 	ResponderPtr		mResponder;
+
+	static std::set<CURL*> sFreeHandles;
+	static std::set<CURL*> sActiveHandles;
+	static LLMutex* sHandleMutex;
 };
 
+std::set<CURL*> LLCurl::Easy::sFreeHandles;
+std::set<CURL*> LLCurl::Easy::sActiveHandles;
+LLMutex* LLCurl::Easy::sHandleMutex = NULL;
+
+
+//static
+CURL* LLCurl::Easy::allocEasyHandle()
+{
+	CURL* ret = NULL;
+	LLMutexLock lock(sHandleMutex);
+	if (sFreeHandles.empty())
+	{
+		ret = curl_easy_init();
+	}
+	else
+	{
+		ret = *(sFreeHandles.begin());
+		sFreeHandles.erase(ret);
+		curl_easy_reset(ret);
+	}
+
+	if (ret)
+	{
+		sActiveHandles.insert(ret);
+	}
+
+	return ret;
+}
+
+//static
+void LLCurl::Easy::releaseEasyHandle(CURL* handle)
+{
+	if (!handle)
+	{
+		llerrs << "handle cannot be NULL!" << llendl;
+	}
+
+	LLMutexLock lock(sHandleMutex);
+	
+	if (sActiveHandles.find(handle) != sActiveHandles.end())
+	{
+		sActiveHandles.erase(handle);
+		sFreeHandles.insert(handle);
+	}
+	else
+	{
+		llerrs << "Invalid handle." << llendl;
+	}
+}
+
 LLCurl::Easy::Easy()
 	: mHeaders(NULL),
 	  mCurlEasyHandle(NULL)
@@ -283,25 +343,27 @@ LLCurl::Easy::Easy()
 LLCurl::Easy* LLCurl::Easy::getEasy()
 {
 	Easy* easy = new Easy();
-	easy->mCurlEasyHandle = curl_easy_init();
+	easy->mCurlEasyHandle = allocEasyHandle(); 
+	
 	if (!easy->mCurlEasyHandle)
 	{
 		// this can happen if we have too many open files (fails in c-ares/ares_init.c)
-		llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
+		llwarns << "allocEasyHandle() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
 		delete easy;
 		return NULL;
 	}
 	
-	// set no DMS caching as default for all easy handles. This prevents them adopting a
+	// set no DNS caching as default for all easy handles. This prevents them adopting a
 	// multi handles cache if they are added to one.
 	curl_easy_setopt(easy->mCurlEasyHandle, CURLOPT_DNS_CACHE_TIMEOUT, 0);
+
 	++gCurlEasyCount;
 	return easy;
 }
 
 LLCurl::Easy::~Easy()
 {
-	curl_easy_cleanup(mCurlEasyHandle);
+	releaseEasyHandle(mCurlEasyHandle);
 	--gCurlEasyCount;
 	curl_slist_free_all(mHeaders);
 	for_each(mStrings.begin(), mStrings.end(), DeletePointerArray());
@@ -379,6 +441,7 @@ U32 LLCurl::Easy::report(CURLcode code)
 	{
 		responseCode = 499;
 		responseReason = strerror(code) + " : " + mErrorBuffer;
+		setopt(CURLOPT_FRESH_CONNECT, TRUE);
 	}
 		
 	if (mResponder)
@@ -465,7 +528,7 @@ void LLCurl::Easy::prepRequest(const std::string& url,
 	
 	if (post) setoptString(CURLOPT_ENCODING, "");
 
-//	setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
+	//setopt(CURLOPT_VERBOSE, 1); // usefull for debugging
 	setopt(CURLOPT_NOSIGNAL, 1);
 
 	mOutput.reset(new LLBufferArray);
@@ -482,7 +545,10 @@ void LLCurl::Easy::prepRequest(const std::string& url,
 	setCA();
 
 	setopt(CURLOPT_SSL_VERIFYPEER, LLCurl::getSSLVerify());
-	setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify()? 2 : 0);
+	//setopt(CURLOPT_SSL_VERIFYHOST, LLCurl::getSSLVerify()? 2 : 0);
+	
+	//don't verify host name so urls with scrubbed host names will work (improves DNS performance)
+	setopt(CURLOPT_SSL_VERIFYHOST, 0);
 	setopt(CURLOPT_TIMEOUT, CURL_REQUEST_TIMEOUT);
 
 	setoptString(CURLOPT_URL, url);
@@ -543,6 +609,7 @@ LLCurl::Multi::Multi()
 	  mErrorCount(0)
 {
 	mCurlMultiHandle = curl_multi_init();
+	
 	if (!mCurlMultiHandle)
 	{
 		llwarns << "curl_multi_init() returned NULL! Easy handles: " << gCurlEasyCount << " Multi handles: " << gCurlMultiCount << llendl;
@@ -710,6 +777,7 @@ LLCurlRequest::LLCurlRequest() :
 	mActiveRequestCount(0)
 {
 	mThreadID = LLThread::currentID();
+	mProcessing = FALSE;
 }
 
 LLCurlRequest::~LLCurlRequest()
@@ -744,6 +812,11 @@ LLCurl::Easy* LLCurlRequest::allocEasy()
 bool LLCurlRequest::addEasy(LLCurl::Easy* easy)
 {
 	llassert_always(mActiveMulti);
+	
+	if (mProcessing)
+	{
+		llerrs << "Posting to a LLCurlRequest instance from within a responder is not allowed (causes DNS timeouts)." << llendl;
+	}
 	bool res = mActiveMulti->addEasy(easy);
 	return res;
 }
@@ -801,12 +874,41 @@ bool LLCurlRequest::post(const std::string& url,
 	bool res = addEasy(easy);
 	return res;
 }
+
+bool LLCurlRequest::post(const std::string& url,
+						 const headers_t& headers,
+						 const std::string& data,
+						 LLCurl::ResponderPtr responder)
+{
+	LLCurl::Easy* easy = allocEasy();
+	if (!easy)
+	{
+		return false;
+	}
+	easy->prepRequest(url, headers, responder);
+
+	easy->getInput().write(data.data(), data.size());
+	S32 bytes = easy->getInput().str().length();
 	
+	easy->setopt(CURLOPT_POST, 1);
+	easy->setopt(CURLOPT_POSTFIELDS, (void*)NULL);
+	easy->setopt(CURLOPT_POSTFIELDSIZE, bytes);
+
+	easy->slist_append("Content-Type: application/octet-stream");
+	easy->setHeaders();
+
+	lldebugs << "POSTING: " << bytes << " bytes." << llendl;
+	bool res = addEasy(easy);
+	return res;
+}
+
 // Note: call once per frame
 S32 LLCurlRequest::process()
 {
 	llassert_always(mThreadID == LLThread::currentID());
 	S32 res = 0;
+
+	mProcessing = TRUE;
 	for (curlmulti_set_t::iterator iter = mMultiSet.begin();
 		 iter != mMultiSet.end(); )
 	{
@@ -820,6 +922,7 @@ S32 LLCurlRequest::process()
 			delete multi;
 		}
 	}
+	mProcessing = FALSE;
 	return res;
 }
 
@@ -1042,6 +1145,8 @@ void LLCurl::initClass()
 	// - http://curl.haxx.se/libcurl/c/curl_global_init.html
 	curl_global_init(CURL_GLOBAL_ALL);
 	
+	Easy::sHandleMutex = new LLMutex(NULL);
+
 #if SAFE_SSL
 	S32 mutex_count = CRYPTO_num_locks();
 	for (S32 i=0; i<mutex_count; i++)
@@ -1059,5 +1164,22 @@ void LLCurl::cleanupClass()
 	CRYPTO_set_locking_callback(NULL);
 	for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
 #endif
+
+	delete Easy::sHandleMutex;
+	Easy::sHandleMutex = NULL;
+
+	for (std::set<CURL*>::iterator iter = Easy::sFreeHandles.begin(); iter != Easy::sFreeHandles.end(); ++iter)
+	{
+		CURL* curl = *iter;
+		curl_easy_cleanup(curl);
+	}
+
+	Easy::sFreeHandles.clear();
+
+	if (!Easy::sActiveHandles.empty())
+	{
+		llerrs << "CURL easy handles not cleaned up on shutdown!" << llendl;
+	}
+
 	curl_global_cleanup();
 }
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index caf02cccd90bc6c70ab4f755485b6b355bb2986d..6ec0a5d8a7915cc20629ec4d7c6a5d20d00af52b 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -213,6 +213,8 @@ class LLCurlRequest
 	void get(const std::string& url, LLCurl::ResponderPtr responder);
 	bool getByteRange(const std::string& url, const headers_t& headers, S32 offset, S32 length, LLCurl::ResponderPtr responder);
 	bool post(const std::string& url, const headers_t& headers, const LLSD& data, LLCurl::ResponderPtr responder);
+	bool post(const std::string& url, const headers_t& headers, const std::string& data, LLCurl::ResponderPtr responder);
+	
 	S32  process();
 	S32  getQueued();
 
@@ -226,6 +228,7 @@ class LLCurlRequest
 	curlmulti_set_t mMultiSet;
 	LLCurl::Multi* mActiveMulti;
 	S32 mActiveRequestCount;
+	BOOL mProcessing;
 	U32 mThreadID; // debug
 };
 
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index dd56e18caf8fbe26e60b61d0167cdcc3d20ee12b..46952fa43459663bc5862d2f364ef66424611ba8 100644
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -194,6 +194,7 @@ namespace
 			fileBuffer = new U8 [fileSize];
             vfile.read(fileBuffer, fileSize);
             ostream.write((char*)fileBuffer, fileSize);
+			delete [] fileBuffer;
 			eos = true;
 			return STATUS_DONE;
 		}
diff --git a/indra/llmessage/llpumpio.cpp b/indra/llmessage/llpumpio.cpp
index 5e9dfd81faa48e30175eeace6ed6e66af36d7ca1..e3ce2c5ad34192e6b1a1bb8ee47fa42737fc7a61 100644
--- a/indra/llmessage/llpumpio.cpp
+++ b/indra/llmessage/llpumpio.cpp
@@ -444,13 +444,13 @@ void LLPumpIO::pump()
 	pump(DEFAULT_POLL_TIMEOUT);
 }
 
-static LLFastTimer::DeclareTimer FTM_PUMP("Pump");
+static LLFastTimer::DeclareTimer FTM_PUMP_IO("Pump IO");
 
 //timeout is in microseconds
 void LLPumpIO::pump(const S32& poll_timeout)
 {
 	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
-	LLFastTimer t1(FTM_PUMP);
+	LLFastTimer t1(FTM_PUMP_IO);
 	//llinfos << "LLPumpIO::pump()" << llendl;
 
 	// Run any pending runners.
@@ -778,6 +778,8 @@ bool LLPumpIO::respond(
 	return true;
 }
 
+static LLFastTimer::DeclareTimer FTM_PUMP_CALLBACK_CHAIN("Chain");
+
 void LLPumpIO::callback()
 {
 	LLMemType m1(LLMemType::MTYPE_IO_PUMP);
@@ -799,6 +801,7 @@ void LLPumpIO::callback()
 		callbacks_t::iterator end = mCallbacks.end();
 		for(; it != end; ++it)
 		{
+			LLFastTimer t(FTM_PUMP_CALLBACK_CHAIN);
 			// it's always the first and last time for respone chains
 			(*it).mHead = (*it).mChainLinks.begin();
 			(*it).mInit = true;
diff --git a/indra/llmessage/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp
index d64b666edece69f5138fec90b8a01bbcf2b8de24..de9c609500f77237ad4059fb15ee9d168b8d8746 100644
--- a/indra/llmessage/lltransfermanager.cpp
+++ b/indra/llmessage/lltransfermanager.cpp
@@ -344,7 +344,7 @@ void LLTransferManager::processTransferInfo(LLMessageSystem *msgp, void **)
 		}
 	}
 
-	llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl;
+	//llinfos << "Receiving " << transfer_id << ", size " << size << " bytes" << llendl;
 	ttp->setSize(size);
 	ttp->setGotInfo(TRUE);
 
diff --git a/indra/llmessage/lltransfersourceasset.cpp b/indra/llmessage/lltransfersourceasset.cpp
index 43f7c07e9480e4dcaf6bd82fd1a52d1db6e77087..8c0520687a834cedb9351afad7df9db10981b5bf 100644
--- a/indra/llmessage/lltransfersourceasset.cpp
+++ b/indra/llmessage/lltransfersourceasset.cpp
@@ -257,3 +257,4 @@ BOOL LLTransferSourceParamsAsset::unpackParams(LLDataPacker &dp)
 
 	return TRUE;
 }
+
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index 68a3d54597fcbd529516f7e6f2534f1ff5244f33..af78ed79360cad1e527b2a11795af9909289fe9d 100644
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -13,11 +13,14 @@ include_directories(
     ${LLMATH_INCLUDE_DIRS}
     ${LLMESSAGE_INCLUDE_DIRS}
     ${LLXML_INCLUDE_DIRS}
+    ${LIBS_PREBUILT_DIR}/include/collada
+    ${LIBS_PREBUILT_DIR}/include/collada/1.4
     )
 
 set(llprimitive_SOURCE_FILES
     llmaterialtable.cpp
     llmediaentry.cpp
+    llmodel.cpp
     llprimitive.cpp
     llprimtexturelist.cpp
     lltextureanim.cpp
@@ -34,6 +37,7 @@ set(llprimitive_HEADER_FILES
     legacy_object_types.h
     llmaterialtable.h
     llmediaentry.h
+    llmodel.h
     llprimitive.h
     llprimtexturelist.h
     lltextureanim.h
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index b75d1b0f678e024a087022b93d54262d0946885d..732f5a698b0d9b3f0992fd6dbb4ab4494441a87d 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -744,7 +744,11 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai
 		setNumTEs(mVolumep->getNumFaces());
 		return TRUE;
 	}
-
+	
+#if 0 
+	// #if 0'd out by davep
+	// this is a lot of cruft to set texture entry values that just stay the same for LOD switch 
+	// or immediately get overridden by an object update message, also crashes occasionally
 	U32 old_face_mask = mVolumep->mFaceMask;
 
 	S32 face_bit = 0;
@@ -942,6 +946,13 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai
 			setTE(te_num, *(old_tes.getTexture(face_mapping[face_bit])));
 		}
 	}
+#else
+	// build the new object
+	sVolumeManager->unrefVolume(mVolumep);
+	mVolumep = volumep; 
+
+	setNumTEs(mVolumep->getNumFaces());
+#endif
 	return TRUE;
 }
 
@@ -1084,7 +1095,7 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
 	U8 packed_buffer[MAX_TE_BUFFER];
 	U8 *cur_ptr = packed_buffer;
 	
-	S32 last_face_index = getNumTEs() - 1;
+	S32 last_face_index = llmin((U32) getNumTEs(), MAX_TES) - 1;
 	
 	if (last_face_index > -1)
 	{
@@ -1365,7 +1376,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
 		return retval;
 	}
 
-	face_count = getNumTEs();
+	face_count = llmin((U32) getNumTEs(), MAX_TES);
 	U32 i;
 
 	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)image_data, 16, face_count, MVT_LLUUID);
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 4f828186cbbd37c0572d28afa3084b6e9713fc41..a44b9a6c1f859daa8cf7d9d102bcfb980e2361e8 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -286,6 +286,7 @@ class LLLightImageParams : public LLNetworkData
 
 	void setLightTexture(const LLUUID& id) { mLightTexture = id; }
 	LLUUID getLightTexture() const         { return mLightTexture; }
+	bool isLightSpotlight() const         { return mLightTexture.notNull(); }
 	void setParams(const LLVector3& params) { mParams = params; }
 	LLVector3 getParams() const			   { return mParams; }
 	
@@ -328,7 +329,7 @@ class LLPrimitive : public LLXform
 	const LLVolume *getVolumeConst() const { return mVolumep; }		// HACK for Windoze confusion about ostream operator in LLVolume
 	LLVolume *getVolume() const { return mVolumep; }
 	virtual BOOL setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false);
-
+	
 	// Modify texture entry properties
 	inline BOOL validTE(const U8 te_num) const;
 	LLTextureEntry* getTE(const U8 te_num) const;
diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp
index d9e1976341a23840deca771fd8aada9ffbd8f886..82db922368d6e442426f91370a9232f74fc7ed7d 100644
--- a/indra/llrender/llfontgl.cpp
+++ b/indra/llrender/llfontgl.cpp
@@ -247,7 +247,6 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons
 		}
 	}
 
-
 	const LLFontGlyphInfo* next_glyph = NULL;
 
 	for (i = begin_offset; i < begin_offset + length; i++)
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index a3f7a946ecdcd6a0a49af9cb5de315fa92389e09..97019d48c486000e1823beb97f1193a9f11ae699 100644
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -185,6 +185,9 @@ PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT =
 // GL_EXT_framebuffer_blit
 PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT = NULL;
 
+// GL_EXT_blend_func_separate
+PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT = NULL;
+
 // GL_ARB_draw_buffers
 PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL;
 
@@ -324,6 +327,7 @@ LLGLManager::LLGLManager() :
 	mHasCompressedTextures(FALSE),
 	mHasFramebufferObject(FALSE),
 	mHasFramebufferMultisample(FALSE),
+	mHasBlendFuncSeparate(FALSE),
 
 	mHasVertexBufferObject(FALSE),
 	mHasPBuffer(FALSE),
@@ -632,6 +636,11 @@ void LLGLManager::initExtensions()
 	mHasDrawBuffers = TRUE;
 #else
 	mHasDrawBuffers = FALSE;
+# endif
+# if GL_EXT_blend_func_separate
+	mHasBlendFuncSeparate = TRUE;
+#else
+	mHasBlendFuncSeparate = FALSE;
 # endif
 	mHasMipMapGeneration = FALSE;
 	mHasSeparateSpecularColor = FALSE;
@@ -659,6 +668,7 @@ void LLGLManager::initExtensions()
 		&& ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
 	mHasFramebufferMultisample = mHasFramebufferObject && ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts);
 	mHasDrawBuffers = ExtensionExists("GL_ARB_draw_buffers", gGLHExts.mSysExts);
+	mHasBlendFuncSeparate = ExtensionExists("GL_EXT_blend_func_separate", gGLHExts.mSysExts);
 	mHasTextureRectangle = ExtensionExists("GL_ARB_texture_rectangle", gGLHExts.mSysExts);
 #if !LL_DARWIN
 	mHasPointParameters = !mIsATI && ExtensionExists("GL_ARB_point_parameters", gGLHExts.mSysExts);
@@ -682,6 +692,7 @@ void LLGLManager::initExtensions()
 		mHasFramebufferObject = FALSE;
 		mHasFramebufferMultisample = FALSE;
 		mHasDrawBuffers = FALSE;
+		mHasBlendFuncSeparate = FALSE;
 		mHasMipMapGeneration = FALSE;
 		mHasSeparateSpecularColor = FALSE;
 		mHasAnisotropic = FALSE;
@@ -706,6 +717,7 @@ void LLGLManager::initExtensions()
 		mHasShaderObjects = FALSE;
 		mHasVertexShader = FALSE;
 		mHasFragmentShader = FALSE;
+		mHasBlendFuncSeparate = FALSE;
 		LL_WARNS("RenderInit") << "GL extension support forced to SIMPLE level via LL_GL_BASICEXT" << LL_ENDL;
 	}
 	if (getenv("LL_GL_BLACKLIST"))	/* Flawfinder: ignore */
@@ -734,7 +746,8 @@ void LLGLManager::initExtensions()
 		if (strchr(blacklist,'r')) mHasDrawBuffers = FALSE;//S
 		if (strchr(blacklist,'s')) mHasFramebufferMultisample = FALSE;
 		if (strchr(blacklist,'t')) mHasTextureRectangle = FALSE;
-
+		if (strchr(blacklist,'u')) mHasBlendFuncSeparate = FALSE;//S
+		
 	}
 #endif // LL_LINUX || LL_SOLARIS
 	
@@ -782,6 +795,14 @@ void LLGLManager::initExtensions()
 	{
 		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_fragment_shader" << LL_ENDL;
 	}
+	if (!mHasBlendFuncSeparate)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_EXT_blend_func_separate" << LL_ENDL;
+	}
+	if (!mHasDrawBuffers)
+	{
+		LL_INFOS("RenderInit") << "Couldn't initialize GL_ARB_draw_buffers" << LL_ENDL;
+	}
 
 	// Disable certain things due to known bugs
 	if (mIsIntel && mHasMipMapGeneration)
@@ -852,6 +873,10 @@ void LLGLManager::initExtensions()
 	{
 		glDrawBuffersARB = (PFNGLDRAWBUFFERSARBPROC) GLH_EXT_GET_PROC_ADDRESS("glDrawBuffersARB");
 	}
+	if (mHasBlendFuncSeparate)
+	{
+		glBlendFuncSeparateEXT = (PFNGLBLENDFUNCSEPARATEEXTPROC) GLH_EXT_GET_PROC_ADDRESS("glBlendFuncSeparateEXT");
+	}
 #if (!LL_LINUX && !LL_SOLARIS) || LL_LINUX_NV_GL_HEADERS
 	// This is expected to be a static symbol on Linux GL implementations, except if we use the nvidia headers - bah
 	glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)GLH_EXT_GET_PROC_ADDRESS("glDrawRangeElements");
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index 91421f3c954fa91fada6cc768633d72c63232cff..0c2da7dd089d3548bda8e23649957158771719fe 100644
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -87,6 +87,7 @@ class LLGLManager
 	BOOL mHasCompressedTextures;
 	BOOL mHasFramebufferObject;
 	BOOL mHasFramebufferMultisample;
+	BOOL mHasBlendFuncSeparate;
 	
 	// ARB Extensions
 	BOOL mHasVertexBufferObject;
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index f33ae7d8f024965d48d8125f1db3a389234a8615..f6d35bc76696b1e33cc98cde581b186a5eeb02f7 100644
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -216,6 +216,9 @@ extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
 
 extern PFNGLCOLORTABLEEXTPROC glColorTableEXT;
 
+//GL_EXT_blend_func_separate
+extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
+
 //GL_EXT_framebuffer_object
 extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
 extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
@@ -249,7 +252,10 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
 # include "GL/glh_extensions.h"
 # undef __APPLE__
 
-#elif LL_LINUX 
+#elif LL_LINUX
+//----------------------------------------------------------------------------
+// LL_LINUX
+
 //----------------------------------------------------------------------------
 // Linux, MESA headers, but not necessarily assuming MESA runtime.
 // quotes so we get libraries/.../GL/ version
@@ -285,6 +291,7 @@ extern PFNGLGENERATEMIPMAPEXTPROC glGenerateMipmapEXT;
 # define LL_LINUX_NV_GL_HEADERS 0
 #endif // LL_LINUX && defined(WINGDIAPI)
 
+
 #if LL_LINUX_NV_GL_HEADERS
 // Missing functions when using nvidia headers:
 extern PFNGLACTIVETEXTUREARBPROC	glActiveTextureARB;
@@ -445,6 +452,9 @@ extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
 extern PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB;
 extern PFNGLGETCOMPRESSEDTEXIMAGEARBPROC glGetCompressedTexImageARB;
 
+//GL_EXT_blend_func_separate
+extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
+
 //GL_EXT_framebuffer_object
 extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
 extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
@@ -473,7 +483,10 @@ extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
 //GL_ARB_draw_buffers
 extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
 
+
 #elif LL_WINDOWS
+//----------------------------------------------------------------------------
+// LL_WINDOWS
 
 // windows gl headers depend on things like APIENTRY, so include windows.
 #define WIN32_LEAN_AND_MEAN
@@ -641,6 +654,9 @@ extern PFNGLBINDATTRIBLOCATIONARBPROC glBindAttribLocationARB;
 extern PFNGLGETACTIVEATTRIBARBPROC glGetActiveAttribARB;
 extern PFNGLGETATTRIBLOCATIONARBPROC glGetAttribLocationARB;
 
+//GL_EXT_blend_func_separate
+extern PFNGLBLENDFUNCSEPARATEEXTPROC glBlendFuncSeparateEXT;
+
 //GL_EXT_framebuffer_object
 extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
 extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
@@ -669,6 +685,7 @@ extern PFNGLBLITFRAMEBUFFEREXTPROC glBlitFramebufferEXT;
 //GL_ARB_draw_buffers
 extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
 
+
 #elif LL_DARWIN
 //----------------------------------------------------------------------------
 // LL_DARWIN
@@ -685,6 +702,9 @@ extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
 // Note that they also must not be called on 10.3.9.  This should be taken care of by a runtime check for the existence of the GL extension.
 #include <AvailabilityMacros.h>
 
+//GL_EXT_blend_func_separate
+extern void glBlendFuncSeparateEXT(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
+
 // GL_EXT_framebuffer_object
 extern GLboolean glIsRenderbufferEXT(GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
 extern void glBindRenderbufferEXT(GLenum target, GLuint renderbuffer) AVAILABLE_MAC_OS_X_VERSION_10_4_AND_LATER;
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 3d8bd21609775672373e7238174a1504dec9e546..2ab6e327b7e4533bdbb1893d0e54d7893767063b 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1639,7 +1639,7 @@ void LLImageGL::calcAlphaChannelOffsetAndStride()
 	}
 }
 
-void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
+void LLImageGL::analyzeAlpha(const void* data_in, U32 w, U32 h)
 {
 	if(!mNeedsAlphaAndPickMask)
 	{
@@ -1647,24 +1647,64 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
 	}
 
 	U32 length = w * h;
-	const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset ;
 	
-	S32 sample[16];
-	memset(sample, 0, sizeof(S32)*16);
-
-	for (U32 i = 0; i < length; i++)
+	U32 sample[16];
+	memset(sample, 0, sizeof(U32)*16);
+
+	// generate histogram of quantized alpha.
+	// also add-in the histogram of a 2x2 box-sampled version.  The idea is
+	// this will mid-skew the data (and thus increase the chances of not
+	// being used as a mask) from high-frequency alpha maps which
+	// suffer the worst from aliasing when used as alpha masks.
+	if (w >= 2 && h >= 2)
+	{
+		llassert(w%2 == 0);
+		llassert(h%2 == 0);
+		const GLubyte* rowstart = ((const GLubyte*) data_in) + mAlphaOffset;
+		for (U32 y = 0; y < h; y+=2)
+		{
+			const GLubyte* current = rowstart;
+			for (U32 x = 0; x < w; x+=2)
+			{
+				U32 s1 = current[0];
+				U32 s2 = current[w * mAlphaStride];
+				current += mAlphaStride;
+				U32 s3 = current[0];
+				U32 s4 = current[w * mAlphaStride];
+				current += mAlphaStride;
+
+				++sample[s1/16];
+				++sample[s2/16];
+				++sample[s3/16];
+				++sample[s4/16];
+
+				sample[(s1+s2+s3+s4)/(16 * 4)] += 4;
+			}
+			
+			rowstart += 2 * w * mAlphaStride;
+		}
+		length += length;
+	}
+	else
 	{
-		++sample[*current/16];
-		current += mAlphaStride ;
+		const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset;
+		for (U32 i = 0; i < length; i++)
+		{
+			++sample[*current/16];
+			current += mAlphaStride;
+		}
 	}
+	
+	// if more than 1/16th of alpha samples are mid-range, this
+	// shouldn't be treated as a 1-bit mask
 
-	U32 total = 0;
+	U32 midrangetotal = 0;
 	for (U32 i = 4; i < 11; i++)
 	{
-		total += sample[i];
+		midrangetotal += sample[i];
 	}
 
-	if (total > length/16)
+	if (midrangetotal > length/16)
 	{
 		mIsMask = FALSE;
 	}
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index f0870c3fc45b2416c9ac98f8b35613a6b867fb04..1b303307f63624465423c9bc09d4949b73d17aef 100644
--- a/indra/llrender/llimagegl.h
+++ b/indra/llrender/llimagegl.h
@@ -91,7 +91,7 @@ class LLImageGL : public LLRefCount
 protected:
 	virtual ~LLImageGL();
 
-	void analyzeAlpha(const void* data_in, S32 w, S32 h);
+	void analyzeAlpha(const void* data_in, U32 w, U32 h);
 	void calcAlphaChannelOffsetAndStride();
 
 public:
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index c3540a717cbfb0bd34b7d05bac13db5f368e309c..43662fbb5c3c0b5494f7ae67554c05b2dafe0b6d 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -778,8 +778,11 @@ LLRender::LLRender()
 
 	mCurrAlphaFunc = CF_DEFAULT;
 	mCurrAlphaFuncVal = 0.01f;
-	mCurrBlendSFactor = BF_UNDEF;
-	mCurrBlendDFactor = BF_UNDEF;
+
+	mCurrBlendColorSFactor = BF_UNDEF;
+	mCurrBlendAlphaSFactor = BF_UNDEF;
+	mCurrBlendColorDFactor = BF_UNDEF;
+	mCurrBlendAlphaDFactor = BF_UNDEF;
 }
 
 LLRender::~LLRender()
@@ -995,15 +998,44 @@ void LLRender::blendFunc(eBlendFactor sfactor, eBlendFactor dfactor)
 {
 	llassert(sfactor < BF_UNDEF);
 	llassert(dfactor < BF_UNDEF);
-	if (mCurrBlendSFactor != sfactor || mCurrBlendDFactor != dfactor)
+	if (mCurrBlendColorSFactor != sfactor || mCurrBlendColorDFactor != dfactor ||
+	    mCurrBlendAlphaSFactor != sfactor || mCurrBlendAlphaDFactor != dfactor)
 	{
-		mCurrBlendSFactor = sfactor;
-		mCurrBlendDFactor = dfactor;
+		mCurrBlendColorSFactor = sfactor;
+		mCurrBlendAlphaSFactor = sfactor;
+		mCurrBlendColorDFactor = dfactor;
+		mCurrBlendAlphaDFactor = dfactor;
 		flush();
 		glBlendFunc(sGLBlendFactor[sfactor], sGLBlendFactor[dfactor]);
 	}
 }
 
+void LLRender::blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor,
+			 eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor)
+{
+	llassert(color_sfactor < BF_UNDEF);
+	llassert(color_dfactor < BF_UNDEF);
+	llassert(alpha_sfactor < BF_UNDEF);
+	llassert(alpha_dfactor < BF_UNDEF);
+	if (!gGLManager.mHasBlendFuncSeparate)
+	{
+		LL_WARNS_ONCE("render") << "no glBlendFuncSeparateEXT(), using color-only blend func" << llendl;
+		blendFunc(color_sfactor, color_dfactor);
+		return;
+	}
+	if (mCurrBlendColorSFactor != color_sfactor || mCurrBlendColorDFactor != color_dfactor ||
+	    mCurrBlendAlphaSFactor != alpha_sfactor || mCurrBlendAlphaDFactor != alpha_dfactor)
+	{
+		mCurrBlendColorSFactor = color_sfactor;
+		mCurrBlendAlphaSFactor = alpha_sfactor;
+		mCurrBlendColorDFactor = color_dfactor;
+		mCurrBlendAlphaDFactor = alpha_dfactor;
+		flush();
+		glBlendFuncSeparateEXT(sGLBlendFactor[color_sfactor], sGLBlendFactor[color_dfactor],
+				       sGLBlendFactor[alpha_sfactor], sGLBlendFactor[alpha_dfactor]);
+	}
+}
+
 LLTexUnit* LLRender::getTexUnit(U32 index)
 {
 	if (index < mTexUnits.size())
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index a90fbd4a5c43969db1ee0a24c2a46d40f6f2e9b2..3cda4b5770039d00fdbacdd64d1a6590d7e75598 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -323,7 +323,11 @@ class LLRender
 
 	void setAlphaRejectSettings(eCompareFunc func, F32 value = 0.01f);
 
+	// applies blend func to both color and alpha
 	void blendFunc(eBlendFactor sfactor, eBlendFactor dfactor);
+	// applies separate blend functions to color and alpha
+	void blendFunc(eBlendFactor color_sfactor, eBlendFactor color_dfactor,
+		       eBlendFactor alpha_sfactor, eBlendFactor alpha_dfactor);
 
 	LLTexUnit* getTexUnit(U32 index);
 
@@ -362,9 +366,10 @@ class LLRender
 	std::vector<LLTexUnit*>		mTexUnits;
 	LLTexUnit*			mDummyTexUnit;
 
-	eBlendFactor mCurrBlendSFactor;
-	eBlendFactor mCurrBlendDFactor;
-
+	eBlendFactor mCurrBlendColorSFactor;
+	eBlendFactor mCurrBlendColorDFactor;
+	eBlendFactor mCurrBlendAlphaSFactor;
+	eBlendFactor mCurrBlendAlphaDFactor;
 	F32				mMaxAnisotropy;
 
 	std::list<LLVector3> mUIOffset;
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index d9520b3bf63c1f226bb65244bb50904b4a51ee2f..3f2558f1f5e2d1af1d9816dd1e06fb1ade95433a 100644
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -390,8 +390,6 @@ void LLRenderTarget::flush(BOOL fetch_depth)
 	}
 	else
 	{
-#if !LL_DARWIN
-
 		stop_glerror();
 
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
@@ -435,7 +433,6 @@ void LLRenderTarget::flush(BOOL fetch_depth)
 				}
 			}
 		}
-#endif
 
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
 	}
@@ -444,7 +441,6 @@ void LLRenderTarget::flush(BOOL fetch_depth)
 void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
 						S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
 {
-#if !LL_DARWIN
 	gGL.flush();
 	if (!source.mFBO || !mFBO)
 	{
@@ -483,14 +479,12 @@ void LLRenderTarget::copyContents(LLRenderTarget& source, S32 srcX0, S32 srcY0,
 			stop_glerror();
 		}
 	}
-#endif
 }
 
 //static
 void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0, S32 srcY0, S32 srcX1, S32 srcY1,
 						S32 dstX0, S32 dstY0, S32 dstX1, S32 dstY1, U32 mask, U32 filter)
 {
-#if !LL_DARWIN
 	if (!source.mFBO)
 	{
 		llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
@@ -507,7 +501,6 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
 		stop_glerror();
 	}
-#endif
 }
 
 BOOL LLRenderTarget::isComplete() const
@@ -652,7 +645,6 @@ void LLMultisampleBuffer::allocate(U32 resx, U32 resy, U32 color_fmt, BOOL depth
 
 void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
 {
-#if !LL_DARWIN
 	if (color_fmt == 0)
 	{
 		return;
@@ -693,12 +685,10 @@ void LLMultisampleBuffer::addColorAttachment(U32 color_fmt)
 	}
 
 	mTex.push_back(tex);
-#endif
 }
 
 void LLMultisampleBuffer::allocateDepth()
 {
-#if !LL_DARWIN
 	glGenRenderbuffersEXT(1, (GLuint* ) &mDepth);
 	glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, mDepth);
 	if (mStencil)
@@ -709,6 +699,5 @@ void LLMultisampleBuffer::allocateDepth()
 	{
 		glRenderbufferStorageMultisampleEXT(GL_RENDERBUFFER_EXT, mSamples, GL_DEPTH_COMPONENT16_ARB, mResX, mResY);	
 	}
-#endif
 }
 
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index bf5eda21ebd6c9adc487520b742d499040470d38..4064e688e833631609b60024d1e53ae450ef8d9a 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -61,6 +61,7 @@ BOOL LLVertexBuffer::sVBOActive = FALSE;
 BOOL LLVertexBuffer::sIBOActive = FALSE;
 U32 LLVertexBuffer::sAllocatedBytes = 0;
 BOOL LLVertexBuffer::sMapped = FALSE;
+BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
 
 std::vector<U32> LLVertexBuffer::sDeleteList;
 
@@ -381,6 +382,11 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 	{
 		mUsage = 0 ; 
 	}
+
+	if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
+	{
+		mUsage = 0;
+	}
 	
 	S32 stride = calcStride(typemask, mOffsets);
 
@@ -579,7 +585,7 @@ void LLVertexBuffer::destroyGLBuffer()
 	}
 	
 	mGLBuffer = 0;
-	unbind();
+	//unbind();
 }
 
 void LLVertexBuffer::destroyGLIndices()
@@ -606,7 +612,7 @@ void LLVertexBuffer::destroyGLIndices()
 	}
 
 	mGLIndices = 0;
-	unbind();
+	//unbind();
 }
 
 void LLVertexBuffer::updateNumVerts(S32 nverts)
@@ -668,6 +674,12 @@ void LLVertexBuffer::allocateBuffer(S32 nverts, S32 nindices, bool create)
 {
 	LLMemType mt2(LLMemType::MTYPE_VERTEX_ALLOCATE_BUFFER);
 		
+	if (nverts < 0 || nindices < 0 ||
+		nverts > 65536)
+	{
+		llerrs << "Bad vertex buffer allocation: " << nverts << " : " << nindices << llendl;
+	}
+
 	updateNumVerts(nverts);
 	updateNumIndices(nindices);
 	
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index b785a22976993b42923f0b970badb75bc00c89d4..e2fecdffef9065569505507b33668840aadc9bd9 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -83,6 +83,8 @@ class LLVertexBuffer : public LLRefCount
 	static LLVBOPool sDynamicVBOPool;
 	static LLVBOPool sStreamIBOPool;
 	static LLVBOPool sDynamicIBOPool;
+	
+	static BOOL	sUseStreamDraw;
 
 	static void initClass(bool use_vbo);
 	static void cleanupClass();
diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp
index 5fdf41188d46faf90bff83d9b85f5e486e81ec4c..6751f3eb93966f2708ea11454ba5aada368c5cdc 100644
--- a/indra/llvfs/llvfile.cpp
+++ b/indra/llvfs/llvfile.cpp
@@ -320,7 +320,7 @@ BOOL LLVFile::setMaxSize(S32 size)
 
 	if (!mVFS->checkAvailable(size))
 	{
-		LLFastTimer t(FTM_VFILE_WAIT);
+		//LLFastTimer t(FTM_VFILE_WAIT);
 		S32 count = 0;
 		while (sVFSThread->getPending() > 1000)
 		{
@@ -428,7 +428,7 @@ bool LLVFile::isLocked(EVFSLock lock)
 
 void LLVFile::waitForLock(EVFSLock lock)
 {
-	LLFastTimer t(FTM_VFILE_WAIT);
+	//LLFastTimer t(FTM_VFILE_WAIT);
 	// spin until the lock clears
 	while (isLocked(lock))
 	{
diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp
index 9ce1e75d06f501ade52c7f9a5645afa63c7d0873..ddb76fb2ba159175009420ff17c9a80cb15479a5 100644
--- a/indra/llvfs/llvfs.cpp
+++ b/indra/llvfs/llvfs.cpp
@@ -2041,6 +2041,9 @@ std::string get_extension(LLAssetType::EType type)
 	case LLAssetType::AT_ANIMATION:
 		extension = ".lla";
 		break;
+	case LLAssetType::AT_MESH:
+		extension = ".slm";
+		break;
 	default:
 		// Just use the asset server filename extension in most cases
 		extension += ".";
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 47fde08a9de671c2a511d154b2f26f6def00808a..b80190a1d25a70b8a31e69a3ee1bba4c259e3238 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -38,11 +38,13 @@ include(UnixInstall)
 include(LLKDU)
 include(ViewerMiscLibs)
 include(LLLogin)
+include(GLOD)
 include(CMakeCopyIfDifferent)
 
 include_directories(
     ${DBUSGLIB_INCLUDE_DIRS}
     ${ELFIO_INCLUDE_DIR}
+    ${GLOD_INCLUDE_DIR}
     ${LLAUDIO_INCLUDE_DIRS}
     ${LLCHARACTER_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
@@ -61,6 +63,8 @@ include_directories(
     ${LSCRIPT_INCLUDE_DIRS}
     ${LSCRIPT_INCLUDE_DIRS}/lscript_compile
     ${LLLOGIN_INCLUDE_DIRS}
+    ${LIBS_PREBUILT_DIR}/include/collada
+    ${LIBS_PREBUILT_DIR}/include/collada/1.4
     )
 
 set(viewer_SOURCE_FILES
@@ -174,6 +178,7 @@ set(viewer_SOURCE_FILES
     llfloaterhelpbrowser.cpp
     llfloaterhud.cpp
     llfloaterimagepreview.cpp
+    llfloaterimportcollada.cpp
     llfloaterinspect.cpp
     llfloaterinventory.cpp
     llfloaterjoystick.cpp
@@ -184,6 +189,7 @@ set(viewer_SOURCE_FILES
     llfloatermediabrowser.cpp
     llfloatermediasettings.cpp
     llfloatermemleak.cpp
+    llfloatermodelpreview.cpp
     llfloaternamedesc.cpp
     llfloaternotificationsconsole.cpp
     llfloateropenobject.cpp
@@ -276,6 +282,8 @@ set(viewer_SOURCE_FILES
     llmediadataclient.cpp
     llmemoryview.cpp
     llmenucommands.cpp
+    llmeshrepository.cpp
+    llmeshreduction.cpp
     llmetricperformancetester.cpp
     llmimetypes.cpp
     llmorphview.cpp
@@ -678,6 +686,7 @@ set(viewer_HEADER_FILES
     llfloaterhelpbrowser.h
     llfloaterhud.h
     llfloaterimagepreview.h
+    llfloaterimportcollada.h
     llfloaterinspect.h
     llfloaterinventory.h
     llfloaterjoystick.h
@@ -688,6 +697,7 @@ set(viewer_HEADER_FILES
     llfloatermediabrowser.h
     llfloatermediasettings.h
     llfloatermemleak.h
+    llfloatermodelpreview.h
     llfloaternamedesc.h
     llfloaternotificationsconsole.h
     llfloateropenobject.h
@@ -780,6 +790,8 @@ set(viewer_HEADER_FILES
     llmediadataclient.h
     llmemoryview.h
     llmenucommands.h
+    llmeshrepository.h
+    llmeshreduction.h
     llmetricperformancetester.h
     llmimetypes.h
     llmorphview.h
@@ -1191,6 +1203,7 @@ if (WINDOWS)
         ${DINPUT_LIBRARY}
         ${DXGUID_LIBRARY}
         kernel32
+        libboost_system
         odbc32
         odbccp32
         ole32
@@ -1614,6 +1627,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${DBUSGLIB_LIBRARIES}
     ${OPENGL_LIBRARIES}
     ${FMODWRAPPER_LIBRARY} # must come after LLAudio
+    ${GLOD_LIBRARIES}
     ${OPENGL_LIBRARIES}
     ${SDL_LIBRARY}
     ${SMARTHEAP_LIBRARY}
diff --git a/indra/newview/app_settings/high_graphics.xml b/indra/newview/app_settings/high_graphics.xml
index 6368f7099e71eff6067b435e3b81b6254878a87d..93d39c841444f0775bbd1682c683382c30febeea 100644
--- a/indra/newview/app_settings/high_graphics.xml
+++ b/indra/newview/app_settings/high_graphics.xml
@@ -12,8 +12,6 @@
 	<RenderFlexTimeFactor value="1"/>
 	<!--256... but they don't use this-->
 	<RenderGlowResolutionPow value="9"/>
-	<!--Sun/Moon only-->
-	<RenderLightingDetail value="1"/>
 	<!--Low number-->
 	<RenderMaxPartCount value="4096"/>
 	<!--bump okay-->
@@ -31,9 +29,14 @@
 	<!--Default for now-->
 	<RenderVolumeLODFactor value="1.125"/>
 	<!--NO SHADERS-->
-	<RenderWaterReflections value="FALSE"/>
-	<!--NO SHADERS-->
 	<VertexShaderEnable value="TRUE"/>
 	<!--NO SHADERS-->
 	<WindLightUseAtmosShaders value="TRUE"/>
+  <!--Deferred Shading-->
+  <RenderDeferred value="TRUE"/>
+  <!--SSAO Disabled-->
+  <RenderDeferredSSAO value="FALSE"/>
+  <!--Sun Shadows-->
+  <RenderShadowDetail value="1"/>
+
 </settings>
diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml
index 3f67a70d7ac179943d599d234ac87e6ef93fe2f6..a300c8646c4dfdfc93d59d4a7a8bf6dcc8f40802 100644
--- a/indra/newview/app_settings/low_graphics.xml
+++ b/indra/newview/app_settings/low_graphics.xml
@@ -12,8 +12,6 @@
 	<RenderFlexTimeFactor value="0.5"/>
 	<!--256... but they don't use this-->
 	<RenderGlowResolutionPow value="8"/>
-	<!--Sun/Moon only-->
-	<RenderLightingDetail value="0"/>
 	<!--Low number-->
 	<RenderMaxPartCount value="1024"/>
 	<!--bump okay-->
@@ -31,9 +29,14 @@
 	<!--Default for now-->
 	<RenderVolumeLODFactor value="1.125"/>
 	<!--NO SHADERS-->
-	<RenderWaterReflections value="FALSE"/>
-	<!--NO SHADERS-->
 	<VertexShaderEnable value="FALSE"/>
 	<!--NO SHADERS-->
 	<WindLightUseAtmosShaders value="FALSE"/>
+  <!--No Deferred Shading-->
+  <RenderDeferred value="FALSE"/>
+  <!--SSAO Disabled-->
+  <RenderDeferredSSAO value="FALSE"/>
+  <!--No Shadows-->
+  <RenderShadowDetail value="0"/>
+
 </settings>
diff --git a/indra/newview/app_settings/mid_graphics.xml b/indra/newview/app_settings/mid_graphics.xml
index 12da77da400d837673fda1a9f21ad218e01b0132..a1430a58f985d22bc551880f25f5d0c6d2ed006d 100644
--- a/indra/newview/app_settings/mid_graphics.xml
+++ b/indra/newview/app_settings/mid_graphics.xml
@@ -12,8 +12,6 @@
 	<RenderFlexTimeFactor value="1"/>
 	<!--256... but they don't use this-->
 	<RenderGlowResolutionPow value="8"/>
-	<!--Sun/Moon only-->
-	<RenderLightingDetail value="1"/>
 	<!--Low number-->
 	<RenderMaxPartCount value="2048"/>
 	<!--bump okay-->
@@ -31,9 +29,14 @@
 	<!--Default for now-->
 	<RenderVolumeLODFactor value="1.125"/>
 	<!--NO SHADERS-->
-	<RenderWaterReflections value="FALSE"/>
-	<!--NO SHADERS-->
 	<VertexShaderEnable value="TRUE"/>
 	<!--NO SHADERS-->
 	<WindLightUseAtmosShaders value="FALSE"/>
+  <!--No Deferred Shading-->
+  <RenderDeferred value="FALSE"/>
+  <!--SSAO Disabled-->
+  <RenderDeferredSSAO value="FALSE"/>
+  <!--No Shadows-->
+  <RenderShadowDetail value="0"/>
+
 </settings>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 92226f4148862b2694fe567aedd27482da91180d..14acf3eadaa04428287625942b34ce920de33dee 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1709,7 +1709,7 @@
     <key>DebugShowRenderInfo</key>
     <map>
       <key>Comment</key>
-      <string>Show depth buffer contents</string>
+      <string>Show stats about current scene</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -1717,6 +1717,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+  <key>DebugShowUploadCost</key>
+  <map>
+    <key>Comment</key>
+    <string>Show what it would cost to upload assets in current scene</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
   <key>DebugShowRenderMatrices</key>
   <map>
     <key>Comment</key>
@@ -5969,7 +5980,19 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-  
+
+      <key>RenderLightingDetail</key>
+    <map>
+      <key>Comment</key>
+      <string>Amount of detail for lighting objects/avatars/terrain (0=sun/moon only, 1=enable local lights)</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
+
   <key>RenderShadowNearDist</key>
   <map>
     <key>Comment</key>
@@ -6083,7 +6106,7 @@
     <key>Type</key>
     <string>U32</string>
     <key>Value</key>
-    <integer>60</integer>
+    <integer>200</integer>
   </map>
   <key>RenderSSAOFactor</key>
   <map>
@@ -6607,19 +6630,7 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
-
-  <key>RenderDeferredShadow</key>
-  <map>
-    <key>Comment</key>
-    <string>Enable shadows in deferred renderer.</string>
-    <key>Persist</key>
-    <integer>1</integer>
-    <key>Type</key>
-    <string>Boolean</string>
-    <key>Value</key>
-    <integer>1</integer>
-  </map>
-
+  
   <key>RenderDeferredGI</key>
   <map>
     <key>Comment</key>
@@ -6632,10 +6643,10 @@
     <integer>0</integer>
   </map>
 
-  <key>RenderDeferredSunShadow</key>
+  <key>RenderDeferredSun</key>
   <map>
     <key>Comment</key>
-    <string>Generate shadows from the sun.</string>
+    <string>Execute sunlight shader in deferred renderer.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
@@ -6644,10 +6655,10 @@
     <integer>1</integer>
   </map>
 
-  <key>RenderDeferredSun</key>
+  <key>RenderDeferredAtmospheric</key>
   <map>
     <key>Comment</key>
-    <string>Execute sunlight shader in deferred renderer.</string>
+    <string>Execute atmospheric shader in deferred renderer.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
@@ -6656,10 +6667,10 @@
     <integer>1</integer>
   </map>
 
-  <key>RenderDeferredAtmospheric</key>
+  <key>RenderDeferredSSAO</key>
   <map>
     <key>Comment</key>
-    <string>Execute atmospheric shader in deferred renderer.</string>
+    <string>Execute screen space ambient occlusion shader in deferred renderer.</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
@@ -6921,7 +6932,7 @@
     <key>RenderFastAlpha</key>
     <map>
       <key>Comment</key>
-      <string>Use lossy alpha rendering optimization (opaque/nonexistent small alpha faces).</string>
+      <string>Use alpha masks where appropriate.</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -7190,17 +7201,6 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>RenderLightingDetail</key>
-    <map>
-      <key>Comment</key>
-      <string>Amount of detail for lighting objects/avatars/terrain (0=sun/moon only, 1=enable local lights)</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>S32</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
     <key>RenderMaxPartCount</key>
     <map>
       <key>Comment</key>
@@ -7300,7 +7300,19 @@
       <key>Value</key>
       <integer>2</integer>
     </map>
-    <key>RenderReflectionRes</key>
+    <key>RenderShadowDetail</key>
+    <map>
+      <key>Comment</key>
+      <string>Detail of shadows.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>2</integer>
+    </map>
+
+  <key>RenderReflectionRes</key>
     <map>
       <key>Comment</key>
       <string>Reflection map resolution.</string>
@@ -7463,9 +7475,20 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>0</integer>
+      <integer>1</integer>
     </map>
   <key>RenderUseTriStrips</key>
+  <map>
+    <key>Comment</key>
+    <string>Use triangle strips for rendering prims.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+  <key>RenderUseTriStrips</key>
   <map>
     <key>Comment</key>
     <string>Use triangle strips for rendering prims.</string>
@@ -7531,6 +7554,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+  <key>RenderUseStreamVBO</key>
+  <map>
+    <key>Comment</key>
+    <string>Use VBO's for stream buffers</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>1</integer>
+  </map>
     <key>RenderVolumeLODFactor</key>
     <map>
       <key>Comment</key>
@@ -7575,17 +7609,6 @@
       <key>Value</key>
       <integer>512</integer>
     </map>
-    <key>RenderWaterReflections</key>
-    <map>
-      <key>Comment</key>
-      <string>Reflect the environment in the water.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
     <key>RotateRight</key>
     <map>
       <key>Comment</key>
@@ -7619,7 +7642,30 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>SafeMode</key>
+  <key>MeshThreadCount</key>
+  <map>
+    <key>Comment</key>
+    <string>Number of threads to use for loading meshes.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <integer>8</integer>
+  </map>
+  <key>MeshMaxConcurrentRequests</key>
+  <map>
+    <key>Comment</key>
+    <string>Number of threads to use for loading meshes.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <integer>32</integer>
+  </map>
+
+  <key>SafeMode</key>
     <map>
       <key>Comment</key>
       <string>Reset preferences, run in safe mode.</string>
@@ -10180,7 +10226,7 @@
       <key>Type</key>
       <string>Boolean</string>
       <key>Value</key>
-      <integer>1</integer>
+      <integer>0</integer>
     </map>
     <key>SpeakerParticipantRemoveDelay</key>
     <map>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index 4fb109d687012081898b7e3aacdc8cdfef4590c4..fea2e1609082a1d2256bade99fe1ab95e42ff15c 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -24,8 +24,6 @@ varying vec3 vary_fragcoord;
 varying vec3 vary_position;
 varying vec3 vary_light;
 
-uniform float alpha_soften;
-
 uniform mat4 inv_proj;
 
 vec4 getPosition(vec2 pos_screen)
@@ -57,15 +55,6 @@ void main()
 
 	color.rgb = scaleSoftClip(color.rgb);
 
-	if (samp_pos.z != 0.0 && gl_Color.a < 1.0)
-	{
-		float dist_factor = alpha_soften;
-		float a = gl_Color.a;
-		a *= a;
-		dist_factor *= 1.0/(1.0-a);
-		color.a *= min((pos.z-samp_pos.z)*dist_factor, 1.0);
-	}
-	
 	//gl_FragColor = gl_Color;
 	gl_FragColor = color;
 	//gl_FragColor = vec4(1,0,1,1);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index 1a7d58b07badf728127947f7a185e8dab07635ca..04e556c11ad51880c832e6933a91b9dbd597ab2f 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -9,7 +9,7 @@ vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
 void calcAtmospherics(vec3 inPositionEye);
 
 float calcDirectionalLight(vec3 n, vec3 l);
-float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
 
 vec3 atmosAmbient(vec3 light);
 vec3 atmosAffectDirectionalLight(float lightIntensity);
@@ -41,23 +41,22 @@ void main()
 	calcAtmospherics(pos.xyz);
 
 	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
-	vec4 col;
-	col.a = gl_Color.a;
-	
-	// Add windlight lights
-	col.rgb = atmosAmbient(vec3(0.));
-	col.rgb = scaleUpLight(col.rgb);
+
+	vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
 
 	// Collect normal lights (need to be divided by two, as we later multiply by 2)
-	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
-	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
-	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
-	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
- 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
- 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a);
+	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a);
+	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a);
 	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
 	col.rgb = scaleDownLight(col.rgb);
 	
+	// Add windlight lights
+	col.rgb += atmosAmbient(vec3(0.));
+	
 	vary_light = gl_LightSource[0].position.xyz;
 	
 	vary_ambient = col.rgb*gl_Color.rgb;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
index c1988d3c783e4f9ddff80957ec8abfe5bf4b8a6a..650fbcc3f5c59f08d21ea090f91a4204338723f1 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
@@ -10,7 +10,7 @@ mat4 getSkinnedTransform();
 void calcAtmospherics(vec3 inPositionEye);
 
 float calcDirectionalLight(vec3 n, vec3 l);
-float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
 
 vec3 atmosAmbient(vec3 light);
 vec3 atmosAffectDirectionalLight(float lightIntensity);
@@ -47,23 +47,22 @@ void main()
 	calcAtmospherics(pos.xyz);
 
 	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
-	vec4 col;
-	col.a = gl_Color.a;
-	
-	// Add windlight lights
-	col.rgb = atmosAmbient(vec3(0.));
-	col.rgb = scaleUpLight(col.rgb);
+
+	vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
 
 	// Collect normal lights (need to be divided by two, as we later multiply by 2)
-	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
-	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
-	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
-	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
- 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
- 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a);
+	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a);
+	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a);
 	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
 	col.rgb = scaleDownLight(col.rgb);
 	
+	// Add windlight lights
+	col.rgb += atmosAmbient(vec3(0.));
+	
 	vary_ambient = col.rgb*gl_Color.rgb;
 	vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
 	
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
index bd5e9dd75803c6b8ded976bd0d1f11cc41694ed4..0fad5b4b50be87187b9e320cd1aee3aa28e61db2 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
@@ -10,13 +10,11 @@
 uniform sampler2DRect depthMap;
 uniform sampler2DRect normalMap;
 uniform sampler2DRect lightMap;
-uniform sampler2DRect giLightMap;
 
 uniform float dist_factor;
 uniform float blur_size;
 uniform vec2 delta;
-uniform vec3 kern[32];
-uniform int kern_length;
+uniform vec3 kern[4];
 uniform float kern_scale;
 
 varying vec2 vary_fragcoord;
@@ -50,7 +48,7 @@ void main()
 	vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free'
 	vec4 col = defined_weight.xyxx * ccol;
 	
-	for (int i = 1; i < kern_length; i++)
+	for (int i = 1; i < 4; i++)
 	{
 		vec2 tc = vary_fragcoord.xy + kern[i].z*dlt;
 	        vec3 samppos = getPosition(tc).xyz; 
@@ -61,12 +59,22 @@ void main()
 			defined_weight += kern[i].xy;
 		}
 	}
+	for (int i = 1; i < 4; i++)
+	{
+		vec2 tc = vary_fragcoord.xy - kern[i].z*dlt;
+	        vec3 samppos = getPosition(tc).xyz; 
+		float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
+		if (d*d <= 0.003)
+		{
+			col += texture2DRect(lightMap, tc)*kern[i].xyxx;
+			defined_weight += kern[i].xy;
+		}
+	}
 
 
 
 	col /= defined_weight.xyxx;
 	
 	gl_FragColor = col;
-	
-	//gl_FragColor = ccol;
 }
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index e518bddb9840fa4608f1d814620b214e955b549c..0db9586a88d47091fac17fab44e4e9b38d406ca7 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -23,8 +23,6 @@ varying vec4 vary_position;
 varying vec3 vary_normal;
 varying vec3 vary_fragcoord;
 
-uniform float alpha_soften;
-
 uniform mat4 inv_proj;
 
 vec4 getPosition(vec2 pos_screen)
@@ -56,15 +54,6 @@ void main()
 
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
 
-	if (samp_pos.z != 0.0 && color.a < 1.0)
-	{
-		float dist_factor = alpha_soften;
-		float a = color.a;
-		a *= a;
-		dist_factor *= 1.0/(1.0-a);
-		color.a *= min((pos.z-samp_pos.z)*dist_factor, 1.0);
-	}
-
 	//gl_FragColor = gl_Color;
 	gl_FragColor = color;
 	//gl_FragColor = vec4(1,0,1,1);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
index 8c140a7b4f02716fd690ea630fa91b09e9058716..508bbf415ea359c5d3bed932437c2baf0121e59e 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
@@ -11,7 +11,8 @@ uniform sampler2D specularMap;
 
 void main() 
 {
-	gl_FragData[0] = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy);
+	gl_FragData[0] = vec4(col.rgb, col.a <= 0.5 ? 0.0 : 0.005);
 	gl_FragData[1] = texture2D(specularMap, gl_TexCoord[0].xy);
 	gl_FragData[2] = vec4(texture2D(normalMap, gl_TexCoord[0].xy).xyz, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
index 28bcd720c0a294d9202c64486a01813d90cc12f9..82e9450e68473bc45095723b7cfe32c318b7c959 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
@@ -5,9 +5,10 @@
  * $License$
  */
 
-
 #version 120
 
+//class 1 -- no shadows
+
 #extension GL_ARB_texture_rectangle : enable
 
 uniform sampler2DRect diffuseRect;
@@ -26,12 +27,15 @@ uniform vec3 proj_n;
 uniform float proj_focus; //distance from plane to begin blurring
 uniform float proj_lod;  //(number of mips in proj map)
 uniform float proj_range; //range between near clip and far clip plane of projection
+uniform float proj_ambient_lod;
 uniform float proj_ambiance;
 uniform float near_clip;
 uniform float far_clip;
 
 uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
 uniform float sun_wash;
+uniform int proj_shadow_idx;
+uniform float shadow_fade;
 
 varying vec4 vary_light;
 
@@ -40,6 +44,52 @@ uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
 
+vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float det = max(1.0-lod/(proj_lod*0.5), 0.0);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+	
+	float det = min(lod/(proj_lod*0.5), 1.0);
+	
+	float d = min(dist.x, dist.y);
+	
+	float edge = 0.25*det;
+		
+	ret *= clamp(d/edge, 0.0, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0);
+	
+	return ret;
+}
+
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).a;
@@ -68,7 +118,7 @@ void main()
 	{
 		discard;
 	}
-	
+		
 	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
 	
 	norm = normalize(norm);
@@ -83,7 +133,11 @@ void main()
 	proj_tc.xyz /= proj_tc.w;
 	
 	float fa = gl_Color.a+1.0;
-	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
+	float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+	if (dist_atten <= 0.0)
+	{
+		discard;
+	}
 	
 	lv = proj_origin-pos.xyz;
 	lv = normalize(lv);
@@ -101,32 +155,32 @@ void main()
 		proj_tc.y > 0.0)
 	{
 		float lit = 0.0;
+		float amb_da = proj_ambiance;
+		
 		if (da > 0.0)
 		{
 			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
 			float lod = diff * proj_lod;
 			
-			vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+			vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
 		
 			vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
 			
 			lit = da * dist_atten * noise;
 			
 			col = lcol*lit*diff_tex;
+			amb_da += (da*0.5)*proj_ambiance;
 		}
 		
-		float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
-		float lod = diff * proj_lod;
-		vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
-		//float amb_da = mix(proj_ambiance, proj_ambiance*max(-da, 0.0), max(da, 0.0));
-		float amb_da = proj_ambiance;
-		
+		//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
+		vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
+							
 		amb_da += (da*da*0.5+0.5)*proj_ambiance;
-			
+				
 		amb_da *= dist_atten * noise;
-		
+			
 		amb_da = min(amb_da, 1.0-lit);
-		
+			
 		col += amb_da*gl_Color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
 	}
 	
@@ -144,35 +198,28 @@ void main()
 		{
 			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
 			
-			vec3 stc = (proj_mat * vec4(pfinal.xyz, 1.0)).xyz;
+			vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
 
 			if (stc.z > 0.0)
 			{
-				stc.xy /= stc.z+proj_near;
-					
+				stc.xy /= stc.w;
+
+				float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
+				
+				stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
+								
 				if (stc.x < 1.0 &&
 					stc.y < 1.0 &&
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+					vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
 					col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb;
 				}
 			}
 		}
 	}
 	
-	/*if (spec.a > 0.0)
-	{
-		//vec3 ref = reflect(normalize(pos), norm);
-		float sa = dot(normalize(lv-normalize(pos)),norm);;
-		//sa = max(sa, 0.0);
-		//sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
-		sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
-		sa *= noise;
-		col += da*sa*lcol*spec.rgb;
-	}*/
-	
 	gl_FragColor.rgb = col;	
 	gl_FragColor.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index b4b0d0ce9de837d2644ff9aebb7c0a4dcd737719..155f03fdcf908be102160ebca36509b3cc07be11 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -11,6 +11,7 @@ uniform sampler2DRect diffuseRect;
 uniform sampler2DRect specularRect;
 uniform sampler2DRect positionMap;
 uniform sampler2DRect normalMap;
+uniform sampler2DRect lightMap;
 uniform sampler2DRect depthMap;
 uniform sampler2D	  noiseMap;
 uniform samplerCube environmentMap;
@@ -40,7 +41,7 @@ uniform float scene_light_strength;
 uniform vec3 env_mat[3];
 //uniform mat4 shadow_matrix[3];
 //uniform vec4 shadow_clip;
-//uniform mat3 ssao_effect_mat;
+uniform mat3 ssao_effect_mat;
 
 varying vec4 vary_light;
 varying vec2 vary_fragcoord;
@@ -55,9 +56,8 @@ vec3 vary_AtmosAttenuation;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
-vec4 getPosition(vec2 pos_screen)
-{ //get position in screen space (world units) given window coordinate and depth map
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+vec4 getPosition_d(vec2 pos_screen, float depth)
+{
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
@@ -68,6 +68,12 @@ vec4 getPosition(vec2 pos_screen)
 	return pos;
 }
 
+vec4 getPosition(vec2 pos_screen)
+{ //get position in screen space (world units) given window coordinate and depth map
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	return getPosition_d(pos_screen, depth);
+}
+
 vec3 getPositionEye()
 {
 	return vary_PositionEye;
@@ -178,7 +184,17 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
 	temp2.x += .25;
 	
 	//increase ambient when there are more clouds
-	vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow.x * 0.5;	
+	vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow.x * 0.5;
+	
+	/*  decrease value and saturation (that in HSV, not HSL) for occluded areas
+	 * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html
+	 * // The following line of code performs the equivalent of:
+	 * float ambAlpha = tmpAmbient.a;
+	 * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis
+	 * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue);
+	 * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha);
+	 */
+	tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a);
 
 	//haze color
 	setAdditiveColor(
@@ -241,7 +257,8 @@ vec3 scaleSoftClip(vec3 light)
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
-	vec3 pos = getPosition(tc).xyz;
+	float depth = texture2DRect(depthMap, tc.xy).a;
+	vec3 pos = getPosition_d(tc, depth).xyz;
 	vec3 norm = texture2DRect(normalMap, tc).xyz*2.0-1.0;
 	//vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
 	
@@ -250,23 +267,62 @@ void main()
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
 	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
 	
-	calcAtmospherics(pos.xyz, 0.0);
+	vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+	float scol = max(scol_ambocc.r, diffuse.a); 
+	float ambocc = scol_ambocc.g;
+	
+	calcAtmospherics(pos.xyz, ambocc);
 	
 	vec3 col = atmosAmbient(vec3(0));
-	col += atmosAffectDirectionalLight(clamp(da, diffuse.a, 1.0));
+	col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
 	
 	col *= diffuse.rgb;
 	
-	if (spec.a > 0.0)
+	if (spec.a > 0.0) // specular reflection
 	{
-		vec3 ref = normalize(reflect(pos.xyz, norm.xyz));
-		float sa = dot(ref, vary_light.xyz);
-		col.rgb += vary_SunlitColor*spec.rgb*texture2D(lightFunc, vec2(sa, spec.a)).a;
+		// the old infinite-sky shiny reflection
+		//
+		vec3 refnorm = normalize(reflect(pos.xyz, norm.xyz));
+		float sa = dot(refnorm, vary_light.xyz);
+		vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
+
+		// screen-space cheap fakey reflection map
+		//
+		depth -= 0.5; // unbias depth
+		// first figure out where we'll make our 2D guess from
+		vec2 ref2d = (0.25 * screen_res.y) * (refnorm.xy) * abs(refnorm.z) / depth;
+		// Offset the guess source a little according to a trivial
+		// checkerboard dither function and spec.a.
+		// This is meant to be similar to sampling a blurred version
+		// of the diffuse map.  LOD would be better in that regard.
+		// The goal of the blur is to soften reflections in surfaces
+		// with low shinyness, and also to disguise our lameness.
+		float checkerboard = floor(mod(tc.x+tc.y, 2.0)); // 0.0, 1.0
+		ref2d += normalize(ref2d)*14.0*(1.0-spec.a)*(checkerboard-0.5);
+		ref2d += tc.xy; // use as offset from destination
+		// get attributes from the 2D guess point
+		float refdepth = texture2DRect(depthMap, ref2d).a;
+		vec3 refpos = getPosition_d(ref2d, refdepth).xyz;
+		vec3 refcol = texture2DRect(diffuseRect, ref2d).rgb;
+		vec3 refn = normalize(texture2DRect(normalMap, ref2d).rgb * 2.0 - 1.0);
+		// figure out how appropriate our guess actually was
+		float refapprop = max(0.0, dot(-refnorm, normalize(pos - refpos)));
+		// darken reflections from points which face away from the reflected ray - our guess was a back-face
+		//refapprop *= step(dot(refnorm, refn), 0.0);
+		refapprop = min(refapprop, max(0.0, -dot(refnorm, refn))); // more conservative variant
+		// get appropriate light strength for guess-point
+		float reflit = max(dot(refn, lightnorm.xyz), 0.0);
+		// apply sun color to guess-point, dampen according to inappropriateness of guess
+		vec3 refprod = (vary_SunlitColor*reflit) * refcol.rgb * refapprop;
+		vec3 ssshiny = (refprod * spec.a);
+
+		// add the two types of shiny together
+		col += (ssshiny + dumbshiny) * spec.rgb;
 	}
 	
 	col = atmosLighting(col);
 	col = scaleSoftClip(col);
-	
+		
 	gl_FragColor.rgb = col;
 	gl_FragColor.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
index 2a7234fd83bdb3788c392b7935fec020ef5a32b1..f320dbb40017e6f45c364c90024ad8347f4c7ab0 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
@@ -161,17 +161,6 @@ void main()
 		}
 	}
 	
-	/*if (spec.a > 0.0)
-	{
-		//vec3 ref = reflect(normalize(pos), norm);
-		float sa = dot(normalize(lv-normalize(pos)),norm);;
-		//sa = max(sa, 0.0);
-		//sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
-		sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
-		sa *= noise;
-		col += da*sa*lcol*spec.rgb;
-	}*/
-	
 	gl_FragColor.rgb = col;	
 	gl_FragColor.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
index 22bdd2c7f3489743cf42e7c88f346d52f91aea95..56e4055c02c0ff7d53a55aa7e32de1a2c8444e82 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightF.glsl
@@ -5,196 +5,11 @@
  * $License$
  */
 
-#extension GL_ARB_texture_rectangle : enable
-
-uniform sampler2DRect depthMap;
-uniform sampler2DRect normalMap;
-uniform sampler2DRectShadow shadowMap0;
-uniform sampler2DRectShadow shadowMap1;
-uniform sampler2DRectShadow shadowMap2;
-uniform sampler2DRectShadow shadowMap3;
-uniform sampler2DRectShadow shadowMap4;
-uniform sampler2DRectShadow shadowMap5;
-uniform sampler2D noiseMap;
-
-uniform sampler2D		lightFunc;
-
-
-// Inputs
-uniform mat4 shadow_matrix[6];
-uniform vec4 shadow_clip;
-uniform float ssao_radius;
-uniform float ssao_max_radius;
-uniform float ssao_factor;
-uniform float ssao_factor_inv;
-
-varying vec2 vary_fragcoord;
-varying vec4 vary_light;
-
-uniform mat4 inv_proj;
-uniform vec2 screen_res;
-
-uniform float shadow_bias;
-uniform float shadow_offset;
-
-vec4 getPosition(vec2 pos_screen)
-{
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
-	vec2 sc = pos_screen.xy*2.0;
-	sc /= screen_res;
-	sc -= vec2(1.0,1.0);
-	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
-	vec4 pos = inv_proj * ndc;
-	pos /= pos.w;
-	pos.w = 1.0;
-	return pos;
-}
+//class 1, no shadow, no SSAO, should never be called
 
-//calculate decreases in ambient lighting when crowded out (SSAO)
-float calcAmbientOcclusion(vec4 pos, vec3 norm)
-{
-	vec2 kern[8];
-	// exponentially (^2) distant occlusion samples spread around origin
-	kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
-	kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
-	kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
-	kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
-	kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
-	kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
-	kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
-	kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
-
-	vec2 pos_screen = vary_fragcoord.xy;
-	vec3 pos_world = pos.xyz;
-	vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
-	
-	float angle_hidden = 0.0;
-	int points = 0;
-	
-	float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
-	
-	// it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
-	for (int i = 0; i < 8; i++)
-	{
-		vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
-		vec3 samppos_world = getPosition(samppos_screen).xyz; 
-		
-		vec3 diff = pos_world - samppos_world;
-		float dist2 = dot(diff, diff);
-		
-		// assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
-		// --> solid angle shrinking by the square of distance
-		//radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
-		//(k should vary inversely with # of samples, but this is taken care of later)
-		
-		//if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0)  // -0.05*norm to shift sample point back slightly for flat surfaces
-		//	angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional.  max of 1.0 (= ssao_factor_inv * ssao_factor)
-		angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
-		
-		// 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" 
-		points = points + int(diff.z > -1.0);
-	}
-	
-	angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
-	
-	return (1.0 - (float(points != 0) * angle_hidden));
-}
+#extension GL_ARB_texture_rectangle : enable
 
 void main() 
 {
-	vec2 pos_screen = vary_fragcoord.xy;
-	
-	//try doing an unproject here
-	
-	vec4 pos = getPosition(pos_screen);
-	
-    vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
-	
-	/*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL
-	{
-		gl_FragColor = vec4(0.0); // doesn't matter
-		return;
-	}*/
-	
-	float shadow = 1.0;
-    float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
-
-	vec4 spos = vec4(pos.xyz + norm.xyz * (-pos.z/64.0*shadow_offset+shadow_bias), 1.0);
-	
-	//vec3 debug = vec3(0,0,0);
-	
-	if (dp_directional_light == 0.0)
-	{
-		// if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup
-		shadow = 0.0;
-	}
-	else if (spos.z > -shadow_clip.w)
-	{	
-		vec4 lpos;
-		
-		if (spos.z < -shadow_clip.z)
-		{
-			lpos = shadow_matrix[3]*spos;
-			lpos.xy *= screen_res;
-			shadow = shadow2DRectProj(shadowMap3, lpos).x;
-			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
-		}
-		else if (spos.z < -shadow_clip.y)
-		{
-			lpos = shadow_matrix[2]*spos;
-			lpos.xy *= screen_res;
-			shadow = shadow2DRectProj(shadowMap2, lpos).x;
-		}
-		else if (spos.z < -shadow_clip.x)
-		{
-			lpos = shadow_matrix[1]*spos;
-			lpos.xy *= screen_res;
-			shadow = shadow2DRectProj(shadowMap1, lpos).x;
-		}
-		else
-		{
-			lpos = shadow_matrix[0]*spos;
-			lpos.xy *= screen_res;
-			shadow = shadow2DRectProj(shadowMap0, lpos).x;
-		}
-
-		// take the most-shadowed value out of these two:
-		//  * the blurred sun shadow in the light (shadow) map
-		//  * an unblurred dot product between the sun and this norm
-		// the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting
-		shadow = min(shadow, dp_directional_light);
-		
-		/*debug.r = lpos.y / (lpos.w*screen_res.y);
-		
-		lpos.xy /= lpos.w*32.0;
-		if (fract(lpos.x) < 0.1 || fract(lpos.y) < 0.1)
-		{
-			debug.gb = vec2(0.5, 0.5);
-		}
-		
-		debug += (1.0-shadow)*0.5;*/
-		
-	}
-	else
-	{
-		// more distant than the shadow map covers - just use directional shading as shadow
-		shadow = dp_directional_light;
-	}
-	
-	gl_FragColor[0] = shadow;
-	gl_FragColor[1] = calcAmbientOcclusion(pos, norm);
-	
-	//spotlight shadow 1
-	vec4 lpos = shadow_matrix[4]*spos;
-	lpos.xy *= screen_res;
-	gl_FragColor[2] = shadow2DRectProj(shadowMap4, lpos).x; 
-	
-	//spotlight shadow 2
-	lpos = shadow_matrix[5]*spos;
-	lpos.xy *= screen_res;
-	gl_FragColor[3] = shadow2DRectProj(shadowMap5, lpos).x; 
-
-	//gl_FragColor.rgb = pos.xyz;
-	//gl_FragColor.b = shadow;
-	//gl_FragColor.rgb = debug;
+	gl_FragColor = vec4(0,0,0,0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..7450817ea7a3553e4590908cd73b5e00bbef9058
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
@@ -0,0 +1,123 @@
+/** 
+ * @file sunLightSSAOF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+//class 1 -- no shadow, SSAO only
+
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform sampler2D noiseMap;
+
+uniform sampler2D		lightFunc;
+
+
+// Inputs
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform float ssao_radius;
+uniform float ssao_max_radius;
+uniform float ssao_factor;
+uniform float ssao_factor_inv;
+
+varying vec2 vary_fragcoord;
+varying vec4 vary_light;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
+uniform float shadow_bias;
+uniform float shadow_offset;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+//calculate decreases in ambient lighting when crowded out (SSAO)
+float calcAmbientOcclusion(vec4 pos, vec3 norm)
+{
+	float ret = 1.0;
+	
+	float dist = dot(pos.xyz,pos.xyz);
+	
+	if (dist < 64.0*64.0)
+	{
+		vec2 kern[8];
+		// exponentially (^2) distant occlusion samples spread around origin
+		kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
+		kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
+		kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
+		kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
+		kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
+		kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
+		kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
+		kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
+
+		vec2 pos_screen = vary_fragcoord.xy;
+		vec3 pos_world = pos.xyz;
+		vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
+		
+		float angle_hidden = 0.0;
+		int points = 0;
+		
+		float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
+		
+		// it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
+		for (int i = 0; i < 8; i++)
+		{
+			vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
+			vec3 samppos_world = getPosition(samppos_screen).xyz; 
+			
+			vec3 diff = pos_world - samppos_world;
+			float dist2 = dot(diff, diff);
+			
+			// assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
+			// --> solid angle shrinking by the square of distance
+			//radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
+			//(k should vary inversely with # of samples, but this is taken care of later)
+			
+			//if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0)  // -0.05*norm to shift sample point back slightly for flat surfaces
+			//	angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional.  max of 1.0 (= ssao_factor_inv * ssao_factor)
+			angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
+			
+			// 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" 
+			points = points + int(diff.z > -1.0);
+		}
+		
+		angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
+		
+		ret = (1.0 - (float(points != 0) * angle_hidden));
+		ret += max((dist-32.0*32.0)/(32.0*32.0), 0.0);
+	}
+	
+	return min(ret, 1.0);
+}
+
+void main() 
+{
+	vec2 pos_screen = vary_fragcoord.xy;
+	
+	//try doing an unproject here
+	
+	vec4 pos = getPosition(pos_screen);
+	
+    vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
+		
+	gl_FragColor[0] = 1.0;
+	gl_FragColor[1] = calcAmbientOcclusion(pos, norm);
+	gl_FragColor[2] = 1.0; 
+	gl_FragColor[3] = 1.0;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
index d21575119ddab856fbd254de66ed0ceaca449672..ceb7e0fb56e2e57424fec8a1d48beef29231f808 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
@@ -115,7 +115,7 @@ void main()
 	vec4 fb = texture2D(screenTex, distort2);
 	
 	//mix with reflection
-	// Note we actually want to use just df1, but multiplying by 0.999999 gets around and nvidia compiler bug
+	// Note we actually want to use just df1, but multiplying by 0.999999 gets around an nvidia compiler bug
 	color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999);
 	
 	float shadow = 1.0;
@@ -131,11 +131,11 @@ void main()
 	//color.rgb = scaleSoftClip(color.rgb);
 	//color.a = spec * sunAngle2;
 
-	//wavef.z = -0.25f;
-	wavef = normalize(wavef);
-	wavef = (norm_mat*vec4(wavef, 1.0)).xyz;
+	//wavef.z *= 0.1f;
+	//wavef = normalize(wavef);
+	vec3 screenspacewavef = (norm_mat*vec4(wavef, 1.0)).xyz;
 	
-	gl_FragData[0] = vec4(color.rgb, 0.75);
-	gl_FragData[1] = vec4(1,1,1, 0.8);
-	gl_FragData[2] = vec4(wavef*0.5+0.5, 0.0);
+	gl_FragData[0] = vec4(color.rgb, 0.5); // diffuse
+	gl_FragData[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec
+	gl_FragData[2] = vec4(screenspacewavef*0.5+0.5, screenspacewavef.z*0.5); // normal, displace
 }
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl
index 3e8fdfb3e48e3235502d2665f9bed5552886b859..da49e59b89ec82f2e3876a34b61c901c548df48f 100644
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFuncV.glsl
@@ -12,7 +12,8 @@ float calcDirectionalLight(vec3 n, vec3 l)
 	return a;
 }
 
-float calcPointLight(vec3 v, vec3 n, vec4 lp, float la)
+
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight)
 {
 	//get light vector
 	vec3 lv = lp.xyz-v;
@@ -26,9 +27,13 @@ float calcPointLight(vec3 v, vec3 n, vec4 lp, float la)
 	//distance attenuation
 	float da = clamp(1.0/(la * d), 0.0, 1.0);
 	
+	// spotlight coefficient.
+	float spot = max(dot(-ln, lv), is_pointlight);
+	da *= spot*spot; // GL_SPOT_EXPONENT=2
+
 	//angular attenuation
 	da *= calcDirectionalLight(n, lv);
-	
+
 	return da;	
 }
 
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index ad16de6d8160a7e34589fc82bec521af550f70c1..665fe16b4392f0b95ff72c0d7f7fc72c10cc7b6f 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
@@ -29,8 +29,6 @@ varying vec3 vary_fragcoord;
 varying vec3 vary_position;
 varying vec3 vary_light;
 
-uniform float alpha_soften;
-
 uniform float shadow_bias;
 
 uniform mat4 inv_proj;
@@ -115,15 +113,6 @@ void main()
 
 	color.rgb = scaleSoftClip(color.rgb);
 
-	if (samp_pos.z != 0.0 && gl_Color.a < 1.0)
-	{
-		float dist_factor = alpha_soften;
-		float a = gl_Color.a;
-		a *= a;
-		dist_factor *= 1.0/(1.0-a);
-		color.a *= min((pos.z-samp_pos.z)*dist_factor, 1.0);
-	}
-	
 	//gl_FragColor = gl_Color;
 	gl_FragColor = color;
 	//gl_FragColor = vec4(1,0,1,1)*shadow;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
index 5991e1f3b5eae3fd2b9d77079e2fe4849ad63e89..1fae8c4da3849a314452d10f6473dc22d569fcf9 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
@@ -9,7 +9,7 @@ vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
 void calcAtmospherics(vec3 inPositionEye);
 
 float calcDirectionalLight(vec3 n, vec3 l);
-float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
 
 vec3 atmosAmbient(vec3 light);
 vec3 atmosAffectDirectionalLight(float lightIntensity);
@@ -42,23 +42,21 @@ void main()
 	calcAtmospherics(pos.xyz);
 
 	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
-	vec4 col;
-	col.a = gl_Color.a;
-	
-	// Add windlight lights
-	col.rgb = atmosAmbient(vec3(0.));
-	col.rgb = scaleUpLight(col.rgb);
+	vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
 
 	// Collect normal lights (need to be divided by two, as we later multiply by 2)
-	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
-	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
-	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
-	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
- 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
- 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a);
+	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a);
+	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a);
 	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
 	col.rgb = scaleDownLight(col.rgb);
 	
+	// Add windlight lights
+	col.rgb += atmosAmbient(vec3(0.));
+	
 	vary_light = gl_LightSource[0].position.xyz;
 	
 	vary_ambient = col.rgb*gl_Color.rgb;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl
index a939499b1710a48337c8793a1ca5ef6ec00083df..f8dd1b74314003ab218ccb6be1aa7a3bb730d4c4 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/avatarAlphaV.glsl
@@ -10,7 +10,7 @@ mat4 getSkinnedTransform();
 void calcAtmospherics(vec3 inPositionEye);
 
 float calcDirectionalLight(vec3 n, vec3 l);
-float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
 
 vec3 atmosAmbient(vec3 light);
 vec3 atmosAffectDirectionalLight(float lightIntensity);
@@ -53,23 +53,22 @@ void main()
 	calcAtmospherics(pos.xyz);
 
 	//vec4 color = calcLighting(pos.xyz, norm, gl_Color, vec4(0.));
-	vec4 col;
-	col.a = gl_Color.a;
-	
-	// Add windlight lights
-	col.rgb = atmosAmbient(vec3(0.));
-	col.rgb = scaleUpLight(col.rgb);
+
+	vec4 col = vec4(0.0, 0.0, 0.0, gl_Color.a);
 
 	// Collect normal lights (need to be divided by two, as we later multiply by 2)
-	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
-	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
-	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
-	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
- 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
- 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a);
+	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a);
+	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a);
 	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
 	col.rgb = scaleDownLight(col.rgb);
 	
+	// Add windlight lights
+	col.rgb += atmosAmbient(vec3(0.));
+	
 	vary_ambient = col.rgb*gl_Color.rgb;
 	vary_directional = gl_Color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, gl_LightSource[0].position.xyz), (1.0-gl_Color.a)*(1.0-gl_Color.a)));
 	
diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
index 651959413cd06cad296bf3dfd2a4e3a89babe51e..5308e5bb1e10555660b83551e20b4a7c5776d05a 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
@@ -43,6 +43,52 @@ uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
 
+vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float det = max(1.0-lod/(proj_lod*0.5), 0.0);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0)+det, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
+	
+	float det = min(lod/(proj_lod*0.5), 1.0);
+	
+	float d = min(dist.x, dist.y);
+	
+	float edge = 0.25*det;
+		
+	ret *= clamp(d/edge, 0.0, 1.0);
+	
+	return ret;
+}
+
+vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
+{
+	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	
+	vec2 dist = tc-vec2(0.5);
+	
+	float d = dot(dist,dist);
+		
+	ret *= min(clamp((0.25-d)/0.25, 0.0, 1.0), 1.0);
+	
+	return ret;
+}
+
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).a;
@@ -126,7 +172,7 @@ void main()
 			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
 			float lod = diff * proj_lod;
 			
-			vec4 plcol = texture2DLod(projectionMap, proj_tc.xy, lod);
+			vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
 		
 			vec3 lcol = gl_Color.rgb * plcol.rgb * plcol.a;
 			
@@ -137,7 +183,7 @@ void main()
 		}
 		
 		//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
-		vec4 amb_plcol = texture2DLod(projectionMap, proj_tc.xy, proj_ambient_lod);
+		vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
 							
 		amb_da += (da*da*0.5+0.5)*proj_ambiance;
 				
@@ -167,22 +213,23 @@ void main()
 			if (stc.z > 0.0)
 			{
 				stc.xy /= stc.w;
-					
+
+				float fatten = clamp(spec.a*spec.a+spec.a*0.5, 0.25, 1.0);
+				
+				stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
+								
 				if (stc.x < 1.0 &&
 					stc.y < 1.0 &&
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					vec4 scol = texture2DLod(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
+					vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
 					col += dist_atten*scol.rgb*gl_Color.rgb*scol.a*spec.rgb*shadow;
 				}
 			}
 		}
 	}
 	
-	//attenuate point light contribution by SSAO component
-	col *= texture2DRect(lightMap, frag.xy).g;
-	
 	gl_FragColor.rgb = col;	
 	gl_FragColor.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 531f7376a37b2142323eb3a774d15538a848fae6..922a07c306694e9d8e446f383992b364b6c4a967 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -11,6 +11,7 @@ uniform sampler2DRect diffuseRect;
 uniform sampler2DRect specularRect;
 uniform sampler2DRect normalMap;
 uniform sampler2DRect lightMap;
+uniform sampler2DRect depthMap;
 uniform sampler2D	  noiseMap;
 uniform samplerCube environmentMap;
 uniform sampler2D	  lightFunc;
@@ -41,7 +42,6 @@ uniform vec3 env_mat[3];
 uniform vec4 shadow_clip;
 uniform mat3 ssao_effect_mat;
 
-uniform sampler2DRect depthMap;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
@@ -55,9 +55,8 @@ vec3 vary_AmblitColor;
 vec3 vary_AdditiveColor;
 vec3 vary_AtmosAttenuation;
 
-vec4 getPosition(vec2 pos_screen)
-{ //get position in screen space (world units) given window coordinate and depth map
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+vec4 getPosition_d(vec2 pos_screen, float depth)
+{
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
@@ -68,6 +67,12 @@ vec4 getPosition(vec2 pos_screen)
 	return pos;
 }
 
+vec4 getPosition(vec2 pos_screen)
+{ //get position in screen space (world units) given window coordinate and depth map
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	return getPosition_d(pos_screen, depth);
+}
+
 vec3 getPositionEye()
 {
 	return vary_PositionEye;
@@ -251,7 +256,8 @@ vec3 scaleSoftClip(vec3 light)
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
-	vec3 pos = getPosition(tc).xyz;
+	float depth = texture2DRect(depthMap, tc.xy).a;
+	vec3 pos = getPosition_d(tc, depth).xyz;
 	vec3 norm = texture2DRect(normalMap, tc).xyz*2.0-1.0;
 	//vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
 	
@@ -271,24 +277,52 @@ void main()
 	
 	col *= diffuse.rgb;
 	
-	if (spec.a > 0.0)
+	if (spec.a > 0.0) // specular reflection
 	{
-		vec3 ref = normalize(reflect(pos.xyz, norm.xyz));
-		float sa = dot(ref, vary_light.xyz);
-		col.rgb += vary_SunlitColor*scol*spec.rgb*texture2D(lightFunc, vec2(sa, spec.a)).a;
+		// the old infinite-sky shiny reflection
+		//
+		vec3 refnorm = normalize(reflect(pos.xyz, norm.xyz));
+		float sa = dot(refnorm, vary_light.xyz);
+		vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
+
+		// screen-space cheap fakey reflection map
+		//
+		depth -= 0.5; // unbias depth
+		// first figure out where we'll make our 2D guess from
+		vec2 ref2d = (0.25 * screen_res.y) * (refnorm.xy) * abs(refnorm.z) / depth;
+		// Offset the guess source a little according to a trivial
+		// checkerboard dither function and spec.a.
+		// This is meant to be similar to sampling a blurred version
+		// of the diffuse map.  LOD would be better in that regard.
+		// The goal of the blur is to soften reflections in surfaces
+		// with low shinyness, and also to disguise our lameness.
+		float checkerboard = floor(mod(tc.x+tc.y, 2.0)); // 0.0, 1.0
+		ref2d += normalize(ref2d)*14.0*(1.0-spec.a)*(checkerboard-0.5);
+		ref2d += tc.xy; // use as offset from destination
+		// get attributes from the 2D guess point
+		float refdepth = texture2DRect(depthMap, ref2d).a;
+		vec3 refpos = getPosition_d(ref2d, refdepth).xyz;
+		vec3 refcol = texture2DRect(diffuseRect, ref2d).rgb;
+		float refshad = texture2DRect(lightMap, ref2d).r;
+		vec3 refn = normalize(texture2DRect(normalMap, ref2d).rgb * 2.0 - 1.0);
+		// figure out how appropriate our guess actually was
+		float refapprop = max(0.0, dot(-refnorm, normalize(pos - refpos)));
+		// darken reflections from points which face away from the reflected ray - our guess was a back-face
+		//refapprop *= step(dot(refnorm, refn), 0.0);
+		refapprop = min(refapprop, max(0.0, -dot(refnorm, refn))); // more conservative variant
+		// get appropriate light strength for guess-point
+		float reflit = min(max(dot(refn, lightnorm.xyz), 0.0), refshad);
+		// apply sun color to guess-point, dampen according to inappropriateness of guess
+		vec3 refprod = (vary_SunlitColor*reflit) * refcol.rgb * refapprop;
+		vec3 ssshiny = (refprod * spec.a);
+
+		// add the two types of shiny together
+		col += (ssshiny + dumbshiny) * spec.rgb;
 	}
 	
 	col = atmosLighting(col);
 	col = scaleSoftClip(col);
 		
 	gl_FragColor.rgb = col;
-	
-	//gl_FragColor.rgb = gi_col.rgb;
 	gl_FragColor.a = 0.0;
-	
-	//gl_FragColor.rg = scol_ambocc.rg;
-	//gl_FragColor.rgb = texture2DRect(lightMap, vary_fragcoord.xy).rgb;
-	//gl_FragColor.rgb = norm.rgb*0.5+0.5;
-	//gl_FragColor.rgb = vec3(ambocc);
-	//gl_FragColor.rgb = vec3(scol);
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
index d6534083cfe220affb92736c0a6ef4b42de91712..eeaecc157ff16d0859d4d14fb571e6cd76b43115 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
@@ -179,21 +179,6 @@ void main()
 		}
 	}
 	
-	/*if (spec.a > 0.0)
-	{
-		//vec3 ref = reflect(normalize(pos), norm);
-		float sa = dot(normalize(lv-normalize(pos)),norm);;
-		//sa = max(sa, 0.0);
-		//sa = pow(sa, 128.0 * spec.a*spec.a/dist_atten)*min(dist_atten*4.0, 1.0);
-		sa = texture2D(lightFunc, vec2(sa, spec.a)).a * min(dist_atten*4.0, 1.0);
-		sa *= noise;
-		col += da*sa*lcol*spec.rgb;
-	}*/
-	
-	//attenuate point light contribution by SSAO component
-	col *= texture2DRect(lightMap, frag.xy).g;
-	
-
 	gl_FragColor.rgb = col;	
 	gl_FragColor.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
index a0026edcd2186c76264351f698cad8a60371bf46..04c9a4d19aac6e4f622824562756303365f0e059 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
@@ -7,6 +7,8 @@
 
 #extension GL_ARB_texture_rectangle : enable
 
+//class 2, shadows, no SSAO
+
 uniform sampler2DRect depthMap;
 uniform sampler2DRect normalMap;
 uniform sampler2DRectShadow shadowMap0;
@@ -52,56 +54,6 @@ vec4 getPosition(vec2 pos_screen)
 	return pos;
 }
 
-//calculate decreases in ambient lighting when crowded out (SSAO)
-float calcAmbientOcclusion(vec4 pos, vec3 norm)
-{
-	vec2 kern[8];
-	// exponentially (^2) distant occlusion samples spread around origin
-	kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
-	kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
-	kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
-	kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
-	kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
-	kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
-	kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
-	kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
-
-	vec2 pos_screen = vary_fragcoord.xy;
-	vec3 pos_world = pos.xyz;
-	vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
-	
-	float angle_hidden = 0.0;
-	int points = 0;
-	
-	float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
-	
-	// it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
-	for (int i = 0; i < 8; i++)
-	{
-		vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
-		vec3 samppos_world = getPosition(samppos_screen).xyz; 
-		
-		vec3 diff = pos_world - samppos_world;
-		float dist2 = dot(diff, diff);
-		
-		// assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
-		// --> solid angle shrinking by the square of distance
-		//radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
-		//(k should vary inversely with # of samples, but this is taken care of later)
-		
-		//if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0)  // -0.05*norm to shift sample point back slightly for flat surfaces
-		//	angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional.  max of 1.0 (= ssao_factor_inv * ssao_factor)
-		angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
-		
-		// 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" 
-		points = points + int(diff.z > -1.0);
-	}
-	
-	angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
-	
-	return (1.0 - (float(points != 0) * angle_hidden));
-}
-
 float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
 {
 	stc.xyz /= stc.w;
@@ -149,7 +101,9 @@ void main()
 	
 	vec4 pos = getPosition(pos_screen);
 	
-    vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
+	vec4 nmap4 = texture2DRect(normalMap, pos_screen);
+	float displace = nmap4.w;
+	vec3 norm = nmap4.xyz*2.0-1.0;
 	
 	/*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL
 	{
@@ -158,9 +112,9 @@ void main()
 	}*/
 	
 	float shadow = 1.0;
-    float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
+	float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
 
-	vec4 spos = vec4(pos.xyz + vary_light.xyz * (1.0-dp_directional_light)*shadow_offset, 1.0);
+	vec4 spos = vec4(pos.xyz + displace*norm + vary_light.xyz * (1.0-dp_directional_light)*shadow_offset, 1.0);
 	
 	if (spos.z > -shadow_clip.w)
 	{	
@@ -220,15 +174,15 @@ void main()
 	}
 	
 	gl_FragColor[0] = shadow;
-	gl_FragColor[1] = calcAmbientOcclusion(pos, norm);
+	gl_FragColor[1] = 1.0;
 	
 	//spotlight shadow 1
 	vec4 lpos = shadow_matrix[4]*spos;
-	gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.1).x; 
+	gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.8).x; 
 	
 	//spotlight shadow 2
 	lpos = shadow_matrix[5]*spos;
-	gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.1).x; 
+	gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.8).x; 
 
 	//gl_FragColor.rgb = pos.xyz;
 	//gl_FragColor.b = shadow;
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..d77d17942a6ad2b4b4049d2f4d671ecd493de75c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
@@ -0,0 +1,248 @@
+/** 
+ * @file sunLightSSAOF.glsl
+ *
+ * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc.
+ * $License$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+//class 2 -- shadows and SSAO
+
+uniform sampler2DRect depthMap;
+uniform sampler2DRect normalMap;
+uniform sampler2DRectShadow shadowMap0;
+uniform sampler2DRectShadow shadowMap1;
+uniform sampler2DRectShadow shadowMap2;
+uniform sampler2DRectShadow shadowMap3;
+uniform sampler2DShadow shadowMap4;
+uniform sampler2DShadow shadowMap5;
+uniform sampler2D noiseMap;
+
+uniform sampler2D		lightFunc;
+
+// Inputs
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform float ssao_radius;
+uniform float ssao_max_radius;
+uniform float ssao_factor;
+uniform float ssao_factor_inv;
+
+varying vec2 vary_fragcoord;
+varying vec4 vary_light;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+uniform vec2 shadow_res;
+uniform vec2 proj_shadow_res;
+
+uniform float shadow_bias;
+uniform float shadow_offset;
+
+vec4 getPosition(vec2 pos_screen)
+{
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+//calculate decreases in ambient lighting when crowded out (SSAO)
+float calcAmbientOcclusion(vec4 pos, vec3 norm)
+{
+	float ret = 1.0;
+	
+	float dist = dot(pos.xyz,pos.xyz);
+	
+	if (dist < 64.0*64.0)
+	{
+		vec2 kern[8];
+		// exponentially (^2) distant occlusion samples spread around origin
+		kern[0] = vec2(-1.0, 0.0) * 0.125*0.125;
+		kern[1] = vec2(1.0, 0.0) * 0.250*0.250;
+		kern[2] = vec2(0.0, 1.0) * 0.375*0.375;
+		kern[3] = vec2(0.0, -1.0) * 0.500*0.500;
+		kern[4] = vec2(0.7071, 0.7071) * 0.625*0.625;
+		kern[5] = vec2(-0.7071, -0.7071) * 0.750*0.750;
+		kern[6] = vec2(-0.7071, 0.7071) * 0.875*0.875;
+		kern[7] = vec2(0.7071, -0.7071) * 1.000*1.000;
+
+		vec2 pos_screen = vary_fragcoord.xy;
+		vec3 pos_world = pos.xyz;
+		vec2 noise_reflect = texture2D(noiseMap, vary_fragcoord.xy/128.0).xy;
+		
+		float angle_hidden = 0.0;
+		int points = 0;
+		
+		float scale = min(ssao_radius / -pos_world.z, ssao_max_radius);
+		
+		// it was found that keeping # of samples a constant was the fastest, probably due to compiler optimizations (unrolling?)
+		for (int i = 0; i < 8; i++)
+		{
+			vec2 samppos_screen = pos_screen + scale * reflect(kern[i], noise_reflect);
+			vec3 samppos_world = getPosition(samppos_screen).xyz; 
+			
+			vec3 diff = pos_world - samppos_world;
+			float dist2 = dot(diff, diff);
+			
+			// assume each sample corresponds to an occluding sphere with constant radius, constant x-sectional area
+			// --> solid angle shrinking by the square of distance
+			//radius is somewhat arbitrary, can approx with just some constant k * 1 / dist^2
+			//(k should vary inversely with # of samples, but this is taken care of later)
+			
+			//if (dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0)  // -0.05*norm to shift sample point back slightly for flat surfaces
+			//	angle_hidden += min(1.0/dist2, ssao_factor_inv); // dist != 0 follows from conditional.  max of 1.0 (= ssao_factor_inv * ssao_factor)
+			angle_hidden = angle_hidden + float(dot((samppos_world - 0.05*norm - pos_world), norm) > 0.0) * min(1.0/dist2, ssao_factor_inv);
+			
+			// 'blocked' samples (significantly closer to camera relative to pos_world) are "no data", not "no occlusion" 
+			points = points + int(diff.z > -1.0);
+		}
+		
+		angle_hidden = min(ssao_factor*angle_hidden/float(points), 1.0);
+		
+		ret = (1.0 - (float(points != 0) * angle_hidden));
+		ret += max((dist-32.0*32.0)/(32.0*32.0), 0.0);
+	}
+	
+	return min(ret, 1.0);
+}
+
+float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias*scl;
+	
+	float cs = shadow2DRect(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, 1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(1.5, -1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, 1.5, 0.0)).x, cs);
+	shadow += max(shadow2DRect(shadowMap, stc.xyz+vec3(-1.5, -1.5, 0.0)).x, cs);
+			
+	return shadow/5.0;
+	
+	//return shadow;
+}
+
+float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias*scl;
+	
+	float cs = shadow2D(shadowMap, stc.xyz).x;
+	float shadow = cs;
+
+	vec2 off = 1.5/proj_shadow_res;
+	
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(off.x, -off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, off.y, 0.0)).x, cs);
+	shadow += max(shadow2D(shadowMap, stc.xyz+vec3(-off.x, -off.y, 0.0)).x, cs);
+	
+			
+	return shadow/5.0;
+	
+	//return shadow;
+}
+
+void main() 
+{
+	vec2 pos_screen = vary_fragcoord.xy;
+	
+	//try doing an unproject here
+	
+	vec4 pos = getPosition(pos_screen);
+	
+	vec4 nmap4 = texture2DRect(normalMap, pos_screen);
+	float displace = nmap4.w;
+	vec3 norm = nmap4.xyz*2.0-1.0;
+	
+	/*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL
+	{
+		gl_FragColor = vec4(0.0); // doesn't matter
+		return;
+	}*/
+	
+	float shadow = 1.0;
+	float dp_directional_light = max(0.0, dot(norm, vary_light.xyz));
+
+	vec4 spos = vec4(pos.xyz + displace*norm + vary_light.xyz * (1.0-dp_directional_light)*shadow_offset, 1.0);
+	
+	if (spos.z > -shadow_clip.w)
+	{	
+		if (dp_directional_light == 0.0)
+		{
+			// if we know this point is facing away from the sun then we know it's in shadow without having to do a squirrelly shadow-map lookup
+			shadow = 0.0;
+		}
+		else
+		{
+			vec4 lpos;
+			
+			if (spos.z < -shadow_clip.z)
+			{
+				lpos = shadow_matrix[3]*spos;
+				lpos.xy *= shadow_res;
+				shadow = pcfShadow(shadowMap3, lpos, 0.25);
+				shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+			}
+			else if (spos.z < -shadow_clip.y)
+			{
+				lpos = shadow_matrix[2]*spos;
+				lpos.xy *= shadow_res;
+				shadow = pcfShadow(shadowMap2, lpos, 0.5);
+			}
+			else if (spos.z < -shadow_clip.x)
+			{
+				lpos = shadow_matrix[1]*spos;
+				lpos.xy *= shadow_res;
+				shadow = pcfShadow(shadowMap1, lpos, 0.75);
+			}
+			else
+			{
+				lpos = shadow_matrix[0]*spos;
+				lpos.xy *= shadow_res;
+				shadow = pcfShadow(shadowMap0, lpos, 1.0);
+			}
+		
+			// take the most-shadowed value out of these two:
+			//  * the blurred sun shadow in the light (shadow) map
+			//  * an unblurred dot product between the sun and this norm
+			// the goal is to err on the side of most-shadow to fill-in shadow holes and reduce artifacting
+			shadow = min(shadow, dp_directional_light);
+			
+			//lpos.xy /= lpos.w*32.0;
+			//if (fract(lpos.x) < 0.1 || fract(lpos.y) < 0.1)
+			//{
+			//	shadow = 0.0;
+			//}
+			
+		}
+	}
+	else
+	{
+		// more distant than the shadow map covers
+		shadow = 1.0;
+	}
+	
+	gl_FragColor[0] = shadow;
+	gl_FragColor[1] = calcAmbientOcclusion(pos, norm);
+	
+	//spotlight shadow 1
+	vec4 lpos = shadow_matrix[4]*spos;
+	gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.8).x; 
+	
+	//spotlight shadow 2
+	lpos = shadow_matrix[5]*spos;
+	gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.8).x; 
+
+	//gl_FragColor.rgb = pos.xyz;
+	//gl_FragColor.b = shadow;
+}
diff --git a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl
index f4c59734a47c2773957b5ec594929bb6918e88f6..19800d96dc6321e7f5837bcb80e5af1fcdcb8822 100644
--- a/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl
+++ b/indra/newview/app_settings/shaders/class2/lighting/sumLightsV.glsl
@@ -6,7 +6,7 @@
  */
 
 float calcDirectionalLight(vec3 n, vec3 l);
-float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
 
 vec3 atmosAmbient(vec3 light);
 vec3 atmosAffectDirectionalLight(float lightIntensity);
@@ -18,9 +18,10 @@ vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight)
 	
 	// Collect normal lights (need to be divided by two, as we later multiply by 2)
 	col.rgb += gl_LightSource[1].diffuse.rgb * calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
-	col.rgb += gl_LightSource[2].diffuse.rgb * calcPointLight(pos, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
-	col.rgb += gl_LightSource[3].diffuse.rgb * calcPointLight(pos, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
-	//col.rgb += gl_LightSource[4].diffuse.rgb * calcPointLight(pos, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
+
+	col.rgb += gl_LightSource[2].diffuse.rgb * calcPointLightOrSpotLight(pos, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
+	col.rgb += gl_LightSource[3].diffuse.rgb * calcPointLightOrSpotLight(pos, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
+	//col.rgb += gl_LightSource[4].diffuse.rgb * calcPointLightOrSpotLight(pos, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
 	col.rgb = scaleDownLight(col.rgb);
 
 	// Add windlight lights
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index 96a083b52216947b72f53b67522fb86554de6b46..ddd69befc365a72eb08f99d08a8c52bf2c93c9b6 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
@@ -56,9 +56,8 @@ vec3 vary_AdditiveColor;
 vec3 vary_AtmosAttenuation;
 uniform float gi_ambiance;
 
-vec4 getPosition(vec2 pos_screen)
-{ //get position in screen space (world units) given window coordinate and depth map
-	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+vec4 getPosition_d(vec2 pos_screen, float depth)
+{
 	vec2 sc = pos_screen.xy*2.0;
 	sc /= screen_res;
 	sc -= vec2(1.0,1.0);
@@ -69,6 +68,12 @@ vec4 getPosition(vec2 pos_screen)
 	return pos;
 }
 
+vec4 getPosition(vec2 pos_screen)
+{ //get position in screen space (world units) given window coordinate and depth map
+	float depth = texture2DRect(depthMap, pos_screen.xy).a;
+	return getPosition_d(pos_screen, depth);
+}
+
 vec3 getPositionEye()
 {
 	return vary_PositionEye;
@@ -252,7 +257,8 @@ vec3 scaleSoftClip(vec3 light)
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
-	vec3 pos = getPosition(tc).xyz;
+	float depth = texture2DRect(depthMap, tc.xy).a;
+	vec3 pos = getPosition_d(tc, depth).xyz;
 	vec3 norm = texture2DRect(normalMap, tc).xyz*2.0-1.0;
 	//vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
 	
@@ -274,11 +280,47 @@ void main()
 	
 	col *= diffuse.rgb;
 	
-	if (spec.a > 0.0)
+	if (spec.a > 0.0) // specular reflection
 	{
-		vec3 ref = normalize(reflect(pos.xyz, norm.xyz));
-		float sa = dot(ref, vary_light.xyz);
-		col.rgb += vary_SunlitColor*scol*spec.rgb*texture2D(lightFunc, vec2(sa, spec.a)).a;
+		// the old infinite-sky shiny reflection
+		//
+		vec3 refnorm = normalize(reflect(pos.xyz, norm.xyz));
+		float sa = dot(refnorm, vary_light.xyz);
+		vec3 dumbshiny = vary_SunlitColor*scol*texture2D(lightFunc, vec2(sa, spec.a)).a;
+
+		// screen-space cheap fakey reflection map
+		//
+		depth -= 0.5; // unbias depth
+		// first figure out where we'll make our 2D guess from
+		vec2 ref2d = (0.25 * screen_res.y) * (refnorm.xy) * abs(refnorm.z) / depth;
+		// Offset the guess source a little according to a trivial
+		// checkerboard dither function and spec.a.
+		// This is meant to be similar to sampling a blurred version
+		// of the diffuse map.  LOD would be better in that regard.
+		// The goal of the blur is to soften reflections in surfaces
+		// with low shinyness, and also to disguise our lameness.
+		float checkerboard = floor(mod(tc.x+tc.y, 2.0)); // 0.0, 1.0
+		ref2d += normalize(ref2d)*14.0*(1.0-spec.a)*(checkerboard-0.5);
+		ref2d += tc.xy; // use as offset from destination
+		// get attributes from the 2D guess point
+		float refdepth = texture2DRect(depthMap, ref2d).a;
+		vec3 refpos = getPosition_d(ref2d, refdepth).xyz;
+		vec3 refcol = texture2DRect(diffuseRect, ref2d).rgb;
+		float refshad = texture2DRect(lightMap, ref2d).r;
+		vec3 refn = normalize(texture2DRect(normalMap, ref2d).rgb * 2.0 - 1.0);
+		// figure out how appropriate our guess actually was
+		float refapprop = max(0.0, dot(-refnorm, normalize(pos - refpos)));
+		// darken reflections from points which face away from the reflected ray - our guess was a back-face
+		//refapprop *= step(dot(refnorm, refn), 0.0);
+		refapprop = min(refapprop, max(0.0, -dot(refnorm, refn))); // more conservative variant
+		// get appropriate light strength for guess-point
+		float reflit = min(max(dot(refn, lightnorm.xyz), 0.0), refshad);
+		// apply sun color to guess-point, dampen according to inappropriateness of guess
+		vec3 refprod = (vary_SunlitColor*reflit) * refcol.rgb * refapprop;
+		vec3 ssshiny = (refprod * spec.a);
+
+		// add the two types of shiny together
+		col += (ssshiny + dumbshiny) * spec.rgb;
 	}
 	
 	col = atmosLighting(col);
diff --git a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
index 1c5234c4502514cc941a91e8821647c082195d7f..f129a1517b3eb8437353f4b24723ee530e56e791 100644
--- a/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
+++ b/indra/newview/app_settings/shaders/class3/lighting/sumLightsV.glsl
@@ -6,7 +6,7 @@
  */
 
 float calcDirectionalLight(vec3 n, vec3 l);
-float calcPointLight(vec3 v, vec3 n, vec4 lp, float la);
+float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float is_pointlight);
 
 vec3 atmosAmbient(vec3 light);
 vec3 atmosAffectDirectionalLight(float lightIntensity);
@@ -15,24 +15,21 @@ vec3 scaleUpLight(vec3 light);
 
 vec4 sumLights(vec3 pos, vec3 norm, vec4 color, vec4 baseLight)
 {
-	vec4 col;
-	col.a = color.a;
+	vec4 col = vec4(0.0, 0.0, 0.0, color.a);
 	
-	// Add windlight lights
-	col.rgb = atmosAffectDirectionalLight(calcDirectionalLight(norm, gl_LightSource[0].position.xyz));
-	col.rgb += atmosAmbient(baseLight.rgb);
-	col.rgb = scaleUpLight(col.rgb);
-
 	// Collect normal lights (need to be divided by two, as we later multiply by 2)
-	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[2].position, gl_LightSource[2].linearAttenuation);
-	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[3].position, gl_LightSource[3].linearAttenuation);
-	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[4].position, gl_LightSource[4].linearAttenuation);
-	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[5].position, gl_LightSource[5].linearAttenuation);
- 	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[6].position, gl_LightSource[6].linearAttenuation);
- 	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLight(pos, norm, gl_LightSource[7].position, gl_LightSource[7].linearAttenuation);
+	col.rgb += gl_LightSource[2].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[2].position, gl_LightSource[2].spotDirection.xyz, gl_LightSource[2].linearAttenuation, gl_LightSource[2].specular.a);
+	col.rgb += gl_LightSource[3].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[3].position, gl_LightSource[3].spotDirection.xyz, gl_LightSource[3].linearAttenuation, gl_LightSource[3].specular.a);
+	col.rgb += gl_LightSource[4].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[4].position, gl_LightSource[4].spotDirection.xyz, gl_LightSource[4].linearAttenuation, gl_LightSource[4].specular.a);
+	col.rgb += gl_LightSource[5].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[5].position, gl_LightSource[5].spotDirection.xyz, gl_LightSource[5].linearAttenuation, gl_LightSource[5].specular.a);
+	col.rgb += gl_LightSource[6].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[6].position, gl_LightSource[6].spotDirection.xyz, gl_LightSource[6].linearAttenuation, gl_LightSource[6].specular.a);
+	col.rgb += gl_LightSource[7].diffuse.rgb*calcPointLightOrSpotLight(pos.xyz, norm, gl_LightSource[7].position, gl_LightSource[7].spotDirection.xyz, gl_LightSource[7].linearAttenuation, gl_LightSource[7].specular.a);
 	col.rgb += gl_LightSource[1].diffuse.rgb*calcDirectionalLight(norm, gl_LightSource[1].position.xyz);
 	col.rgb = scaleDownLight(col.rgb);
-				
+
+	// Add windlight lights
+	col.rgb += atmosAffectDirectionalLight(calcDirectionalLight(norm, gl_LightSource[0].position.xyz));
+	col.rgb += atmosAmbient(baseLight.rgb);
 
 	col.rgb = min(col.rgb*color.rgb, 1.0);
 	
diff --git a/indra/newview/app_settings/ultra_graphics.xml b/indra/newview/app_settings/ultra_graphics.xml
index f16ec6c30f20cdf668cf2f8cdc5f46b230eb08cd..f741089ca2b6098ad6068a1b621182a3a4b46d63 100644
--- a/indra/newview/app_settings/ultra_graphics.xml
+++ b/indra/newview/app_settings/ultra_graphics.xml
@@ -12,14 +12,12 @@
 	<RenderFlexTimeFactor value="1"/>
 	<!--256... but they don't use this-->
 	<RenderGlowResolutionPow value="9"/>
-	<!--Sun/Moon only-->
-	<RenderLightingDetail value="1"/>
 	<!--Low number-->
 	<RenderMaxPartCount value="4096"/>
 	<!--bump okay-->
 	<RenderObjectBump value="TRUE"/>
 	<!--NO SHADERS-->
-	<RenderReflectionDetail value="3"/>
+	<RenderReflectionDetail value="4"/>
 	<!--Simple-->
 	<RenderTerrainDetail value="1"/>
 	<!--Default for now-->
@@ -31,9 +29,14 @@
 	<!--Default for now-->
 	<RenderVolumeLODFactor value="2.0"/>
 	<!--NO SHADERS-->
-	<RenderWaterReflections value="TRUE"/>
-	<!--NO SHADERS-->
 	<VertexShaderEnable value="TRUE"/>
 	<!--NO SHADERS-->
 	<WindLightUseAtmosShaders value="TRUE"/>
+  <!--Deferred Shading-->
+  <RenderDeferred value="TRUE"/>
+  <!--SSAO Enabled-->
+  <RenderDeferredSSAO value="TRUE"/>
+  <!--Full Shadows-->
+  <RenderShadowDetail value="2"/>
+
 </settings>
diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt
index 4029bf95a0d0f04bbaf7babb7571a7b4a2e6b10d..1913f52499becd96f45cc8fc63c003a7def0247e 100644
--- a/indra/newview/featuretable.txt
+++ b/indra/newview/featuretable.txt
@@ -23,7 +23,7 @@ version 21
 // NOTE: All settings are set to the MIN of applied values, including 'all'!
 //
 list all
-RenderAnisotropic			1	0
+RenderAnisotropic			1	1
 RenderAvatarCloth			1	1
 RenderAvatarLODFactor		1	1.0
 RenderAvatarVP				1	1
@@ -35,18 +35,16 @@ RenderFogRatio				1	4.0
 RenderGamma					1	0
 RenderGlowResolutionPow		1	9
 RenderGround				1	1
-RenderLightingDetail		1	1
 RenderMaxPartCount			1	8192
 RenderNightBrightness		1	1.0
 RenderObjectBump			1	1
-RenderReflectionDetail		1	3
+RenderReflectionDetail		1	4
 RenderTerrainDetail			1	1
 RenderTerrainLODFactor		1	2.0
 RenderTreeLODFactor			1	1.0
 RenderUseImpostors			1	1
 RenderVBOEnable				1	1
 RenderVolumeLODFactor		1	2.0
-RenderWaterReflections		1	1
 UseStartScreen				1	1
 UseOcclusion				1	1
 VertexShaderEnable			1	1
@@ -56,6 +54,9 @@ Disregard128DefaultDrawDistance	1	1
 Disregard96DefaultDrawDistance	1	1
 RenderTextureMemoryMultiple		1	1.0
 RenderShaderLightingMaxLevel	1	3
+RenderDeferred				1	1
+RenderDeferredSSAO			1	1
+RenderShadowDetail			1	2
 
 
 //
@@ -69,7 +70,6 @@ RenderAvatarVP				1	0
 RenderFarClip				1	64
 RenderFlexTimeFactor		1	0.5
 RenderGlowResolutionPow		1	8
-RenderLightingDetail		1	0
 RenderMaxPartCount			1	1024
 RenderObjectBump			1	0
 RenderReflectionDetail		1	0
@@ -78,10 +78,13 @@ RenderTerrainLODFactor		1	1
 RenderTreeLODFactor			1	0.5
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	1.125
-RenderWaterReflections		1	0
 VertexShaderEnable			1	0
 WindLightUseAtmosShaders	1	0
 WLSkyDetail					1	48
+RenderDeferred				1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
 
 //
 // Mid Graphics Settings
@@ -94,7 +97,6 @@ RenderAvatarVP				1	1
 RenderFarClip				1	96
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	8
-RenderLightingDetail		1	1
 RenderMaxPartCount			1	2048
 RenderObjectBump			1	1
 RenderReflectionDetail		1	0
@@ -103,10 +105,13 @@ RenderTerrainLODFactor		1	1.0
 RenderTreeLODFactor			1	0.5
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	1.125
-RenderWaterReflections		1	0
 VertexShaderEnable			1	1
 WindLightUseAtmosShaders	1	0
 WLSkyDetail					1	48
+RenderDeferred				1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
 
 //
 // High Graphics Settings (purty)
@@ -119,7 +124,6 @@ RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
-RenderLightingDetail		1	1
 RenderMaxPartCount			1	4096
 RenderObjectBump			1	1
 RenderReflectionDetail		1	2
@@ -128,10 +132,13 @@ RenderTerrainLODFactor		1	2.0
 RenderTreeLODFactor			1	0.5
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	1.125
-RenderWaterReflections		1	0
 VertexShaderEnable			1	1
 WindLightUseAtmosShaders	1	1
 WLSkyDetail					1	48
+RenderDeferred				1	1
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	1
+
 
 //
 // Ultra graphics (REALLY PURTY!)
@@ -144,19 +151,21 @@ RenderAvatarVP				1	1
 RenderFarClip				1	256
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
-RenderLightingDetail		1	1
 RenderMaxPartCount			1	8192
 RenderObjectBump			1	1
-RenderReflectionDetail		1	3
+RenderReflectionDetail		1	4
 RenderTerrainDetail			1	1
 RenderTerrainLODFactor		1	2.0
 RenderTreeLODFactor			1	1.0
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	2.0
-RenderWaterReflections		1	1
 VertexShaderEnable			1	1
 WindLightUseAtmosShaders	1	1
 WLSkyDetail					1	128
+RenderDeferred				1	1
+RenderDeferredSSAO			1	1
+RenderShadowDetail			1	2
+
 
 //
 // Class Unknown Hardware (unknown)
@@ -194,9 +203,12 @@ RenderVBOEnable				1	1
 list NoPixelShaders
 RenderAvatarVP				0	0
 RenderAvatarCloth			0	0
-RenderWaterReflections		0	0
+RenderReflectionDetail		0	0
 VertexShaderEnable			0	0
 WindLightUseAtmosShaders	0	0
+RenderDeferred				0	0
+RenderDeferredSSAO			0	0
+RenderShadowDetail			0	0
 
 //
 // No Vertex Shaders available
@@ -204,9 +216,13 @@ WindLightUseAtmosShaders	0	0
 list NoVertexShaders
 RenderAvatarVP				0	0
 RenderAvatarCloth			0	0
-RenderWaterReflections		0	0
+RenderReflectionDetail		0	0
 VertexShaderEnable			0	0
 WindLightUseAtmosShaders	0	0
+RenderDeferred				0	0
+RenderDeferredSSAO			0	0
+RenderShadowDetail			0	0
+
 
 // "Default" setups for safe, low, medium, high
 //
@@ -214,14 +230,17 @@ list safe
 RenderAnisotropic			1	0
 RenderAvatarCloth			0	0
 RenderAvatarVP				0	0
-RenderLightingDetail		1	0
 RenderObjectBump			0	0
 RenderMaxPartCount			1	1024
 RenderTerrainDetail 		1	0
 RenderUseImpostors			0	0
 RenderVBOEnable				1	0
-RenderWaterReflections		0	0
+RenderReflectionDetail		0	0
 WindLightUseAtmosShaders	0	0
+RenderDeferred				0	0
+RenderDeferredSSAO			0	0
+RenderShadowDetail			0	0
+
 
 //
 // CPU based feature masks
@@ -245,11 +264,9 @@ RenderVBOEnable				1	0
 
 list Intel
 RenderAnisotropic			1	0
-RenderLightingDetail		1	0
 
 list GeForce2
 RenderAnisotropic			1	0
-RenderLightingDetail		1	0
 RenderMaxPartCount			1	2048
 RenderTerrainDetail			1	0
 RenderVBOEnable				1	1
diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt
index 61a8e51c50e5d04e71e5b6eb6deae5ab3ffc3427..254b9c4ce4fed76e6c7fff3e7883c96784a29ff6 100644
--- a/indra/newview/featuretable_linux.txt
+++ b/indra/newview/featuretable_linux.txt
@@ -23,7 +23,7 @@ version 21
 // NOTE: All settings are set to the MIN of applied values, including 'all'!
 //
 list all
-RenderAnisotropic			1	0
+RenderAnisotropic			1	1
 RenderAvatarCloth			1	1
 RenderAvatarLODFactor		1	1.0
 RenderAvatarVP				1	1
@@ -35,18 +35,16 @@ RenderFogRatio				1	4.0
 RenderGamma					1	0
 RenderGlowResolutionPow		1	9
 RenderGround				1	1
-RenderLightingDetail		1	1
 RenderMaxPartCount			1	8192
 RenderNightBrightness		1	1.0
 RenderObjectBump			1	1
-RenderReflectionDetail		1	3
+RenderReflectionDetail		1	4
 RenderTerrainDetail			1	1
 RenderTerrainLODFactor		1	2.0
 RenderTreeLODFactor			1	1.0
 RenderUseImpostors			1	1
 RenderVBOEnable				1	1
 RenderVolumeLODFactor		1	2.0
-RenderWaterReflections		1	1
 UseStartScreen				1	1
 UseOcclusion				1	1
 VertexShaderEnable			1	1
@@ -55,6 +53,10 @@ WLSkyDetail					1	128
 Disregard128DefaultDrawDistance	1	1
 Disregard96DefaultDrawDistance	1	1
 RenderTextureMemoryMultiple		1	1.0
+RenderShaderLightingMaxLevel		1	3
+RenderDeferred				1	1
+RenderDeferredSSAO			1	1
+RenderShadowDetail			1	2
 
 //
 // Low Graphics Settings
@@ -67,7 +69,6 @@ RenderAvatarVP				1	0
 RenderFarClip				1	64
 RenderFlexTimeFactor		1	0.5
 RenderGlowResolutionPow		1	8
-RenderLightingDetail		1	0
 RenderMaxPartCount			1	1024
 RenderObjectBump			1	0
 RenderReflectionDetail		1	0
@@ -76,10 +77,13 @@ RenderTerrainLODFactor		1	1
 RenderTreeLODFactor			1	0.5
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	1.125
-RenderWaterReflections		1	0
 VertexShaderEnable			1	0
 WindLightUseAtmosShaders	1	0
 WLSkyDetail					1	48
+RenderDeferred				1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
 
 //
 // Mid Graphics Settings
@@ -92,7 +96,6 @@ RenderAvatarVP				1	1
 RenderFarClip				1	96
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	8
-RenderLightingDetail		1	1
 RenderMaxPartCount			1	2048
 RenderObjectBump			1	1
 RenderReflectionDetail		1	0
@@ -101,10 +104,13 @@ RenderTerrainLODFactor		1	1.0
 RenderTreeLODFactor			1	0.5
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	1.125
-RenderWaterReflections		1	0
 VertexShaderEnable			1	1
 WindLightUseAtmosShaders	1	0
 WLSkyDetail					1	48
+RenderDeferred				1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
 
 //
 // High Graphics Settings (purty)
@@ -117,7 +123,6 @@ RenderAvatarVP				1	1
 RenderFarClip				1	128
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
-RenderLightingDetail		1	1
 RenderMaxPartCount			1	4096
 RenderObjectBump			1	1
 RenderReflectionDetail		1	2
@@ -126,10 +131,13 @@ RenderTerrainLODFactor		1	2.0
 RenderTreeLODFactor			1	0.5
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	1.125
-RenderWaterReflections		1	0
 VertexShaderEnable			1	1
 WindLightUseAtmosShaders	1	1
 WLSkyDetail					1	48
+RenderDeferred				1	1
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	1
+
 
 //
 // Ultra graphics (REALLY PURTY!)
@@ -142,19 +150,21 @@ RenderAvatarVP				1	1
 RenderFarClip				1	256
 RenderFlexTimeFactor		1	1.0
 RenderGlowResolutionPow		1	9
-RenderLightingDetail		1	1
 RenderMaxPartCount			1	8192
 RenderObjectBump			1	1
-RenderReflectionDetail		1	3
+RenderReflectionDetail		1	4
 RenderTerrainDetail			1	1
 RenderTerrainLODFactor		1	2.0
 RenderTreeLODFactor			1	1.0
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	2.0
-RenderWaterReflections		1	1
 VertexShaderEnable			1	1
 WindLightUseAtmosShaders	1	1
 WLSkyDetail					1	128
+RenderDeferred				1	1
+RenderDeferredSSAO			1	1
+RenderShadowDetail			1	2
+
 
 //
 // Class Unknown Hardware (unknown)
@@ -192,9 +202,12 @@ RenderVBOEnable				1	1
 list NoPixelShaders
 RenderAvatarVP				0	0
 RenderAvatarCloth			0	0
-RenderWaterReflections		0	0
+RenderReflectionDetail		0	0
 VertexShaderEnable			0	0
 WindLightUseAtmosShaders	0	0
+RenderDeferred				0	0
+RenderDeferredSSAO			0	0
+RenderShadowDetail			0	0
 
 //
 // No Vertex Shaders available
@@ -202,9 +215,13 @@ WindLightUseAtmosShaders	0	0
 list NoVertexShaders
 RenderAvatarVP				0	0
 RenderAvatarCloth			0	0
-RenderWaterReflections		0	0
+RenderReflectionDetail		0	0
 VertexShaderEnable			0	0
 WindLightUseAtmosShaders	0	0
+RenderDeferred				0	0
+RenderDeferredSSAO			0	0
+RenderShadowDetail			0	0
+
 
 // "Default" setups for safe, low, medium, high
 //
@@ -212,14 +229,17 @@ list safe
 RenderAnisotropic			1	0
 RenderAvatarCloth			0	0
 RenderAvatarVP				0	0
-RenderLightingDetail		1	0
 RenderObjectBump			0	0
 RenderMaxPartCount			1	1024
 RenderTerrainDetail 		1	0
 RenderUseImpostors			0	0
 RenderVBOEnable				1	0
-RenderWaterReflections		0	0
+RenderReflectionDetail		0	0
 WindLightUseAtmosShaders	0	0
+RenderDeferred				0	0
+RenderDeferredSSAO			0	0
+RenderShadowDetail			0	0
+
 
 //
 // CPU based feature masks
@@ -243,13 +263,11 @@ RenderVBOEnable				1	0
 
 list Intel
 RenderAnisotropic			1	0
-RenderLightingDetail		1	0
 // Avoid some Intel crashes on Linux
 RenderCubeMap				0	0
 
 list GeForce2
 RenderAnisotropic			1	0
-RenderLightingDetail		1	0
 RenderMaxPartCount			1	2048
 RenderTerrainDetail			1	0
 RenderVBOEnable				1	1
@@ -461,17 +479,47 @@ list NVIDIA_GeForce_Go_6
 RenderVBOEnable				1	0
 Disregard128DefaultDrawDistance	1	0
 
+list NVIDIA_GeForce_7000
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7100
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_7200
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_7300
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_7400
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7500
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7600
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7700
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7800
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_7900
+RenderShaderLightingMaxLevel	1	2
 
 list NVIDIA_GeForce_Go_7200
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_Go_7300
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7300_LE
+RenderShaderLightingMaxLevel	1	2
 list NVIDIA_GeForce_Go_7400
 Disregard128DefaultDrawDistance	1	0
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7600
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7700
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7800
+RenderShaderLightingMaxLevel	1	2
+list NVIDIA_GeForce_Go_7900
+RenderShaderLightingMaxLevel	1	2
 
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 12d47a904c0def93caca1ffb0042fb7b25e63914..db0252d2e70008fd6df65120d890483880f4a850 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -366,6 +366,7 @@ list ATI_Radeon_X1500
 Disregard128DefaultDrawDistance	1	0
 list ATI_Radeon_X1600 
 Disregard128DefaultDrawDistance	1	0
+RenderUseFBO 					0	0
 list ATI_Radeon_X1700 
 Disregard128DefaultDrawDistance	1	0
 list ATI_Mobility_Radeon_X1xxx
diff --git a/indra/newview/licenses-win32.txt b/indra/newview/licenses-win32.txt
index 7e6d4b4561ce44100f2a395517ccf3964e85acf2..8736626907409eb21518ba10793faa2793cbef3a 100644
--- a/indra/newview/licenses-win32.txt
+++ b/indra/newview/licenses-win32.txt
@@ -769,3 +769,72 @@ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+=============
+GLOD license
+=============
+The GLOD Open-Source License   Version 1.0                June 16, 2004
+
+Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns 
+Hopkins University and David Luebke, Brenden Schubert, University of 
+Virginia. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, is permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer and
+   request.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer and
+   request in the documentation and/or other materials provided with
+   the distribution.
+
+3. The name "GLOD" must not be used to endorse or promote products
+   derived from this software without prior written permission.
+
+4. Redistributions of any modified version of this source, whether in
+   source or binary form , must include a form of the following
+   acknowledgment: "This product is derived from the GLOD library,
+   which is available from http://www.cs.jhu.edu/~graphics/GLOD."
+
+5. Redistributions of any modified version of this source in binary
+   form must provide, free of charge, access to the modified version
+   of the code.
+
+6. This license shall be governed by and construed and enforced in
+   accordance with the laws of the State of Maryland, without
+   reference to its conflicts of law provisions. The exclusive
+   jurisdiction and venue for all legal actions relating to this
+   license shall be in courts of competent subject matter jurisdiction
+   located in the State of Maryland.
+
+TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED
+UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
+THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH
+YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY
+CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS
+AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
+SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF
+PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS.
+
+YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE
+COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS,
+DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM
+YOUR ACCEPTANCE AND USE OF GLOD.
+
+Although NOT REQUIRED, we would appreciate it if active users of GLOD
+put a link on their web site to the GLOD web site when possible.
+
+
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 43c8c679c69c6ba3c2074d2198d5c5b4f931d834..34e9497ed8fb37c2552d7ff2f93f014af837159d 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -49,6 +49,7 @@
 #include "llwindow.h"
 #include "llviewerstats.h"
 #include "llmd5.h"
+#include "llmeshrepository.h"
 #include "llpumpio.h"
 #include "llmimetypes.h"
 #include "llslurl.h"
@@ -78,6 +79,7 @@
 #include "llteleporthistory.h"
 #include "lllocationhistory.h"
 #include "llfasttimerview.h"
+#include "llviewermenufile.h"
 #include "llvoicechannel.h"
 #include "llvoavatarself.h"
 #include "llsidetray.h"
@@ -922,6 +924,9 @@ static LLFastTimer::DeclareTimer FTM_LFS("LFS Thread");
 static LLFastTimer::DeclareTimer FTM_PAUSE_THREADS("Pause Threads");
 static LLFastTimer::DeclareTimer FTM_IDLE("Idle");
 static LLFastTimer::DeclareTimer FTM_PUMP("Pump");
+static LLFastTimer::DeclareTimer FTM_PUMP_ARES("Ares");
+static LLFastTimer::DeclareTimer FTM_PUMP_SERVICE("Service");
+static LLFastTimer::DeclareTimer FTM_SERVICE_CALLBACK("Callback");
 
 bool LLAppViewer::mainLoop()
 {
@@ -1033,10 +1038,20 @@ bool LLAppViewer::mainLoop()
 						LLMemType mt_ip(LLMemType::MTYPE_IDLE_PUMP);
 						pingMainloopTimeout("Main:ServicePump");				
 						LLFastTimer t4(FTM_PUMP);
-						gAres->process();
-						// this pump is necessary to make the login screen show up
-						gServicePump->pump();
-						gServicePump->callback();
+						{
+							LLFastTimer t(FTM_PUMP_ARES);
+							gAres->process();
+						}
+						{
+							LLFastTimer t(FTM_PUMP_SERVICE);
+							// this pump is necessary to make the login screen show up
+							gServicePump->pump();
+
+							{
+								LLFastTimer t(FTM_SERVICE_CALLBACK);
+								gServicePump->callback();
+							}
+						}
 					}
 					
 					resumeMainloopTimeout();
@@ -1287,6 +1302,9 @@ bool LLAppViewer::cleanup()
 
 	llinfos << "Cleaning Up" << llendflush;
 
+	// shut down mesh streamer
+	gMeshRepo.shutdown();
+
 	// Must clean up texture references before viewer window is destroyed.
 	LLHUDManager::getInstance()->updateEffects();
 	LLHUDObject::updateAll();
@@ -1565,6 +1583,8 @@ bool LLAppViewer::cleanup()
 	sTextureFetch->shutDownTextureCacheThread() ;
 	sTextureFetch->shutDownImageDecodeThread() ;
 
+	LLFilePickerThread::cleanupClass();
+
 	delete sTextureCache;
     sTextureCache = NULL;
 	delete sTextureFetch;
@@ -1712,6 +1732,11 @@ bool LLAppViewer::initThreads()
 		mFastTimerLogThread->start();
 	}
 
+	// Mesh streaming and caching
+	gMeshRepo.init();
+
+	LLFilePickerThread::initClass();
+
 	// *FIX: no error handling here!
 	return true;
 }
@@ -2425,6 +2450,7 @@ bool LLAppViewer::initWindow()
 		gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
 	
 		gPipeline.init();
+		
 		stop_glerror();
 		gViewerWindow->initGLDefaults();
 
@@ -3410,6 +3436,10 @@ static LLFastTimer::DeclareTimer FTM_OBJECTLIST_UPDATE("Update Objectlist");
 static LLFastTimer::DeclareTimer FTM_REGION_UPDATE("Update Region");
 static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World");
 static LLFastTimer::DeclareTimer FTM_NETWORK("Network");
+static LLFastTimer::DeclareTimer FTM_AGENT_NETWORK("Agent Network");
+static LLFastTimer::DeclareTimer FTM_AGENT_AUTOPILOT("Autopilot");
+static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE("Update");
+static LLFastTimer::DeclareTimer FTM_VLMANAGER("VL Manager");
 
 ///////////////////////////////////////////////////////
 // idle()
@@ -3430,6 +3460,8 @@ void LLAppViewer::idle()
 	LLEventTimer::updateClass();
 	LLCriticalDamp::updateInterpolants();
 	LLMortician::updateClass();
+	LLFilePickerThread::clearDead();  //calls LLFilePickerThread::notify()
+
 	F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
 
 	// Cap out-of-control frame times
@@ -3480,7 +3512,7 @@ void LLAppViewer::idle()
 
 	if (!gDisconnected)
 	{
-		LLFastTimer t(FTM_NETWORK);
+		LLFastTimer t(FTM_AGENT_NETWORK);
 		// Update spaceserver timeinfo
 	    LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC));
     
@@ -3495,9 +3527,12 @@ void LLAppViewer::idle()
 			gAgent.moveYaw(-1.f);
 		}
 
-	    // Handle automatic walking towards points
-	    gAgentPilot.updateTarget();
-	    gAgent.autoPilot(&yaw);
+		{
+			LLFastTimer t(FTM_AGENT_AUTOPILOT);
+			// Handle automatic walking towards points
+			gAgentPilot.updateTarget();
+			gAgent.autoPilot(&yaw);
+		}
     
 	    static LLFrameTimer agent_update_timer;
 	    static U32 				last_control_flags;
@@ -3508,6 +3543,7 @@ void LLAppViewer::idle()
 		    
 	    if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
 	    {
+			LLFastTimer t(FTM_AGENT_UPDATE);
 		    // Send avatar and camera info
 		    last_control_flags = gAgent.getControlFlags();
 		    send_agent_update(TRUE);
@@ -3673,7 +3709,7 @@ void LLAppViewer::idle()
 	//
 
 	{
-		LLFastTimer t(FTM_NETWORK);
+		LLFastTimer t(FTM_VLMANAGER);
 		gVLManager.unpackData();
 	}
 	
@@ -3919,6 +3955,11 @@ static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
 #endif
 
 static LLFastTimer::DeclareTimer FTM_IDLE_NETWORK("Idle Network");
+static LLFastTimer::DeclareTimer FTM_MESSAGE_ACKS("Message Acks");
+static LLFastTimer::DeclareTimer FTM_RETRANSMIT("Retransmit");
+static LLFastTimer::DeclareTimer FTM_TIMEOUT_CHECK("Timeout Check");
+static LLFastTimer::DeclareTimer FTM_DYNAMIC_THROTTLE("Dynamic Throttle");
+static LLFastTimer::DeclareTimer FTM_CHECK_REGION_CIRCUIT("Check Region Circuit");
 
 void LLAppViewer::idleNetwork()
 {
@@ -3972,7 +4013,10 @@ void LLAppViewer::idleNetwork()
 		}
 
 		// Handle per-frame message system processing.
-		gMessageSystem->processAcks();
+		{
+			LLFastTimer ftm(FTM_MESSAGE_ACKS);
+			gMessageSystem->processAcks();
+		}
 
 #ifdef TIME_THROTTLE_MESSAGES
 		if (total_time >= CheckMessagesMaxTime)
@@ -4010,26 +4054,41 @@ void LLAppViewer::idleNetwork()
 	LLViewerStats::getInstance()->mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects);
 
 	// Retransmit unacknowledged packets.
-	gXferManager->retransmitUnackedPackets();
-	gAssetStorage->checkForTimeouts();
+	{
+		LLFastTimer ftm(FTM_RETRANSMIT);
+		gXferManager->retransmitUnackedPackets();
+	}
+
+	{
+		LLFastTimer ftm(FTM_TIMEOUT_CHECK);
+		gAssetStorage->checkForTimeouts();
+	}
+
 	llpushcallstacks ;
-	gViewerThrottle.updateDynamicThrottle();
+
+	{
+		LLFastTimer ftm(FTM_DYNAMIC_THROTTLE);
+		gViewerThrottle.updateDynamicThrottle();
+	}
 
 	llpushcallstacks ;
 	// Check that the circuit between the viewer and the agent's current
 	// region is still alive
-	LLViewerRegion *agent_region = gAgent.getRegion();
-	if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED))
 	{
-		LLUUID this_region_id = agent_region->getRegionID();
-		bool this_region_alive = agent_region->isAlive();
-		if ((mAgentRegionLastAlive && !this_region_alive) // newly dead
-		    && (mAgentRegionLastID == this_region_id)) // same region
+		LLFastTimer ftm(FTM_CHECK_REGION_CIRCUIT);
+		LLViewerRegion *agent_region = gAgent.getRegion();
+		if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED))
 		{
-			forceDisconnect(LLTrans::getString("AgentLostConnection"));
+			LLUUID this_region_id = agent_region->getRegionID();
+			bool this_region_alive = agent_region->isAlive();
+			if ((mAgentRegionLastAlive && !this_region_alive) // newly dead
+				&& (mAgentRegionLastID == this_region_id)) // same region
+			{
+				forceDisconnect(LLTrans::getString("AgentLostConnection"));
+			}
+			mAgentRegionLastID = this_region_id;
+			mAgentRegionLastAlive = this_region_alive;
 		}
-		mAgentRegionLastID = this_region_id;
-		mAgentRegionLastAlive = this_region_alive;
 	}
 	llpushcallstacks ;
 }
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index 370ecc06656ff07e82ade5ded8e2289845bef367..c14d2348909283fc5ae4799fa231ccf60e34b5e6 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -41,6 +41,7 @@
 #include "llfilepicker.h"
 #include "llinventoryobserver.h"
 #include "llinventorypanel.h"
+#include "llfloaterimportcollada.h"
 #include "llpermissionsflags.h"
 #include "llpreviewnotecard.h"
 #include "llpreviewscript.h"
@@ -65,6 +66,7 @@
 #include "llnotificationsutil.h"
 #include "llscrolllistctrl.h"
 #include "llsdserialize.h"
+#include "llsdutil.h"
 #include "llvfs.h"
 
 // When uploading multiple files, don't display any of them when uploading more than this number.
@@ -72,6 +74,106 @@ static const S32 FILE_COUNT_DISPLAY_THRESHOLD = 5;
 
 void dialog_refresh_all();
 
+void on_new_single_inventory_upload_complete(
+	LLAssetType::EType asset_type,
+	LLInventoryType::EType inventory_type,
+	const std::string inventory_type_string,
+	const LLUUID& item_folder_id,
+	const std::string& item_name,
+	const std::string& item_description,
+	const LLSD& server_response,
+	S32 upload_price)
+{
+	if ( upload_price > 0 )
+	{
+		// this upload costed us L$, update our balance
+		// and display something saying that it cost L$
+		LLStatusBar::sendMoneyBalanceRequest();
+
+		LLSD args;
+		args["AMOUNT"] = llformat("%d", upload_price);
+		LLNotificationsUtil::add("UploadPayment", args);
+	}
+
+	if( item_folder_id.notNull() )
+	{
+		U32 everyone_perms = PERM_NONE;
+		U32 group_perms = PERM_NONE;
+		U32 next_owner_perms = PERM_ALL;
+		if( server_response.has("new_next_owner_mask") )
+		{
+			// The server provided creation perms so use them.
+			// Do not assume we got the perms we asked for in
+			// since the server may not have granted them all.
+			everyone_perms = server_response["new_everyone_mask"].asInteger();
+			group_perms = server_response["new_group_mask"].asInteger();
+			next_owner_perms = server_response["new_next_owner_mask"].asInteger();
+		}
+		else 
+		{
+			// The server doesn't provide creation perms
+			// so use old assumption-based perms.
+			if( inventory_type_string != "snapshot")
+			{
+				next_owner_perms = PERM_MOVE | PERM_TRANSFER;
+			}
+		}
+
+		LLPermissions new_perms;
+		new_perms.init(
+			gAgent.getID(),
+			gAgent.getID(),
+			LLUUID::null,
+			LLUUID::null);
+
+		new_perms.initMasks(
+			PERM_ALL,
+			PERM_ALL,
+			everyone_perms,
+			group_perms,
+			next_owner_perms);
+
+		S32 creation_date_now = time_corrected();
+		LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
+			server_response["new_inventory_item"].asUUID(),
+			item_folder_id,
+			new_perms,
+			server_response["new_asset"].asUUID(),
+			asset_type,
+			inventory_type,
+			item_name,
+			item_description,
+			LLSaleInfo::DEFAULT,
+			LLInventoryItem::II_FLAGS_NONE,
+			creation_date_now);
+
+		gInventory.updateItem(item);
+		gInventory.notifyObservers();
+
+		// Show the preview panel for textures and sounds to let
+		// user know that the image (or snapshot) arrived intact.
+		LLInventoryPanel* panel = LLInventoryPanel::getActiveInventoryPanel();
+		if ( panel )
+		{
+			LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
+
+			panel->setSelection(
+				server_response["new_inventory_item"].asUUID(),
+				TAKE_FOCUS_NO);
+
+			// restore keyboard focus
+			gFocusMgr.setKeyboardFocus(focus);
+		}
+	}
+	else
+	{
+		llwarns << "Can't find a folder to put it in" << llendl;
+	}
+
+	// remove the "Uploading..." message
+	LLUploadDialog::modalUploadFinished();	
+}
+
 LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
 											   const LLUUID& vfile_id,
 											   LLAssetType::EType asset_type)
@@ -89,9 +191,10 @@ LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
 	}
 }
 
-LLAssetUploadResponder::LLAssetUploadResponder(const LLSD &post_data,
-											   const std::string& file_name, 
-											   LLAssetType::EType asset_type)
+LLAssetUploadResponder::LLAssetUploadResponder(
+	const LLSD &post_data,
+	const std::string& file_name, 
+	LLAssetType::EType asset_type)
 	: LLHTTPClient::Responder(),
 	  mPostData(post_data),
 	  mFileName(file_name),
@@ -139,6 +242,7 @@ void LLAssetUploadResponder::result(const LLSD& content)
 	lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl;
 
 	std::string state = content["state"];
+
 	if (state == "upload")
 	{
 		uploadUpload(content);
@@ -200,22 +304,36 @@ void LLAssetUploadResponder::uploadComplete(const LLSD& content)
 {
 }
 
-LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data,
-														   const LLUUID& vfile_id,
-														   LLAssetType::EType asset_type,
-														   boost::function<void(const LLUUID& uuid)> callback)
-: LLAssetUploadResponder(post_data, vfile_id, asset_type),
-  mCallback(callback)
+LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
+	const LLSD& post_data,
+	const LLUUID& vfile_id,
+	LLAssetType::EType asset_type)
+	: LLAssetUploadResponder(post_data, vfile_id, asset_type)
 {
 }
 
-LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(const LLSD& post_data, 
-														   const std::string& file_name, 
-														   LLAssetType::EType asset_type, 
-														   boost::function<void(const LLUUID& uuid)> callback)
-: LLAssetUploadResponder(post_data, file_name, asset_type),
-  mCallback(callback)
+LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
+	const LLSD& post_data,
+	const std::string& file_name,
+	LLAssetType::EType asset_type)
+	: LLAssetUploadResponder(post_data, file_name, asset_type)
+{
+}
+
+// virtual
+void LLNewAgentInventoryResponder::error(U32 statusNum, const std::string& reason)
 {
+	LLAssetUploadResponder::error(statusNum, reason);
+	LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, LLUUID(), FALSE);
+}
+
+
+//virtual 
+void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content)
+{
+	LLAssetUploadResponder::uploadFailure(content);
+
+	LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE);
 }
 
 //virtual 
@@ -229,101 +347,31 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
 
 	LLAssetType::EType asset_type = LLAssetType::lookup(mPostData["asset_type"].asString());
 	LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString());
-	S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+	S32 expected_upload_cost = 0;
 
 	// Update L$ and ownership credit information
 	// since it probably changed on the server
 	if (asset_type == LLAssetType::AT_TEXTURE ||
 		asset_type == LLAssetType::AT_SOUND ||
-		asset_type == LLAssetType::AT_ANIMATION)
+		asset_type == LLAssetType::AT_ANIMATION ||
+		asset_type == LLAssetType::AT_MESH)
 	{
-		LLStatusBar::sendMoneyBalanceRequest();
-
-		LLSD args;
-		args["AMOUNT"] = llformat("%d", expected_upload_cost);
-		LLNotificationsUtil::add("UploadPayment", args);
+		expected_upload_cost = 
+			LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
 	}
 
-	// Actually add the upload to viewer inventory
-	llinfos << "Adding " << content["new_inventory_item"].asUUID() << " "
-			<< content["new_asset"].asUUID() << " to inventory." << llendl;
-	if(mPostData["folder_id"].asUUID().notNull())
-	{
-		//std::ostringstream out;
-		//LLSDXMLFormatter *formatter = new LLSDXMLFormatter;
-		//formatter->format(mPostData, out, LLSDFormatter::OPTIONS_PRETTY);
-		//llinfos << "Post Data: " << out.str() << llendl;
-
-		U32 everyone_perms = PERM_NONE;
-		U32 group_perms = PERM_NONE;
-		U32 next_owner_perms = PERM_ALL;
-		if(content.has("new_next_owner_mask"))
-		{
-			// This is a new sim that provides creation perms so use them.
-			// Do not assume we got the perms we asked for in mPostData 
-			// since the sim may not have granted them all.
-			everyone_perms = content["new_everyone_mask"].asInteger();
-			group_perms = content["new_group_mask"].asInteger();
-			next_owner_perms = content["new_next_owner_mask"].asInteger();
-		}
-		else 
-		{
-			// This old sim doesn't provide creation perms so use old assumption-based perms.
-			if(mPostData["inventory_type"].asString() != "snapshot")
-			{
-				next_owner_perms = PERM_MOVE | PERM_TRANSFER;
-			}
-		}
-		LLPermissions new_perms;
-		new_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
-		new_perms.initMasks(PERM_ALL, PERM_ALL, everyone_perms, group_perms, next_owner_perms);
-		S32 creation_date_now = time_corrected();
-		LLPointer<LLViewerInventoryItem> item
-			= new LLViewerInventoryItem(content["new_inventory_item"].asUUID(),
-										mPostData["folder_id"].asUUID(),
-										new_perms,
-										content["new_asset"].asUUID(),
-										asset_type,
-										inventory_type,
-										mPostData["name"].asString(),
-										mPostData["description"].asString(),
-										LLSaleInfo::DEFAULT,
-										LLInventoryItem::II_FLAGS_NONE,
-										creation_date_now);
-		gInventory.updateItem(item);
-		gInventory.notifyObservers();
-		
-		if (mCallback)
-		{
-			// call the callback with the new Asset UUID
-			mCallback(item->getAssetUUID());
-		}
+	on_new_single_inventory_upload_complete(
+		asset_type,
+		inventory_type,
+		mPostData["asset_type"].asString(),
+		mPostData["folder_id"].asUUID(),
+		mPostData["name"],
+		mPostData["description"],
+		content,
+		expected_upload_cost);
 
-		// Show the preview panel for textures and sounds to let
-		// user know that the image (or snapshot) arrived intact.
-		LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
-		if (active_panel)
-		{
-			active_panel->setSelection(content["new_inventory_item"].asUUID(), TAKE_FOCUS_NO);
-			if((LLAssetType::AT_TEXTURE == asset_type || LLAssetType::AT_SOUND == asset_type)
-				&& LLFilePicker::instance().getFileCount() <= FILE_COUNT_DISPLAY_THRESHOLD)
-			{
-				active_panel->openSelected();
-			}
-			//LLFloaterInventory::dumpSelectionInformation((void*)view);
-			// restore keyboard focus
-			LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
-			gFocusMgr.setKeyboardFocus(focus);
-		}
-	}
-	else
-	{
-		llwarns << "Can't find a folder to put it in" << llendl;
-	}
+	// continue uploading for bulk uploads
 
-	// remove the "Uploading..." message
-	LLUploadDialog::modalUploadFinished();
-	
 	// *FIX: This is a pretty big hack. What this does is check the
 	// file picker if there are any more pending uploads. If so,
 	// upload that file.
@@ -340,17 +388,42 @@ void LLNewAgentInventoryResponder::uploadComplete(const LLSD& content)
 
 		// Continuing the horrible hack above, we need to extract the originally requested permissions data, if any,
 		// and use them for each next file to be uploaded. Note the requested perms are not the same as the
-		// granted ones found in the given "content" structure but can still be found in mPostData. -MG
-		U32 everyone_perms   = mPostData.has("everyone_mask")   ? mPostData.get("everyone_mask"  ).asInteger() : PERM_NONE;
-		U32 group_perms      = mPostData.has("group_mask")      ? mPostData.get("group_mask"     ).asInteger() : PERM_NONE;
-		U32 next_owner_perms = mPostData.has("next_owner_mask") ? mPostData.get("next_owner_mask").asInteger() : PERM_NONE;
+		U32 everyone_perms =
+			content.has("everyone_mask") ?
+			content["everyone_mask"].asInteger() :
+			PERM_NONE;
+
+		U32 group_perms =
+			content.has("group_mask") ?
+			content["group_mask"].asInteger() :
+			PERM_NONE;
+
+		U32 next_owner_perms =
+			content.has("next_owner_mask") ?
+			content["next_owner_mask"].asInteger() :
+			PERM_NONE;
+
 		std::string display_name = LLStringUtil::null;
-		upload_new_resource(next_file, asset_name, asset_name,
-				    LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
-				    next_owner_perms, group_perms,
-				    everyone_perms, display_name,
-				    NULL, expected_upload_cost);
+		LLAssetStorage::LLStoreAssetCallback callback = NULL;
+		void *userdata = NULL;
+
+		upload_new_resource(
+			next_file,
+			asset_name,
+			asset_name,
+			0,
+			LLFolderType::FT_NONE,
+			LLInventoryType::IT_NONE,
+			next_owner_perms,
+			group_perms,
+			everyone_perms,
+			display_name,
+			callback,
+			LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(),
+			userdata);
 	}
+
+	LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], TRUE);
 }
 
 LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data,
@@ -404,17 +477,19 @@ void LLSendTexLayerResponder::error(U32 statusNum, const std::string& reason)
 	mBakedUploadData = NULL;	// deleted in onTextureUploadComplete()
 }
 
-LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data,
-																 const LLUUID& vfile_id,
-																 LLAssetType::EType asset_type)
-: LLAssetUploadResponder(post_data, vfile_id, asset_type)
+LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
+	const LLSD& post_data,
+	const LLUUID& vfile_id,
+	LLAssetType::EType asset_type)
+	: LLAssetUploadResponder(post_data, vfile_id, asset_type)
 {
 }
 
-LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(const LLSD& post_data,
-																 const std::string& file_name,
-																 LLAssetType::EType asset_type)
-: LLAssetUploadResponder(post_data, file_name, asset_type)
+LLUpdateAgentInventoryResponder::LLUpdateAgentInventoryResponder(
+	const LLSD& post_data,
+	const std::string& file_name,
+	LLAssetType::EType asset_type)
+	: LLAssetUploadResponder(post_data, file_name, asset_type)
 {
 }
 
@@ -597,3 +672,472 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content)
 		break;
 	}
 }
+
+
+/////////////////////////////////////////////////////
+// LLNewAgentInventoryVariablePriceResponder::Impl //
+/////////////////////////////////////////////////////
+class LLNewAgentInventoryVariablePriceResponder::Impl
+{
+public:
+	Impl(
+		const LLUUID& vfile_id,
+		LLAssetType::EType asset_type,
+		const LLSD& inventory_data) :
+		mVFileID(vfile_id),
+		mAssetType(asset_type),
+		mInventoryData(inventory_data),
+		mFileName("")
+	{
+		if (!gVFS->getExists(vfile_id, asset_type))
+		{
+			llwarns
+				<< "LLAssetUploadResponder called with nonexistant "
+				<< "vfile_id " << vfile_id << llendl;
+			mVFileID.setNull();
+			mAssetType = LLAssetType::AT_NONE;
+		}
+	}
+
+	Impl(
+		const std::string& file_name,
+		LLAssetType::EType asset_type,
+		const LLSD& inventory_data) :
+		mFileName(file_name),
+		mAssetType(asset_type),
+		mInventoryData(inventory_data)
+	{
+		mVFileID.setNull();
+	}
+
+	std::string getFilenameOrIDString() const
+	{
+		return (mFileName.empty() ? mVFileID.asString() : mFileName);
+	}
+
+	LLUUID getVFileID() const
+	{
+		return mVFileID;
+	}
+
+	std::string getFilename() const
+	{
+		return mFileName;
+	}
+
+	LLAssetType::EType getAssetType() const
+	{
+		return mAssetType;
+	}
+
+	LLInventoryType::EType getInventoryType() const
+	{
+		return LLInventoryType::lookup(
+			mInventoryData["inventory_type"].asString());
+	}
+
+	std::string getInventoryTypeString() const
+	{
+		return mInventoryData["inventory_type"].asString();
+	}
+
+	LLUUID getFolderID() const
+	{
+		return mInventoryData["folder_id"].asUUID();
+	}
+
+	std::string getItemName() const
+	{
+		return mInventoryData["name"].asString();
+	}
+
+	std::string getItemDescription() const
+	{
+		return mInventoryData["description"].asString();
+	}
+
+	void displayCannotUploadReason(const std::string& reason)
+	{
+		LLSD args;
+		args["FILE"] = getFilenameOrIDString();
+		args["REASON"] = reason;
+
+
+		LLNotificationsUtil::add("CannotUploadReason", args);
+		LLUploadDialog::modalUploadFinished();
+	}
+
+	void onApplicationLevelError(const LLSD& error)
+	{
+		static const std::string _IDENTIFIER = "identifier";
+
+		static const std::string _INSUFFICIENT_FUNDS =
+			"NewAgentInventory_InsufficientLindenDollarBalance";
+		static const std::string _MISSING_REQUIRED_PARAMETER =
+			"NewAgentInventory_MissingRequiredParamater";
+		static const std::string _INVALID_REQUEST_BODY =
+			"NewAgentInventory_InvalidRequestBody";
+		static const std::string _RESOURCE_COST_DIFFERS =
+			"NewAgentInventory_ResourceCostDiffers";
+
+		static const std::string _MISSING_PARAMETER = "missing_parameter";
+		static const std::string _INVALID_PARAMETER = "invalid_parameter";
+		static const std::string _MISSING_RESOURCE = "missing_resource";
+		static const std::string _INVALID_RESOURCE = "invalid_resource";
+
+		// TODO* Add the other error_identifiers
+
+		std::string error_identifier = error[_IDENTIFIER].asString();
+
+		// TODO*: Pull these user visible strings from an xml file
+		// to be localized
+		if ( _INSUFFICIENT_FUNDS == error_identifier )
+		{
+			displayCannotUploadReason("You do not have a sufficient L$ balance to complete this upload.");
+		}
+		else if ( _MISSING_REQUIRED_PARAMETER == error_identifier )
+		{
+			// Missing parameters
+			if (error.has(_MISSING_PARAMETER) )
+			{
+				std::string message = 
+					"Upload request was missing required parameter '[P]'";
+				LLStringUtil::replaceString(
+					message,
+					"[P]",
+					error[_MISSING_PARAMETER].asString());
+
+				displayCannotUploadReason(message);
+			}
+			else
+			{
+				std::string message = 
+					"Upload request was missing a required parameter";
+				displayCannotUploadReason(message);					
+			}
+		}
+		else if ( _INVALID_REQUEST_BODY == error_identifier )
+		{
+			// Invalid request body, check to see if 
+			// a particular parameter was invalid
+			if ( error.has(_INVALID_PARAMETER) )
+			{
+				std::string message = "Upload parameter '[P]' is invalid.";
+				LLStringUtil::replaceString(
+					message,
+					"[P]",
+					error[_INVALID_PARAMETER].asString());
+
+				// See if the server also responds with what resource
+				// is missing.
+				if ( error.has(_MISSING_RESOURCE) )
+				{
+					message += "\nMissing resource '[R]'.";
+
+					LLStringUtil::replaceString(
+						message,
+						"[R]",
+						error[_MISSING_RESOURCE].asString());
+				}
+				else if ( error.has(_INVALID_RESOURCE) )
+				{
+					message += "\nInvalid resource '[R]'.";
+
+					LLStringUtil::replaceString(
+						message,
+						"[R]",
+						error[_INVALID_RESOURCE].asString());
+				}
+
+				displayCannotUploadReason(message);
+			}
+			else
+			{
+				std::string message = "Upload request was malformed";
+				displayCannotUploadReason(message);					
+			}
+		}
+		else if ( _RESOURCE_COST_DIFFERS == error_identifier )
+		{
+			displayCannotUploadReason("The resource cost associated with this upload is not consistent with the server.");
+		}
+		else
+		{
+			displayCannotUploadReason("Unknown Error");
+		}
+	}
+
+	void onTransportError()
+	{
+		displayCannotUploadReason(
+				"The server is experiencing unexpected difficulties.");
+	}
+
+	void onTransportError(const LLSD& error)
+	{
+		static const std::string _IDENTIFIER = "identifier";
+
+		static const std::string _SERVER_ERROR_AFTER_CHARGE =
+			"NewAgentInventory_ServerErrorAfterCharge";
+
+		std::string error_identifier = error[_IDENTIFIER].asString();
+
+		// TODO*: Pull the user visible strings from an xml file
+		// to be localized
+
+		if ( _SERVER_ERROR_AFTER_CHARGE == error_identifier )
+		{
+			displayCannotUploadReason(
+				"The server is experiencing unexpected difficulties.  You may have been charged for the upload.");
+		}
+		else
+		{
+			displayCannotUploadReason(
+				"The server is experiencing unexpected difficulties.");
+		}
+	}
+
+	bool uploadConfirmationCallback(
+		const LLSD& notification,
+		const LLSD& response,
+		boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder> responder)
+	{
+		S32 option;
+		std::string confirmation_url;
+
+		option = LLNotificationsUtil::getSelectedOption(
+			notification,
+			response);
+
+		confirmation_url =
+			notification["payload"]["confirmation_url"].asString();
+
+		// Yay!  We are confirming or cancelling our upload
+		switch(option)
+		{
+		case 0:
+		    {
+				confirmUpload(confirmation_url, responder);
+			}
+			break;
+		case 1:
+		default:
+			break;
+		}
+
+		return false;
+	}
+
+	void confirmUpload(
+		const std::string& confirmation_url,
+		boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder> responder)
+	{
+		if ( getFilename().empty() )
+		{
+			// we have no filename, use virtual file ID instead
+			LLHTTPClient::postFile(
+				confirmation_url,
+				getVFileID(),
+				getAssetType(),
+				responder);
+		}
+		else
+		{
+			LLHTTPClient::postFile(
+				confirmation_url,
+				getFilename(),
+				responder);
+		}
+	}
+
+
+private:
+	std::string mFileName;
+
+	LLSD mInventoryData;
+	LLAssetType::EType mAssetType;
+	LLUUID mVFileID;
+};
+
+///////////////////////////////////////////////
+// LLNewAgentInventoryVariablePriceResponder //
+///////////////////////////////////////////////
+LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
+	const LLUUID& vfile_id,
+	LLAssetType::EType asset_type,
+	const LLSD& inventory_info)
+{
+	mImpl = new Impl(
+		vfile_id,
+		asset_type,
+		inventory_info);
+}
+
+LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
+	const std::string& file_name,
+	LLAssetType::EType asset_type,
+	const LLSD& inventory_info)
+{
+	mImpl = new Impl(
+		file_name,
+		asset_type,
+		inventory_info);
+}
+
+LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder()
+{
+	delete mImpl;
+}
+
+void LLNewAgentInventoryVariablePriceResponder::errorWithContent(
+	U32 statusNum,
+	const std::string& reason,
+	const LLSD& content)
+{
+	lldebugs 
+		<< "LLNewAgentInventoryVariablePrice::error " << statusNum 
+		<< " reason: " << reason << llendl;
+
+	if ( content.has("error") )
+	{
+		static const std::string _ERROR = "error";
+
+		mImpl->onTransportError(content[_ERROR]);
+	}
+	else
+	{
+		mImpl->onTransportError();
+	}
+}
+
+void LLNewAgentInventoryVariablePriceResponder::result(const LLSD& content)
+{
+	// Parse out application level errors and the appropriate
+	// responses for them
+	static const std::string _ERROR = "error";
+	static const std::string _STATE = "state";
+
+	static const std::string _COMPLETE = "complete";
+	static const std::string _CONFIRM_UPLOAD = "confirm_upload";
+
+	static const std::string _UPLOAD_PRICE = "upload_price";
+	static const std::string _RESOURCE_COST = "resource_cost";
+	static const std::string _RSVP = "rsvp";
+
+	// Check for application level errors
+	if ( content.has(_ERROR) )
+	{
+		onApplicationLevelError(content[_ERROR]);
+		return;
+	}
+
+	std::string state = content[_STATE];
+	LLAssetType::EType asset_type = mImpl->getAssetType();
+
+	if ( _COMPLETE == state )
+	{
+		// rename file in VFS with new asset id
+		if (mImpl->getFilename().empty())
+		{
+			// rename the file in the VFS to the actual asset id
+			// llinfos << "Changing uploaded asset UUID to " << content["new_asset"].asUUID() << llendl;
+			gVFS->renameFile(
+				mImpl->getVFileID(),
+				asset_type,
+				content["new_asset"].asUUID(),
+				asset_type);
+		}
+
+ 		on_new_single_inventory_upload_complete(
+ 			asset_type,
+ 			mImpl->getInventoryType(),
+			mImpl->getInventoryTypeString(),
+			mImpl->getFolderID(),
+			mImpl->getItemName(),
+			mImpl->getItemDescription(),
+			content,
+			content[_UPLOAD_PRICE].asInteger());
+
+		// TODO* Add bulk (serial) uploading or add
+		// a super class of this that does so
+	}
+	else if ( _CONFIRM_UPLOAD == state )
+	{
+		showConfirmationDialog(
+			content[_UPLOAD_PRICE].asInteger(),
+			content[_RESOURCE_COST].asInteger(),
+			content[_RSVP].asString());
+	}
+	else
+	{
+		onApplicationLevelError("");
+	}
+}
+
+void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError(
+	const LLSD& error)
+{
+	mImpl->onApplicationLevelError(error);
+}
+
+void LLNewAgentInventoryVariablePriceResponder::showConfirmationDialog(
+	S32 upload_price,
+	S32 resource_cost,
+	const std::string& confirmation_url)
+{
+	if ( 0 == upload_price )
+	{
+		// don't show confirmation dialog for free uploads, I mean,
+		// they're free!
+
+		// The creating of a new instrusive_ptr(this)
+		// creates a new boost::intrusive_ptr
+		// which is a copy of this.  This code is required because
+		// 'this' is always of type Class* and not the intrusive_ptr,
+		// and thus, a reference to 'this' is not registered
+		// by using just plain 'this'.
+
+		// Since LLNewAgentInventoryVariablePriceResponder is a
+		// reference counted class, it is possible (since the
+		// reference to a plain 'this' would be missed here) that,
+		// when using plain ol' 'this', that this object
+		// would be deleted before the callback is triggered
+		// and cause sadness.
+		mImpl->confirmUpload(
+			confirmation_url,
+			boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this));
+	}
+	else
+	{
+		LLSD substitutions;
+		LLSD payload;
+
+		substitutions["PRICE"] = upload_price;
+
+		payload["confirmation_url"] = confirmation_url;
+
+		// The creating of a new instrusive_ptr(this)
+		// creates a new boost::intrusive_ptr
+		// which is a copy of this.  This code is required because
+		// 'this' is always of type Class* and not the intrusive_ptr,
+		// and thus, a reference to 'this' is not registered
+		// by using just plain 'this'.
+
+		// Since LLNewAgentInventoryVariablePriceResponder is a
+		// reference counted class, it is possible (since the
+		// reference to a plain 'this' would be missed here) that,
+		// when using plain ol' 'this', that this object
+		// would be deleted before the callback is triggered
+		// and cause sadness.
+		LLNotificationsUtil::add(
+			"UploadCostConfirmation",
+			substitutions,
+			payload,
+			boost::bind(
+				&LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback,
+				mImpl,
+				_1,
+				_2,
+				boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this)));
+	}
+}
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
index ade9c967580a8ae9ecddbf120fd72aed863e64a9..c869988203587bd7ba50e64d97722f2a2f8f869f 100644
--- a/indra/newview/llassetuploadresponders.h
+++ b/indra/newview/llassetuploadresponders.h
@@ -33,7 +33,6 @@
 #ifndef LL_LLASSETUPLOADRESPONDER_H
 #define LL_LLASSETUPLOADRESPONDER_H
 
-#include "llassetstorage.h"
 #include "llhttpclient.h"
 
 // Abstract class for supporting asset upload
@@ -62,20 +61,60 @@ class LLAssetUploadResponder : public LLHTTPClient::Responder
 	std::string mFileName;
 };
 
+
+// TODO*: Remove this once deprecated
 class LLNewAgentInventoryResponder : public LLAssetUploadResponder
 {
 public:
-	LLNewAgentInventoryResponder(const LLSD& post_data,
-								const LLUUID& vfile_id,
-								LLAssetType::EType asset_type,
-								boost::function<void(const LLUUID& uuid)> callback = NULL);
-	LLNewAgentInventoryResponder(const LLSD& post_data, 
-								const std::string& file_name,
-								 LLAssetType::EType asset_type,
-								boost::function<void(const LLUUID& uuid)> callback = NULL);
+	LLNewAgentInventoryResponder(
+		const LLSD& post_data,
+		const LLUUID& vfile_id,
+		LLAssetType::EType asset_type);
+	LLNewAgentInventoryResponder(
+		const LLSD& post_data,
+		const std::string& file_name,
+		LLAssetType::EType asset_type);
+    virtual void error(U32 statusNum, const std::string& reason);
 	virtual void uploadComplete(const LLSD& content);
+	virtual void uploadFailure(const LLSD& content);
+};
+
+// A base class which goes through and performs some default
+// actions for variable price uploads.  If more specific actions
+// are needed (such as different confirmation messages, etc.)
+// the functions onApplicationLevelError and showConfirmationDialog.
+class LLNewAgentInventoryVariablePriceResponder :
+	public LLHTTPClient::Responder
+{
+public:
+	LLNewAgentInventoryVariablePriceResponder(
+		const LLUUID& vfile_id,
+		LLAssetType::EType asset_type,
+		const LLSD& inventory_info);
+
+	LLNewAgentInventoryVariablePriceResponder(
+		const std::string& file_name,
+		LLAssetType::EType asset_type,
+		const LLSD& inventory_info);
+
+	virtual ~LLNewAgentInventoryVariablePriceResponder();
 
-	boost::function<void(const LLUUID& uuid)> mCallback;
+	void errorWithContent(
+		U32 statusNum,
+		const std::string& reason,
+		const LLSD& content);
+	void result(const LLSD& content);
+
+	virtual void onApplicationLevelError(
+		const LLSD& error);
+	virtual void showConfirmationDialog(
+		S32 upload_price,
+		S32 resource_cost,
+		const std::string& confirmation_url);
+
+private:
+	class Impl;
+	Impl* mImpl;
 };
 
 class LLBakedUploadData;
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 38eda5bd2e014d049210e5192003e731044b189e..390e950d758c8de3f95eef871f4fd72e9ff6b77a 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -189,20 +189,30 @@ BOOL LLDrawable::isLight() const
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_CLEANUP_DRAWABLE("Cleanup Drawable");
+static LLFastTimer::DeclareTimer FTM_DEREF_DRAWABLE("Deref");
+static LLFastTimer::DeclareTimer FTM_DELETE_FACES("Faces");
+
 void LLDrawable::cleanupReferences()
 {
-	LLFastTimer t(FTM_PIPELINE);
+	LLFastTimer t(FTM_CLEANUP_DRAWABLE);
 	
-	std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
-	mFaces.clear();
+	{
+		LLFastTimer t(FTM_DELETE_FACES);
+		std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
+		mFaces.clear();
+	}
 
 	gObjectList.removeDrawable(this);
 	
 	gPipeline.unlinkDrawable(this);
 	
-	// Cleanup references to other objects
-	mVObjp = NULL;
-	mParent = NULL;
+	{
+		LLFastTimer t(FTM_DEREF_DRAWABLE);
+		// Cleanup references to other objects
+		mVObjp = NULL;
+		mParent = NULL;
+	}
 }
 
 void LLDrawable::cleanupDeadDrawables()
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 651dabff9eaa3805f9ff3deeed41b2c0fab79f7a..c3c6cbe12f79221edbe62955efe8b3ac221ea1b0 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -313,8 +313,10 @@ class LLDrawable : public LLRefCount
 
 inline LLFace* LLDrawable::getFace(const S32 i) const
 {
-	llassert((U32)i < mFaces.size());
-	llassert(mFaces[i]);
+	if ((U32) i >= mFaces.size())
+	{
+		return NULL;
+	}
 	return mFaces[i];
 }
 
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index ef946ac49e5cfe99ff3fc99ddf682a20e3ce4433..ae30af3647838d4403cb2764ce0864c4afe36c26 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -442,7 +442,6 @@ void LLRenderPass::renderTexture(U32 type, U32 mask)
 
 void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture)
 {
-	llpushcallstacks ;
 	for (LLCullResult::drawinfo_list_t::iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
 	{
 		LLDrawInfo* pparams = *i;
@@ -475,6 +474,7 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture)
 	{
 		if (params.mTexture.notNull())
 		{
+			params.mTexture->addTextureStats(params.mVSize);
 			gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ;
 			if (params.mTextureMatrix)
 			{
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 875c9ac6a9d597ca84c3e78891bbe43df646a6ea..7fd7cd3910b38b0c3b1f01a95b5a270048762b4e 100644
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -60,7 +60,9 @@ static BOOL deferred_render = FALSE;
 
 LLDrawPoolAlpha::LLDrawPoolAlpha(U32 type) :
 		LLRenderPass(type), current_shader(NULL), target_shader(NULL),
-		simple_shader(NULL), fullbright_shader(NULL)
+		simple_shader(NULL), fullbright_shader(NULL),
+		mColorSFactor(LLRender::BF_UNDEF), mColorDFactor(LLRender::BF_UNDEF),
+		mAlphaSFactor(LLRender::BF_UNDEF), mAlphaDFactor(LLRender::BF_UNDEF)
 {
 
 }
@@ -178,9 +180,16 @@ void LLDrawPoolAlpha::render(S32 pass)
 
 	LLGLSPipelineAlpha gls_pipeline_alpha;
 
+	gGL.setColorMask(true, true);
+
 	if (LLPipeline::sFastAlpha && !deferred_render)
 	{
-		LLGLDisable blend_disable(GL_BLEND);
+		mColorSFactor = LLRender::BF_ONE;  // }
+		mColorDFactor = LLRender::BF_ZERO; // } these are like disabling blend on the color channels, but we're still blending on the alpha channel so that we can suppress glow
+		mAlphaSFactor = LLRender::BF_ZERO;
+		mAlphaDFactor = LLRender::BF_ZERO; // block (zero-out) glow where the alpha test succeeds
+		gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+
 		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.33f);
 		if (mVertexShaderLevel > 0)
 		{
@@ -204,8 +213,17 @@ void LLDrawPoolAlpha::render(S32 pass)
 	}
 
 	LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy ? GL_TRUE : GL_FALSE);
+
+	mColorSFactor = LLRender::BF_SOURCE_ALPHA;           // } regular alpha blend
+	mColorDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA; // }
+	mAlphaSFactor = LLRender::BF_ZERO;                         // } glow suppression
+	mAlphaDFactor = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;       // }
+	gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+
 	renderAlpha(getVertexDataMask());
 
+	gGL.setColorMask(true, false);
+
 	if (deferred_render && current_shader != NULL)
 	{
 		gPipeline.unbindDeferredShader(*current_shader);
@@ -283,9 +301,18 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 	for (LLCullResult::sg_list_t::iterator i = gPipeline.beginAlphaGroups(); i != gPipeline.endAlphaGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
+		llassert(group);
+		llassert(group->mSpatialPartition);
+
 		if (group->mSpatialPartition->mRenderByGroup &&
-			!group->isDead())
+		    !group->isDead())
 		{
+			bool draw_glow_for_this_partition = mVertexShaderLevel > 0 && // no shaders = no glow.
+				// All particle systems seem to come off the wire with texture entries which claim that they glow.  This is probably a bug in the data.  Suppress.
+				group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_PARTICLE &&
+				group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_CLOUD &&
+				group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD_PARTICLE;
+
 			LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[LLRenderPass::PASS_ALPHA];
 
 			for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k)	
@@ -294,96 +321,118 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 
 				LLRenderPass::applyModelMatrix(params);
 
-				if (params.mFullbright)
 				{
-					// Turn off lighting if it hasn't already been so.
-					if (light_enabled || !initialized_lighting)
+					if (params.mFullbright)
+					{
+						// Turn off lighting if it hasn't already been so.
+						if (light_enabled || !initialized_lighting)
+						{
+							initialized_lighting = TRUE;
+							if (use_shaders) 
+							{
+								target_shader = fullbright_shader;
+							}
+							else
+							{
+								gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+							}
+							light_enabled = FALSE;
+						}
+					}
+					// Turn on lighting if it isn't already.
+					else if (!light_enabled || !initialized_lighting)
 					{
 						initialized_lighting = TRUE;
 						if (use_shaders) 
 						{
-							target_shader = fullbright_shader;
+							target_shader = simple_shader;
 						}
 						else
 						{
-							gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+							gPipeline.enableLightsDynamic();
 						}
-						light_enabled = FALSE;
+						light_enabled = TRUE;
 					}
-				}
-				// Turn on lighting if it isn't already.
-				else if (!light_enabled || !initialized_lighting)
-				{
-					initialized_lighting = TRUE;
-					if (use_shaders) 
-					{
-						target_shader = simple_shader;
-					}
-					else
-					{
-						gPipeline.enableLightsDynamic();
-					}
-					light_enabled = TRUE;
-				}
 
-				// If we need shaders, and we're not ALREADY using the proper shader, then bind it
-				// (this way we won't rebind shaders unnecessarily).
-				if(use_shaders && (current_shader != target_shader))
-				{
-					llassert(target_shader != NULL);
-					if (deferred_render && current_shader != NULL)
+					// If we need shaders, and we're not ALREADY using the proper shader, then bind it
+					// (this way we won't rebind shaders unnecessarily).
+					if(use_shaders && (current_shader != target_shader))
 					{
-						gPipeline.unbindDeferredShader(*current_shader);
-						diffuse_channel = 0;
-					}
-					current_shader = target_shader;
-					if (deferred_render)
-					{
-						gPipeline.bindDeferredShader(*current_shader);
-						diffuse_channel = current_shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-					}
-					else
-					{
-						current_shader->bind();
+						llassert(target_shader != NULL);
+						if (deferred_render && current_shader != NULL)
+						{
+							gPipeline.unbindDeferredShader(*current_shader);
+							diffuse_channel = 0;
+						}
+						current_shader = target_shader;
+						if (deferred_render)
+						{
+							gPipeline.bindDeferredShader(*current_shader);
+							diffuse_channel = current_shader->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+						}
+						else
+						{
+							current_shader->bind();
+						}
 					}
-				}
-				else if (!use_shaders && current_shader != NULL)
-				{
-					if (deferred_render)
+					else if (!use_shaders && current_shader != NULL)
 					{
-						gPipeline.unbindDeferredShader(*current_shader);
-						diffuse_channel = 0;
+						if (deferred_render)
+						{
+							gPipeline.unbindDeferredShader(*current_shader);
+							diffuse_channel = 0;
+						}
+						LLGLSLShader::bindNoShader();
+						current_shader = NULL;
 					}
-					LLGLSLShader::bindNoShader();
-					current_shader = NULL;
-				}
-
-				if (params.mGroup)
-				{
-					params.mGroup->rebuildMesh();
-				}
 
-				
-				if (params.mTexture.notNull())
-				{
-					gGL.getTexUnit(diffuse_channel)->bind(params.mTexture.get());
-					if(params.mTexture.notNull())
+					if (params.mGroup)
 					{
-						params.mTexture->addTextureStats(params.mVSize);
+						params.mGroup->rebuildMesh();
 					}
-					if (params.mTextureMatrix)
+
+					
+					if (params.mTexture.notNull())
 					{
-						gGL.getTexUnit(0)->activate();
-						glMatrixMode(GL_TEXTURE);
-						glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
-						gPipeline.mTextureMatrixOps++;
+						gGL.getTexUnit(diffuse_channel)->bind(params.mTexture.get());
+						if(params.mTexture.notNull())
+						{
+							params.mTexture->addTextureStats(params.mVSize);
+						}
+						if (params.mTextureMatrix)
+						{
+							gGL.getTexUnit(0)->activate();
+							glMatrixMode(GL_TEXTURE);
+							glLoadMatrixf((GLfloat*) params.mTextureMatrix->mMatrix);
+							gPipeline.mTextureMatrixOps++;
+						}
 					}
 				}
 
 				params.mVertexBuffer->setBuffer(mask);
 				params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 				gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
+				
+				// If this alpha mesh has glow, then draw it a second time to add the destination-alpha (=glow).  Interleaving these state-changing calls could be expensive, but glow must be drawn Z-sorted with alpha.
+				if (draw_glow_for_this_partition &&
+				    params.mGlowColor.mV[3] > 0)
+				{
+					// install glow-accumulating blend mode
+					gGL.blendFunc(LLRender::BF_ZERO, LLRender::BF_ONE, // don't touch color
+						      LLRender::BF_ONE, LLRender::BF_ONE); // add to alpha (glow)
 
+					// glow doesn't use vertex colors from the mesh data
+					params.mVertexBuffer->setBuffer(mask & ~LLVertexBuffer::MAP_COLOR);
+					glColor4ubv(params.mGlowColor.mV);
+
+					// do the actual drawing, again
+					params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+					gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
+
+					// restore our alpha blend mode
+					gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
+				}
+			
 				if (params.mTextureMatrix && params.mTexture.notNull())
 				{
 					gGL.getTexUnit(0)->activate();
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index 3aa752f72c58f69d24c727239fc62bbf9b04185a..61f73d0b3119d9ee123724d69350d91dc8954612 100644
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -34,6 +34,7 @@
 #define LL_LLDRAWPOOLALPHA_H
 
 #include "lldrawpool.h"
+#include "llrender.h"
 #include "llframetimer.h"
 
 class LLFace;
@@ -83,6 +84,12 @@ class LLDrawPoolAlpha: public LLRenderPass
 	LLGLSLShader* target_shader;
 	LLGLSLShader* simple_shader;
 	LLGLSLShader* fullbright_shader;	
+
+	// our 'normal' alpha blend function for this pass
+	LLRender::eBlendFactor mColorSFactor;
+	LLRender::eBlendFactor mColorDFactor;	
+	LLRender::eBlendFactor mAlphaSFactor;
+	LLRender::eBlendFactor mAlphaDFactor;
 };
 
 class LLDrawPoolAlphaPostWater : public LLDrawPoolAlpha
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 546b60f286777c35aee462b14597b5bd329d88f5..012e41383fbb9ecef089dc879537f85f74c2ae77 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -157,6 +157,8 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_CHARACTERS);
 	
+	sSkipTransparent = TRUE;
+
 	if (LLPipeline::sImpostorRender)
 	{
 		beginDeferredSkinned();
@@ -181,6 +183,8 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_CHARACTERS);
 
+	sSkipTransparent = FALSE;
+
 	if (LLPipeline::sImpostorRender)
 	{
 		endDeferredSkinned();
@@ -564,7 +568,6 @@ void LLDrawPoolAvatar::endSkinned()
 
 void LLDrawPoolAvatar::beginDeferredSkinned()
 {
-	sSkipTransparent = TRUE;
 	sShaderLevel = mVertexShaderLevel;
 	sVertexProgram = &gDeferredAvatarProgram;
 
@@ -579,7 +582,6 @@ void LLDrawPoolAvatar::beginDeferredSkinned()
 
 void LLDrawPoolAvatar::endDeferredSkinned()
 {
-	sSkipTransparent = FALSE;
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	sRenderingSkinned = FALSE;
 	disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index d09d4a412fa13e0924268f4a38bdcf2d8679f429..8f3e775976cf4b3550fa285ca8b7dd0c5b879ca1 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -701,6 +701,18 @@ void LLDrawPoolBump::endBump()
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 }
 
+S32 LLDrawPoolBump::getNumDeferredPasses()
+{ 
+	if (gSavedSettings.getBOOL("RenderObjectBump"))
+	{
+		return 1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
 void LLDrawPoolBump::beginDeferredPass(S32 pass)
 {
 	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
@@ -825,7 +837,6 @@ void LLBumpImageList::addTextureStats(U8 bump, const LLUUID& base_image_id, F32
 
 void LLBumpImageList::updateImages()
 {	
-	llpushcallstacks ;
 	for (bump_image_map_t::iterator iter = mBrightnessEntries.begin(); iter != mBrightnessEntries.end(); )
 	{
 		bump_image_map_t::iterator curiter = iter++;
@@ -852,7 +863,7 @@ void LLBumpImageList::updateImages()
 			}
 		}
 	}
-	llpushcallstacks ;
+	
 	for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); )
 	{
 		bump_image_map_t::iterator curiter = iter++;
@@ -879,7 +890,6 @@ void LLBumpImageList::updateImages()
 			}
 		}
 	}
-	llpushcallstacks ;
 }
 
 
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index bf940cf1e46ef6d5bbf0bd58eb57265fd5d58e2c..2019f1df2698c45a7ef014363c14a0f129cdd94f 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -79,7 +79,7 @@ protected :
 	void renderBump();
 	void endBump();
 
-	virtual S32 getNumDeferredPasses() { return 1; }
+	virtual S32 getNumDeferredPasses();
 	/*virtual*/ void beginDeferredPass(S32 pass);
 	/*virtual*/ void endDeferredPass(S32 pass);
 	/*virtual*/ void renderDeferred(S32 pass);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 9de69a8173553f6f391c9006fb7229e50c1f417d..53330e4d9857e7e43b6cd2d0268caf33e78d8222 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -185,22 +185,33 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	mHasMedia = FALSE ;
 }
 
+static LLFastTimer::DeclareTimer FTM_DESTROY_FACE("Destroy Face");
+static LLFastTimer::DeclareTimer FTM_DESTROY_TEXTURE("Texture");
+static LLFastTimer::DeclareTimer FTM_DESTROY_DRAWPOOL("Drawpool");
+static LLFastTimer::DeclareTimer FTM_DESTROY_TEXTURE_MATRIX("Texture Matrix");
+static LLFastTimer::DeclareTimer FTM_DESTROY_DRAW_INFO("Draw Info");
+static LLFastTimer::DeclareTimer FTM_DESTROY_ATLAS("Atlas");
+static LLFastTimer::DeclareTimer FTM_FACE_DEREF("Deref");
 
 void LLFace::destroy()
 {
+	LLFastTimer t(FTM_DESTROY_FACE);
 	if(mTexture.notNull())
 	{
+		LLFastTimer t(FTM_DESTROY_TEXTURE);
 		mTexture->removeFace(this) ;
 	}
 	
 	if (mDrawPoolp)
 	{
+		LLFastTimer t(FTM_DESTROY_DRAWPOOL);
 		mDrawPoolp->removeFace(this);
 		mDrawPoolp = NULL;
 	}
 
 	if (mTextureMatrix)
 	{
+		LLFastTimer t(FTM_DESTROY_TEXTURE_MATRIX);
 		delete mTextureMatrix;
 		mTextureMatrix = NULL;
 
@@ -215,11 +226,21 @@ void LLFace::destroy()
 		}
 	}
 	
-	setDrawInfo(NULL);
+	{
+		LLFastTimer t(FTM_DESTROY_DRAW_INFO);
+		setDrawInfo(NULL);
+	}
+	
+	{
+		LLFastTimer t(FTM_DESTROY_ATLAS);
+		removeAtlas();
+	}
 	
-	removeAtlas();
-	mDrawablep = NULL;
-	mVObjp = NULL;
+	{
+		LLFastTimer t(FTM_FACE_DEREF);
+		mDrawablep = NULL;
+		mVObjp = NULL;
+	}
 }
 
 
@@ -862,12 +883,14 @@ void LLFace::updateRebuildFlags()
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_FACE_GET_GEOM("Face Geom");
+
 BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 							   const S32 &f,
 								const LLMatrix4& mat_vert, const LLMatrix3& mat_normal,
 								const U16 &index_offset)
 {
-	llpushcallstacks ;
+	LLFastTimer t(FTM_FACE_GET_GEOM);
 	const LLVolumeFace &vf = volume.getVolumeFace(f);
 	S32 num_vertices = (S32)vf.mVertices.size();
 	S32 num_indices = LLPipeline::sUseTriStrips ? (S32)vf.mTriStrip.size() : (S32) vf.mIndices.size();
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 2873057c19a8023d8cf56df7b0847d4466faf5f2..324d99937ed5bf8873807d75c2e82869fe34829a 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -55,12 +55,14 @@ LLFilePicker LLFilePicker::sInstance;
 #define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0"
 #define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.png)\0*.tga;*.bmp;*.jpg;*.jpeg;*.png\0"
 #define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0"
+#define COLLADA_FILTER L"Scene (*.dae)\0*.dae\0"
 #ifdef _CORY_TESTING
 #define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0"
 #endif
 #define XML_FILTER L"XML files (*.xml)\0*.xml\0"
 #define SLOBJECT_FILTER L"Objects (*.slobject)\0*.slobject\0"
 #define RAW_FILTER L"RAW files (*.raw)\0*.raw\0"
+#define MODEL_FILTER L"Model files (*.dae)\0*.dae\0"
 #endif
 
 //
@@ -176,6 +178,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
 		mOFN.lpstrFilter = ANIM_FILTER \
 			L"\0";
 		break;
+	case FFLOAD_COLLADA:
+		mOFN.lpstrFilter = COLLADA_FILTER \
+			L"\0";
+		break;
 #ifdef _CORY_TESTING
 	case FFLOAD_GEOMETRY:
 		mOFN.lpstrFilter = GEOMETRY_FILTER \
@@ -194,6 +200,10 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
 		mOFN.lpstrFilter = RAW_FILTER \
 			L"\0";
 		break;
+	case FFLOAD_MODEL:
+		mOFN.lpstrFilter = MODEL_FILTER \
+			L"\0";
+		break;
 	default:
 		res = FALSE;
 		break;
@@ -201,7 +211,7 @@ BOOL LLFilePicker::setupFilter(ELoadFilter filter)
 	return res;
 }
 
-BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
+BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking)
 {
 	if( mLocked )
 	{
@@ -220,8 +230,11 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
 
 	setupFilter(filter);
 	
-	// Modal, so pause agent
-	send_agent_pause();
+	if (blocking)
+	{
+		// Modal, so pause agent
+		send_agent_pause();
+	}
 
 	reset();
 	
@@ -232,10 +245,14 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
 		std::string filename = utf16str_to_utf8str(llutf16string(mFilesW));
 		mFiles.push_back(filename);
 	}
-	send_agent_resume();
 
-	// Account for the fact that the app has been stalled.
-	LLFrameTimer::updateFrameTime();
+	if (blocking)
+	{
+		send_agent_resume();
+		// Account for the fact that the app has been stalled.
+		LLFrameTimer::updateFrameTime();
+	}
+	
 	return success;
 }
 
@@ -543,6 +560,15 @@ Boolean LLFilePicker::navOpenFilterProc(AEDesc *theItem, void *info, void *callB
 								result = false;
 							}
 						}
+						else if (filter == FFLOAD_COLLADA)
+						{
+							if (fileInfo.filetype != 'DAE ' && 
+								(fileInfo.extension && (CFStringCompare(fileInfo.extension, CFSTR("dae"), kCFCompareCaseInsensitive) != kCFCompareEqualTo))
+							)
+							{
+								result = false;
+							}
+						}
 #ifdef _CORY_TESTING
 						else if (filter == FFLOAD_GEOMETRY)
 						{
@@ -808,7 +834,7 @@ OSStatus	LLFilePicker::doNavSaveDialog(ESaveFilter filter, const std::string& fi
 	return error;
 }
 
-BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
+BOOL LLFilePicker::getOpenFile(ELoadFilter filter, bool blocking)
 {
 	if( mLocked )
 		return FALSE;
@@ -827,20 +853,29 @@ BOOL LLFilePicker::getOpenFile(ELoadFilter filter)
 		mNavOptions.optionFlags |= kNavSupportPackages;
 	}
 	
-	// Modal, so pause agent
-	send_agent_pause();
+	if (blocking)
+	{
+		// Modal, so pause agent
+		send_agent_pause();
+	}
+
 	{
 		error = doNavChooseDialog(filter);
 	}
-	send_agent_resume();
+	
 	if (error == noErr)
 	{
 		if (getFileCount())
 			success = true;
 	}
 
-	// Account for the fact that the app has been stalled.
-	LLFrameTimer::updateFrameTime();
+	if (blocking)
+	{
+		send_agent_resume();
+		// Account for the fact that the app has been stalled.
+		LLFrameTimer::updateFrameTime();
+	}
+
 	return success;
 }
 
@@ -1089,6 +1124,12 @@ static std::string add_bvh_filter_to_gtkchooser(GtkWindow *picker)
 						       LLTrans::getString("animation_files") + " (*.bvh)");
 }
 
+static std::string add_collada_filter_to_gtkchooser(GtkWindow *picker)
+{
+	return add_simple_pattern_filter_to_gtkchooser(picker,  "*.dae",
+						       LLTrans::getString("scene_files") + " (*.dae)");
+}
+
 static std::string add_imageload_filter_to_gtkchooser(GtkWindow *picker)
 {
 	GtkFileFilter *gfilter = gtk_file_filter_new();
@@ -1191,7 +1232,7 @@ BOOL LLFilePicker::getSaveFile( ESaveFilter filter, const std::string& filename
 	return rtn;
 }
 
-BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
+BOOL LLFilePicker::getOpenFile( ELoadFilter filter, bool blocking )
 {
 	BOOL rtn = FALSE;
 
@@ -1213,6 +1254,9 @@ BOOL LLFilePicker::getOpenFile( ELoadFilter filter )
 		case FFLOAD_ANIM:
 			filtername = add_bvh_filter_to_gtkchooser(picker);
 			break;
+		case FFLOAD_COLLADA:
+			filtername = add_collada_filter_to_gtkchooser(picker);
+			break;
 		case FFLOAD_IMAGE:
 			filtername = add_imageload_filter_to_gtkchooser(picker);
 			break;
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index 4f254ff67eb73f63817e497301febec2d6c1e902..10fb30af9f0311eb4ac4b305e14362417025c71a 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -88,6 +88,8 @@ class LLFilePicker
 		FFLOAD_XML = 6,
 		FFLOAD_SLOBJECT = 7,
 		FFLOAD_RAW = 8,
+		FFLOAD_MODEL = 9,
+		FFLOAD_COLLADA = 10,
 	};
 
 	enum ESaveFilter
@@ -111,7 +113,7 @@ class LLFilePicker
 
 	// open the dialog. This is a modal operation
 	BOOL getSaveFile( ESaveFilter filter = FFSAVE_ALL, const std::string& filename = LLStringUtil::null );
-	BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL );
+	BOOL getOpenFile( ELoadFilter filter = FFLOAD_ALL, bool blocking = true  );
 	BOOL getMultipleOpenFiles( ELoadFilter filter = FFLOAD_ALL );
 
 	// Get the filename(s) found. getFirstFile() sets the pointer to
@@ -192,4 +194,6 @@ class LLFilePicker
 	~LLFilePicker();
 };
 
+const std::string upload_pick(void* data);
+
 #endif
diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp
index 434c89e8bac429749926bcafc54a1112aec6bf03..7dcf4350aab1864c5b7482ed64070ea176efb53c 100644
--- a/indra/newview/llfloateranimpreview.cpp
+++ b/indra/newview/llfloateranimpreview.cpp
@@ -1006,13 +1006,15 @@ void LLFloaterAnimPreview::onBtnOK(void* userdata)
 						    LLAssetType::AT_ANIMATION,
 						    name,
 						    desc,
+						    0,
 						    LLFolderType::FT_NONE,
 						    LLInventoryType::IT_ANIMATION,
 						    LLFloaterPerms::getNextOwnerPerms(), 
-							LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(),
+						    LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(),
 						    name,
 						    NULL, 
-							expected_upload_cost);
+						    expected_upload_cost,
+						    NULL);
 			}
 			else
 			{
diff --git a/indra/newview/llfloaternamedesc.cpp b/indra/newview/llfloaternamedesc.cpp
index 5c343ecb22001fe5c78984c6491dde58d4f6b290..244b2f78c91cc95e538ed5a16cebec73a3cfd3c9 100644
--- a/indra/newview/llfloaternamedesc.cpp
+++ b/indra/newview/llfloaternamedesc.cpp
@@ -174,9 +174,10 @@ void LLFloaterNameDesc::onBtnOK( )
 	upload_new_resource(mFilenameAndPath, // file
 			    childGetValue("name_form").asString(), 
 			    childGetValue("description_form").asString(), 
+			    0,
 			    LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
 			    LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(),
-			    display_name, NULL, expected_upload_cost);
+			    display_name, NULL, expected_upload_cost, NULL);
 	closeFloater(false);
 }
 
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index 3487f52f3551b2f852bc517fb304b9a3b42a5695..d15eedd9c09bf02f0b222c91f517df98303d63d9 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -809,7 +809,7 @@ void LLFloaterPreference::buildPopupLists()
 
 void LLFloaterPreference::refreshEnabledState()
 {	
-	LLCheckBoxCtrl* ctrl_reflections = getChild<LLCheckBoxCtrl>("Reflections");
+	LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections");
 	LLRadioGroup* radio_reflection_detail = getChild<LLRadioGroup>("ReflectionDetailRadio");
 	
 	// Reflections
@@ -822,7 +822,7 @@ void LLFloaterPreference::refreshEnabledState()
 	bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump");
 	getChild<LLCheckBoxCtrl>("BumpShiny")->setEnabled(bumpshiny ? TRUE : FALSE);
 	
-	radio_reflection_detail->setEnabled(ctrl_reflections->get() && reflections);
+	radio_reflection_detail->setEnabled(reflections);
 	
 	// Avatar Mode
 	// Enable Avatar Shaders
@@ -868,18 +868,41 @@ void LLFloaterPreference::refreshEnabledState()
 	// *HACK just checks to see if we can use shaders... 
 	// maybe some cards that use shaders, but don't support windlight
 	ctrl_wind_light->setEnabled(ctrl_shader_enable->getEnabled() && shaders);
+
+	//Deferred/SSAO/Shadows
+	LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders");
+	if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderUseFBO") &&
+		shaders)
+	{
+		BOOL enabled = ctrl_wind_light->get() ? TRUE : FALSE;
+
+		ctrl_deferred->setEnabled(enabled);
+	
+		LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO");
+		LLComboBox* ctrl_shadow = getChild<LLComboBox>("ShadowDetail");
+
+		enabled = enabled && (ctrl_deferred->get() ? TRUE : FALSE);
+		
+		ctrl_ssao->setEnabled(enabled);
+		ctrl_shadow->setEnabled(enabled);
+	}
+
+
 	// now turn off any features that are unavailable
 	disableUnavailableSettings();
 }
 
 void LLFloaterPreference::disableUnavailableSettings()
 {	
-	LLCheckBoxCtrl* ctrl_reflections   = getChild<LLCheckBoxCtrl>("Reflections");
+	LLComboBox* ctrl_reflections   = getChild<LLComboBox>("Reflections");
 	LLCheckBoxCtrl* ctrl_avatar_vp     = getChild<LLCheckBoxCtrl>("AvatarVertexProgram");
 	LLCheckBoxCtrl* ctrl_avatar_cloth  = getChild<LLCheckBoxCtrl>("AvatarCloth");
 	LLCheckBoxCtrl* ctrl_shader_enable = getChild<LLCheckBoxCtrl>("BasicShaders");
 	LLCheckBoxCtrl* ctrl_wind_light    = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders");
 	LLCheckBoxCtrl* ctrl_avatar_impostors = getChild<LLCheckBoxCtrl>("AvatarImpostors");
+	LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders");
+	LLComboBox* ctrl_shadows = getChild<LLComboBox>("ShadowDetail");
+	LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO");
 
 	// if vertex shaders off, disable all shader related products
 	if(!LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable"))
@@ -891,13 +914,22 @@ void LLFloaterPreference::disableUnavailableSettings()
 		ctrl_wind_light->setValue(FALSE);
 		
 		ctrl_reflections->setEnabled(FALSE);
-		ctrl_reflections->setValue(FALSE);
+		ctrl_reflections->setValue(0);
 		
 		ctrl_avatar_vp->setEnabled(FALSE);
 		ctrl_avatar_vp->setValue(FALSE);
 		
 		ctrl_avatar_cloth->setEnabled(FALSE);
 		ctrl_avatar_cloth->setValue(FALSE);
+
+		ctrl_shadows->setEnabled(FALSE);
+		ctrl_shadows->setValue(0);
+		
+		ctrl_ssao->setEnabled(FALSE);
+		ctrl_ssao->setValue(FALSE);
+
+		ctrl_deferred->setEnabled(FALSE);
+		ctrl_deferred->setValue(FALSE);
 	}
 	
 	// disabled windlight
@@ -905,10 +937,20 @@ void LLFloaterPreference::disableUnavailableSettings()
 	{
 		ctrl_wind_light->setEnabled(FALSE);
 		ctrl_wind_light->setValue(FALSE);
+
+		//deferred needs windlight, disable deferred
+		ctrl_shadows->setEnabled(FALSE);
+		ctrl_shadows->setValue(0);
+		
+		ctrl_ssao->setEnabled(FALSE);
+		ctrl_ssao->setValue(FALSE);
+
+		ctrl_deferred->setEnabled(FALSE);
+		ctrl_deferred->setValue(FALSE);
 	}
 	
 	// disabled reflections
-	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderWaterReflections"))
+	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionDetail"))
 	{
 		ctrl_reflections->setEnabled(FALSE);
 		ctrl_reflections->setValue(FALSE);
@@ -922,13 +964,25 @@ void LLFloaterPreference::disableUnavailableSettings()
 		
 		ctrl_avatar_cloth->setEnabled(FALSE);
 		ctrl_avatar_cloth->setValue(FALSE);
+
+		//deferred needs AvatarVP, disable deferred
+		ctrl_shadows->setEnabled(FALSE);
+		ctrl_shadows->setValue(0);
+		
+		ctrl_ssao->setEnabled(FALSE);
+		ctrl_ssao->setValue(FALSE);
+
+		ctrl_deferred->setEnabled(FALSE);
+		ctrl_deferred->setValue(FALSE);
 	}
+
 	// disabled cloth
 	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth"))
 	{
 		ctrl_avatar_cloth->setEnabled(FALSE);
 		ctrl_avatar_cloth->setValue(FALSE);
 	}
+
 	// disabled impostors
 	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderUseImpostors"))
 	{
diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp
index adac9861d481cdb08b25e37466447560acaec746..357c10c6b64442206b5e487e773dde71225637da 100644
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -977,7 +977,7 @@ LLFloaterPostcard* LLSnapshotLivePreview::savePostcard()
 }
 
 // Callback for asset upload
-void profile_pic_upload_callback(const LLUUID& uuid)
+void profile_pic_upload_callback(const LLUUID& uuid, void *user_data, S32 status, LLExtStat ext_status)
 {
 	LLFloaterSnapshot* floater =  LLFloaterReg::getTypedInstance<LLFloaterSnapshot>("snapshot");
 	floater->setAsProfilePic(uuid);
@@ -1001,7 +1001,7 @@ void LLSnapshotLivePreview::saveTexture(bool set_as_profile_pic)
 			
 	if (formatted->encode(scaled, 0.0f))
 	{
-		boost::function<void(const LLUUID& uuid)> callback = NULL;
+		LLAssetStorage::LLStoreAssetCallback callback = NULL;
 
 		if (set_as_profile_pic)
 		{
@@ -1014,17 +1014,19 @@ void LLSnapshotLivePreview::saveTexture(bool set_as_profile_pic)
 		std::string who_took_it;
 		LLAgentUI::buildFullname(who_took_it);
 		S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+		std::string snapname = "Snapshot : " + pos_string;
 		upload_new_resource(tid,	// tid
 				    LLAssetType::AT_TEXTURE,
-				    "Snapshot : " + pos_string,
+				    snapname,
 				    "Taken by " + who_took_it + " at " + pos_string,
+				    0,
 				    LLFolderType::FT_SNAPSHOT_CATEGORY,
 				    LLInventoryType::IT_SNAPSHOT,
 				    PERM_ALL,  // Note: Snapshots to inventory is a special case of content upload
 				    PERM_NONE, // that ignores the user's premissions preferences and continues to
 				    PERM_NONE, // always use these fairly permissive hard-coded initial perms. - MG
-				    "Snapshot : " + pos_string,
-				    callback, expected_upload_cost);
+				    snapname,
+				    callback, expected_upload_cost, NULL);
 		gViewerWindow->playSnapshotAnimAndSound();
 	}
 	else
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index d8d7057c4e0853c685945bfb83bdb5d242ed7c3b..a8172bbfaef7ae7075d37ca88489f1b3053372d9 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -423,7 +423,7 @@ void LLFloaterTools::refresh()
 	LLResMgr::getInstance()->getIntegerString(obj_count_string, LLSelectMgr::getInstance()->getSelection()->getRootObjectCount());
 	childSetTextArg("obj_count",  "[COUNT]", obj_count_string);	
 	std::string prim_count_string;
-	LLResMgr::getInstance()->getIntegerString(prim_count_string, LLSelectMgr::getInstance()->getSelection()->getObjectCount());
+	LLResMgr::getInstance()->getIntegerString(prim_count_string, LLSelectMgr::getInstance()->getSelection()->getObjectCount(TRUE));
 	childSetTextArg("prim_count", "[COUNT]", prim_count_string);
 
 	// calculate selection rendering cost
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 8d1d27444b900fecb8222dc41ce7c93621f3a8b7..9ed5d13831ccabbc7ba7c4178470fcbb1b7319a3 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -567,6 +567,18 @@ void LLHUDText::setStringUTF8(const std::string &wtext)
 	setString(utf8str_to_wstring(wtext));
 }
 
+std::string LLHUDText::getString()
+{
+	std::ostringstream ostr;
+	for (U32 i = 0; i < mTextSegments.size(); ++i)
+	{
+		const std::string str = wstring_to_utf8str(mTextSegments[i].getText());
+		ostr << str;
+	}
+
+	return ostr.str();
+}
+
 void LLHUDText::setString(const LLWString &wtext)
 {
 	mTextSegments.clear();
diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h
index dc14a8c764ac825e6687c454791aa2f52ed15fea..4787a15eafe88f4d82cf8c964153be44e7d827c0 100644
--- a/indra/newview/llhudtext.h
+++ b/indra/newview/llhudtext.h
@@ -90,6 +90,7 @@ class LLHUDText : public LLHUDObject
 
 public:
 	void setStringUTF8(const std::string &utf8string);
+	std::string getString();
 	void setString(const LLWString &wstring);
 	void clearString();
 	void addLine(const std::string &text, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL);
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index 0fbf3148ac6d813f6399e87531d3f6bbd14cc1dc..e394b4dfc125495f8780d4d8afa098f9457ceec1 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -132,7 +132,9 @@ std::string ICON_NAME[ICON_NAME_COUNT] =
 	"Inv_Gesture",
 
 	"Inv_LinkItem",
-	"Inv_LinkFolder"
+	"Inv_LinkFolder",
+	
+	"Inv_Mesh"
 };
 
 // +=================================================+
@@ -985,6 +987,14 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
 			// Only should happen for broken links.
 			new_listener = new LLLinkItemBridge(inventory, uuid);
 			break;
+	        case LLAssetType::AT_MESH:
+			if(!(inv_type == LLInventoryType::IT_MESH))
+			{
+				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+			}
+			new_listener = new LLMeshBridge(inventory, uuid);
+			break;
+
 		default:
 			llinfos << "Unhandled asset type (llassetstorage.h): "
 					<< (S32)asset_type << llendl;
@@ -2274,6 +2284,9 @@ LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type)
 		return LLUI::getUIImage("Inv_LookFolderClosed");
 	}
 	return LLUI::getUIImage("Inv_FolderClosed");
+		/*case LLAssetType::AT_MESH:
+			control = "inv_folder_mesh.tga";
+			break;*/
 }
 
 LLUIImagePtr LLFolderBridge::getOpenIcon() const
@@ -2773,6 +2786,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
 		case DAD_LINK:
+		case DAD_MESH:
 			accept = dragItemIntoFolder((LLInventoryItem*)cargo_data,
 										drop);
 			break;
@@ -3658,6 +3672,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
 		case DAD_BODYPART:
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
+		case DAD_MESH:
 			{
 				LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
 				const LLPermissions& perm = inv_item->getPermissions();
@@ -4969,6 +4984,65 @@ void LLWearableBridge::removeFromAvatar()
 	}
 }
 
+
+// +=================================================+
+// |        LLMeshBridge                             |
+// +=================================================+
+
+LLUIImagePtr LLMeshBridge::getIcon() const
+{
+	return get_item_icon(LLAssetType::AT_MESH, LLInventoryType::IT_MESH, 0, FALSE);
+}
+
+void LLMeshBridge::openItem()
+{
+	LLViewerInventoryItem* item = getItem();
+	
+	if (item)
+	{
+		// open mesh
+	}
+}
+
+void LLMeshBridge::previewItem()
+{
+	LLViewerInventoryItem* item = getItem();
+	if(item)
+	{
+		// preview mesh
+	}
+}
+
+
+void LLMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+	lldebugs << "LLMeshBridge::buildContextMenu()" << llendl;
+	std::vector<std::string> items;
+	std::vector<std::string> disabled_items;
+
+	if(isItemInTrash())
+	{
+		items.push_back(std::string("Purge Item"));
+		if (!isItemRemovable())
+		{
+			disabled_items.push_back(std::string("Purge Item"));
+		}
+
+		items.push_back(std::string("Restore Item"));
+	}
+	else
+	{
+		items.push_back(std::string("Properties"));
+
+		getClipboardEntries(true, items, disabled_items, flags);
+	}
+
+
+	hide_context_entries(menu, items, disabled_items);
+}
+
+
+
 LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type,
 													   const LLUUID& uuid,LLInventoryModel* model)
 {
@@ -5017,6 +5091,12 @@ LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_
 
 		break;
 
+	case LLAssetType::AT_MESH:
+		action = new LLMeshBridgeAction(uuid,model);
+		break;
+
+
+		
 	default:
 		break;
 	}
@@ -5265,6 +5345,18 @@ void LLWearableBridgeAction::doIt()
 	LLInvFVBridgeAction::doIt();
 }
 
+//virtual
+void	LLMeshBridgeAction::doIt() 
+{
+	LLViewerInventoryItem* item = getItem();
+	if(item)
+	{
+		// do it
+	}
+	
+	LLInvFVBridgeAction::doIt();
+}
+
 // +=================================================+
 // |        LLLinkItemBridge                         |
 // +=================================================+
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 32504091cb9ca273288efc565421b7b7c8f011bf..318e37f7a1f8712384663c39af9cb3fb8ead3d14 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -82,6 +82,8 @@ enum EInventoryIcon
 
 	LINKITEM_ICON_NAME,
 	LINKFOLDER_ICON_NAME,
+	
+	MESH_ICON_NAME,
 
 	ICON_NAME_COUNT
 };
@@ -626,7 +628,6 @@ class LLLinkItemBridge : public LLItemBridge
 	static std::string sPrefix;
 };
 
-
 class LLLinkFolderBridge : public LLItemBridge
 {
 	friend class LLInvFVBridge;
@@ -647,6 +648,25 @@ class LLLinkFolderBridge : public LLItemBridge
 	static std::string sPrefix;
 };
 
+
+
+class LLMeshBridge : public LLItemBridge
+{
+	friend class LLInvFVBridge;
+public:
+	virtual LLUIImagePtr getIcon() const;
+	virtual void openItem();
+	virtual void previewItem();
+	virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
+
+protected:
+	LLMeshBridge(LLInventoryPanel* inventory, const LLUUID& uuid) :
+		LLItemBridge(inventory, uuid) {}
+};
+
+
+
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLInvFVBridgeAction (& its derived classes)
 //
@@ -807,6 +827,19 @@ class LLWearableBridgeAction: public LLInvFVBridgeAction
 
 };
 
+class LLMeshBridgeAction: public LLInvFVBridgeAction
+{
+	friend class LLInvFVBridgeAction;
+public:
+	virtual void	doIt() ;
+	virtual ~LLMeshBridgeAction(){}
+protected:
+	LLMeshBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){}
+
+};
+
+
+
 void wear_inventory_item_on_avatar(LLInventoryItem* item);
 
 class LLViewerJointAttachment;
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index 3e16dfea5f8108b0d5a5dd17cc932e440e601588..56de7cc771734810ed8648d7f59035c0b5ffacc3 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -538,6 +538,9 @@ const std::string& get_item_icon_name(LLAssetType::EType asset_type,
 	case LLAssetType::AT_LINK_FOLDER:
 		idx = LINKFOLDER_ICON_NAME;
 		break;
+	case LLAssetType::AT_MESH:
+		idx = MESH_ICON_NAME;
+		break;
 	default:
 		break;
 	}
diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp
index 5f913d5469fc9ab53e88c412195f0d1d1e52d12a..c2a68288371aac399c4999f377978940e62658d6 100644
--- a/indra/newview/llpanelgroupnotices.cpp
+++ b/indra/newview/llpanelgroupnotices.cpp
@@ -158,6 +158,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
 		case DAD_CALLINGCARD:
+		case DAD_MESH:
 		{
 			LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
 			if(gInventory.getItem(inv_item->getUUID())
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index c43cbf5819ae4574c1bd3b0e7586c4b9805d5de0..95716e0046acd41c00448cdccfb40b0484b61213 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -818,6 +818,7 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop,
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
 		case DAD_CALLINGCARD:
+		case DAD_MESH:
 			accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data);
 			if(accept && drop)
 			{
@@ -1403,6 +1404,117 @@ LLUIImagePtr LLTaskWearableBridge::getIcon() const
 	return get_item_icon(mAssetType, LLInventoryType::IT_WEARABLE, mFlags, FALSE );
 }
 
+///----------------------------------------------------------------------------
+/// Class LLTaskMeshBridge
+///----------------------------------------------------------------------------
+
+class LLTaskMeshBridge : public LLTaskInvFVBridge
+{
+public:
+	LLTaskMeshBridge(
+		LLPanelObjectInventory* panel,
+		const LLUUID& uuid,
+		const std::string& name);
+
+	virtual LLUIImagePtr getIcon() const;
+	virtual void openItem();
+	virtual void performAction(LLFolderView* folder, LLInventoryModel* model, std::string action);
+	virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
+};
+
+LLTaskMeshBridge::LLTaskMeshBridge(
+	LLPanelObjectInventory* panel,
+	const LLUUID& uuid,
+	const std::string& name) :
+	LLTaskInvFVBridge(panel, uuid, name)
+{
+}
+
+LLUIImagePtr LLTaskMeshBridge::getIcon() const
+{
+	return get_item_icon(LLAssetType::AT_MESH, LLInventoryType::IT_MESH, 0, FALSE);
+}
+
+void LLTaskMeshBridge::openItem()
+{
+	// open mesh
+}
+
+
+// virtual
+void LLTaskMeshBridge::performAction(LLFolderView* folder, LLInventoryModel* model, std::string action)
+{
+	if (action == "mesh action")
+	{
+		LLInventoryItem* item = findItem();
+		if(item)
+		{
+			// do action
+		}
+	}
+	LLTaskInvFVBridge::performAction(folder, model, action);
+}
+
+void LLTaskMeshBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
+{
+	LLInventoryItem* item = findItem();
+	if(!item) return;
+	std::vector<std::string> items;
+	std::vector<std::string> disabled_items;
+
+	if(item->getPermissions().getOwner() != gAgent.getID()
+	   && item->getSaleInfo().isForSale())
+	{
+		items.push_back(std::string("Task Buy"));
+
+		std::string label= LLTrans::getString("Buy");
+		// Check the price of the item.
+		S32 price = getPrice();
+		if (-1 == price)
+		{
+			llwarns << "label_buy_task_bridged_item: Invalid price" << llendl;
+		}
+		else
+		{
+			std::ostringstream info;
+			info <<  LLTrans::getString("BuyforL$") << price;
+			label.assign(info.str());
+		}
+
+		const LLView::child_list_t *list = menu.getChildList();
+		LLView::child_list_t::const_iterator itor;
+		for (itor = list->begin(); itor != list->end(); ++itor)
+		{
+			std::string name = (*itor)->getName();
+			LLMenuItemCallGL* menu_itemp = dynamic_cast<LLMenuItemCallGL*>(*itor);
+			if (name == "Task Buy" && menu_itemp)
+			{
+				menu_itemp->setLabel(label);
+			}
+		}
+	}
+	else
+	{
+		items.push_back(std::string("Task Open")); 
+		if (!isItemCopyable())
+		{
+			disabled_items.push_back(std::string("Task Open"));
+		}
+	}
+	items.push_back(std::string("Task Properties"));
+	if(isItemRenameable())
+	{
+		items.push_back(std::string("Task Rename"));
+	}
+	if(isItemRemovable())
+	{
+		items.push_back(std::string("Task Remove"));
+	}
+
+
+	hide_context_entries(menu, items, disabled_items);
+}
+
 
 ///----------------------------------------------------------------------------
 /// LLTaskInvFVBridge impl
@@ -1490,6 +1602,11 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory*
 										 object->getUUID(),
 										 object->getName());
 		break;
+	case LLAssetType::AT_MESH:
+		new_bridge = new LLTaskMeshBridge(panel,
+										  object->getUUID(),
+										  object->getName());
+		break;
 	
 		break;
 	default:
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index fbe68b4d92f22adfc28041640b7d2ccd785d8c6a..8b016372392b207f060c882527bc408ebe9958bc 100644
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -574,7 +574,7 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata )
 		LLUUID id = LightTextureCtrl->getImageAssetID();
 		if (id.notNull())
 		{
-			if (volobjp->getLightTextureID().isNull())
+			if (!volobjp->isLightSpotlight())
 			{ //this commit is making this a spot light, set UI to default params
 				volobjp->setLightTextureID(id);
 				LLVector3 spot_params = volobjp->getSpotLightParams();
@@ -591,7 +591,7 @@ void LLPanelVolume::onCommitLight( LLUICtrl* ctrl, void* userdata )
 				volobjp->setSpotLightParams(spot_params);
 			}
 		}
-		else if (volobjp->getLightTextureID().notNull())
+		else if (volobjp->isLightSpotlight())
 		{ //no longer a spot light
 			volobjp->setLightTextureID(id);
 			//self->childDisable("Light FOV");
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index d03a492cd1002146da0a6ecc2b074f254bf95836..f0c4559ad2a7b6941beb66f3d8cb53e23cfb61e2 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -70,6 +70,7 @@
 #include "llhudmanager.h"
 #include "llinventorymodel.h"
 #include "llmenugl.h"
+#include "llmeshrepository.h"
 #include "llmutelist.h"
 #include "llsidepaneltaskinfo.h"
 #include "llslurl.h"
@@ -181,7 +182,6 @@ LLObjectSelection *get_null_object_selection()
 
 // Build time optimization, generate this function once here
 template class LLSelectMgr* LLSingleton<class LLSelectMgr>::getInstance();
-
 //-----------------------------------------------------------------------------
 // LLSelectMgr()
 //-----------------------------------------------------------------------------
@@ -5348,6 +5348,78 @@ BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power)
 	return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id));
 }
 
+void LLSelectNode::renderOneWireframe(const LLColor4& color)
+{
+	LLViewerObject* objectp = getObject();
+	if (!objectp)
+	{
+		return;
+	}
+
+	LLDrawable* drawable = objectp->mDrawable;
+	if(!drawable)
+	{
+		return;
+	}
+
+	glMatrixMode(GL_MODELVIEW);
+	gGL.pushMatrix();
+
+	BOOL is_hud_object = objectp->isHUDAttachment();
+
+	if (!is_hud_object)
+	{
+		glLoadIdentity();
+		glMultMatrixd(gGLModelView);
+	}
+	
+	if (drawable->isActive())
+	{
+		glMultMatrixf((F32*) objectp->getRenderMatrix().mMatrix);
+	}
+
+	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+	
+	if (LLSelectMgr::sRenderHiddenSelections) // && gFloaterTools && gFloaterTools->getVisible())
+	{
+		gGL.blendFunc(LLRender::BF_SOURCE_COLOR, LLRender::BF_ONE);
+		LLGLEnable fog(GL_FOG);
+		glFogi(GL_FOG_MODE, GL_LINEAR);
+		float d = (LLViewerCamera::getInstance()->getPointOfInterest()-LLViewerCamera::getInstance()->getOrigin()).magVec();
+		LLColor4 fogCol = color * (F32)llclamp((LLSelectMgr::getInstance()->getSelectionCenterGlobal()-gAgentCamera.getCameraPositionGlobal()).magVec()/(LLSelectMgr::getInstance()->getBBoxOfSelection().getExtentLocal().magVec()*4), 0.0, 1.0);
+		glFogf(GL_FOG_START, d);
+		glFogf(GL_FOG_END, d*(1 + (LLViewerCamera::getInstance()->getView() / LLViewerCamera::getInstance()->getDefaultFOV())));
+		glFogfv(GL_FOG_COLOR, fogCol.mV);
+
+		LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE, GL_GEQUAL);
+		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+		{
+			glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
+			for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+			{
+				LLFace* face = drawable->getFace(i);
+				pushVerts(face, LLVertexBuffer::MAP_VERTEX);
+			}
+		}
+	}
+
+	gGL.flush();
+	gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+	glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
+	LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+	glPolygonOffset(3.f, 2.f);
+	glLineWidth(3.f);
+	for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+	{
+		LLFace* face = drawable->getFace(i);
+		pushVerts(face, LLVertexBuffer::MAP_VERTEX);
+	}
+	glLineWidth(1.f);
+	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+	gGL.popMatrix();
+}
+
 //-----------------------------------------------------------------------------
 // renderOneSilhouette()
 //-----------------------------------------------------------------------------
@@ -5365,6 +5437,13 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 		return;
 	}
 
+	LLVOVolume* vobj = drawable->getVOVolume();
+	if (vobj && vobj->isMesh())
+	{
+		renderOneWireframe(color);
+		return;
+	}
+
 	if (!mSilhouetteExists)
 	{
 		return;
@@ -6054,10 +6133,32 @@ BOOL LLObjectSelection::isEmpty() const
 //-----------------------------------------------------------------------------
 // getObjectCount() - returns number of non null objects
 //-----------------------------------------------------------------------------
-S32 LLObjectSelection::getObjectCount()
+S32 LLObjectSelection::getObjectCount(BOOL mesh_adjust)
 {
 	cleanupNodes();
 	S32 count = mList.size();
+
+	if (mesh_adjust)
+	{
+		for (list_t::iterator iter = mList.begin(); iter != mList.end(); ++iter)
+		{
+			LLSelectNode* node = *iter;
+			LLViewerObject* object = node->getObject();
+			
+			if (object && object->getVolume())
+			{
+				LLVOVolume* vobj = (LLVOVolume*) object;
+				if (vobj->isMesh())
+				{
+					LLUUID mesh_id = vobj->getVolume()->getParams().getSculptID();
+					U32 cost = gMeshRepo.getResourceCost(mesh_id);
+					count += cost-1;
+				}
+			}
+
+		}
+	}
+
 	return count;
 }
 
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index d315f40ff3ba07da0865f523837bee111447674e..78b94a8efe3b8bd4192dc900503a369c1b6a3a66 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -140,6 +140,7 @@ class LLSelectNode
 	BOOL isTESelected(S32 te_index);
 	S32 getLastSelectedTE();
 	S32 getTESelectMask() { return mTESelectMask; }
+	void renderOneWireframe(const LLColor4& color);
 	void renderOneSilhouette(const LLColor4 &color);
 	void setTransient(BOOL transient) { mTransient = transient; }
 	BOOL isTransient() { return mTransient; }
@@ -290,7 +291,7 @@ class LLObjectSelection : public LLRefCount
 	LLSelectNode* findNode(LLViewerObject* objectp);
 
 	// count members
-	S32 getObjectCount();
+	S32 getObjectCount(BOOL mesh_adjust = FALSE);
 	S32 getTECount();
 	S32 getRootObjectCount();
 
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index d6e9256feea2af8ad1461e46505e914117135fb2..3742f70df5223fdc7e5b9279194c8a52f2a785a7 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -1513,6 +1513,7 @@ void LLSpatialGroup::checkOcclusion()
 {
 	if (LLPipeline::sUseOcclusion > 1)
 	{
+		LLFastTimer t(FTM_OCCLUSION_READBACK);
 		LLSpatialGroup* parent = getParent();
 		if (parent && parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
 		{	//if the parent has been marked as occluded, the child is implicitly occluded
@@ -1520,7 +1521,6 @@ void LLSpatialGroup::checkOcclusion()
 		}
 		else if (isOcclusionState(QUERY_PENDING))
 		{	//otherwise, if a query is pending, read it back
-			LLFastTimer t(FTM_OCCLUSION_READBACK);
 			GLuint res = 1;
 			if (!isOcclusionState(DISCARD_QUERY) && mOcclusionQuery[LLViewerCamera::sCurCameraID])
 			{
@@ -2294,7 +2294,6 @@ void pushVerts(LLFace* face, U32 mask)
 		U16 offset = face->getIndicesStart();
 		buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
 	}
-
 }
 
 void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
@@ -3423,11 +3422,23 @@ LLCullResult::LLCullResult()
 void LLCullResult::clear()
 {
 	mVisibleGroupsSize = 0;
+	mVisibleGroupsEnd = mVisibleGroups.begin();
+
 	mAlphaGroupsSize = 0;
+	mAlphaGroupsEnd = mAlphaGroups.begin();
+
 	mOcclusionGroupsSize = 0;
+	mOcclusionGroupsEnd = mOcclusionGroups.begin();
+
 	mDrawableGroupsSize = 0;
+	mDrawableGroupsEnd = mDrawableGroups.begin();
+
 	mVisibleListSize = 0;
+	mVisibleListEnd = mVisibleList.begin();
+
 	mVisibleBridgeSize = 0;
+	mVisibleBridgeEnd = mVisibleBridge.begin();
+
 
 	for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; i++)
 	{
@@ -3436,6 +3447,7 @@ void LLCullResult::clear()
 			mRenderMap[i][j] = 0;
 		}
 		mRenderMapSize[i] = 0;
+		mRenderMapEnd[i] = mRenderMap[i].begin();
 	}
 }
 
@@ -3446,7 +3458,7 @@ LLCullResult::sg_list_t::iterator LLCullResult::beginVisibleGroups()
 
 LLCullResult::sg_list_t::iterator LLCullResult::endVisibleGroups()
 {
-	return mVisibleGroups.begin() + mVisibleGroupsSize;
+	return mVisibleGroupsEnd;
 }
 
 LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups()
@@ -3456,7 +3468,7 @@ LLCullResult::sg_list_t::iterator LLCullResult::beginAlphaGroups()
 
 LLCullResult::sg_list_t::iterator LLCullResult::endAlphaGroups()
 {
-	return mAlphaGroups.begin() + mAlphaGroupsSize;
+	return mAlphaGroupsEnd;
 }
 
 LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups()
@@ -3466,7 +3478,7 @@ LLCullResult::sg_list_t::iterator LLCullResult::beginOcclusionGroups()
 
 LLCullResult::sg_list_t::iterator LLCullResult::endOcclusionGroups()
 {
-	return mOcclusionGroups.begin() + mOcclusionGroupsSize;
+	return mOcclusionGroupsEnd;
 }
 
 LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups()
@@ -3476,7 +3488,7 @@ LLCullResult::sg_list_t::iterator LLCullResult::beginDrawableGroups()
 
 LLCullResult::sg_list_t::iterator LLCullResult::endDrawableGroups()
 {
-	return mDrawableGroups.begin() + mDrawableGroupsSize;
+	return mDrawableGroupsEnd;
 }
 
 LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList()
@@ -3486,7 +3498,7 @@ LLCullResult::drawable_list_t::iterator LLCullResult::beginVisibleList()
 
 LLCullResult::drawable_list_t::iterator LLCullResult::endVisibleList()
 {
-	return mVisibleList.begin() + mVisibleListSize;
+	return mVisibleListEnd;
 }
 
 LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge()
@@ -3496,7 +3508,7 @@ LLCullResult::bridge_list_t::iterator LLCullResult::beginVisibleBridge()
 
 LLCullResult::bridge_list_t::iterator LLCullResult::endVisibleBridge()
 {
-	return mVisibleBridge.begin() + mVisibleBridgeSize;
+	return mVisibleBridgeEnd;
 }
 
 LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type)
@@ -3506,7 +3518,7 @@ LLCullResult::drawinfo_list_t::iterator LLCullResult::beginRenderMap(U32 type)
 
 LLCullResult::drawinfo_list_t::iterator LLCullResult::endRenderMap(U32 type)
 {
-	return mRenderMap[type].begin() + mRenderMapSize[type];
+	return mRenderMapEnd[type];
 }
 
 void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
@@ -3520,6 +3532,7 @@ void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
 		mVisibleGroups.push_back(group);
 	}
 	++mVisibleGroupsSize;
+	mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize;
 }
 
 void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
@@ -3533,6 +3546,7 @@ void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
 		mAlphaGroups.push_back(group);
 	}
 	++mAlphaGroupsSize;
+	mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize;
 }
 
 void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
@@ -3546,6 +3560,7 @@ void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
 		mOcclusionGroups.push_back(group);
 	}
 	++mOcclusionGroupsSize;
+	mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize;
 }
 
 void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
@@ -3559,6 +3574,7 @@ void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
 		mDrawableGroups.push_back(group);
 	}
 	++mDrawableGroupsSize;
+	mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize;
 }
 
 void LLCullResult::pushDrawable(LLDrawable* drawable)
@@ -3572,6 +3588,7 @@ void LLCullResult::pushDrawable(LLDrawable* drawable)
 		mVisibleList.push_back(drawable);
 	}
 	++mVisibleListSize;
+	mVisibleListEnd = mVisibleList.begin()+mVisibleListSize;
 }
 
 void LLCullResult::pushBridge(LLSpatialBridge* bridge)
@@ -3585,6 +3602,7 @@ void LLCullResult::pushBridge(LLSpatialBridge* bridge)
 		mVisibleBridge.push_back(bridge);
 	}
 	++mVisibleBridgeSize;
+	mVisibleBridgeEnd = mVisibleBridge.begin()+mVisibleBridgeSize;
 }
 
 void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info)
@@ -3598,6 +3616,7 @@ void LLCullResult::pushDrawInfo(U32 type, LLDrawInfo* draw_info)
 		mRenderMap[type].push_back(draw_info);
 	}
 	++mRenderMapSize[type];
+	mRenderMapEnd[type] = mRenderMap[type].begin() + mRenderMapSize[type];
 }
 
 
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 7896488379e0d80dc8aa7f1b808032648117787f..d74216de2d19b7521c3c4c2a048dd53591967144 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -59,6 +59,7 @@ class LLTextureAtlasSlot;
 
 S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad);
 S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared);
+void pushVerts(LLFace* face, U32 mask);
 
 // get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
 U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center);
@@ -346,11 +347,11 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	F32 mBuilt;
 	OctreeNode* mOctreeNode;
 	LLSpatialPartition* mSpatialPartition;
-	LLVector3 mBounds[2];
-	LLVector3 mExtents[2];
+	LLVector3 mBounds[2]; // bounding box (center, size) of this node and all its children (tight fit to objects)
+	LLVector3 mExtents[2]; // extents (min, max) of this node and all its children
 	
-	LLVector3 mObjectExtents[2];
-	LLVector3 mObjectBounds[2];
+	LLVector3 mObjectExtents[2]; // extents (min, max) of objects in this node
+	LLVector3 mObjectBounds[2]; // bounding box (center, size) of objects in this node
 
 	LLPointer<LLVertexBuffer> mVertexBuffer;
 	F32*					mOcclusionVerts;
@@ -534,12 +535,19 @@ class LLCullResult
 	U32					mRenderMapSize[LLRenderPass::NUM_RENDER_TYPES];
 
 	sg_list_t			mVisibleGroups;
+	sg_list_t::iterator mVisibleGroupsEnd;
 	sg_list_t			mAlphaGroups;
+	sg_list_t::iterator mAlphaGroupsEnd;
 	sg_list_t			mOcclusionGroups;
+	sg_list_t::iterator	mOcclusionGroupsEnd;
 	sg_list_t			mDrawableGroups;
+	sg_list_t::iterator mDrawableGroupsEnd;
 	drawable_list_t		mVisibleList;
+	drawable_list_t::iterator mVisibleListEnd;
 	bridge_list_t		mVisibleBridge;
+	bridge_list_t::iterator mVisibleBridgeEnd;
 	drawinfo_list_t		mRenderMap[LLRenderPass::NUM_RENDER_TYPES];
+	drawinfo_list_t::iterator mRenderMapEnd[LLRenderPass::NUM_RENDER_TYPES];
 };
 
 
@@ -606,14 +614,15 @@ class LLCloudPartition : public LLParticlePartition
 //class for wrangling geometry out of volumes (implemented in LLVOVolume.cpp)
 class LLVolumeGeometryManager: public LLGeometryManager
 {
-public:
+ public:
 	virtual ~LLVolumeGeometryManager() { }
 	virtual void rebuildGeom(LLSpatialGroup* group);
 	virtual void rebuildMesh(LLSpatialGroup* group);
 	virtual void getGeometry(LLSpatialGroup* group);
 	void genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort = FALSE);
 	void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type);
-
+ private:
+	bool canRenderAsMask(LLFace* facep); // logic helper
 };
 
 //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp)
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index a1b3c8dabd5e52c50a1093e87564206e08c5d611..5381f8291a22db647813aad8eda30958489e82f6 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -292,7 +292,7 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop(
 {
 	BOOL handled = FALSE;
 
-	if (cargo_type == DAD_TEXTURE)
+	if ((cargo_type == DAD_TEXTURE) || (cargo_type == DAD_MESH))
 	{
 		LLInventoryItem *item = (LLInventoryItem *)cargo_data;
 
@@ -1163,7 +1163,9 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask,
 	// returns true, then the cast was valid, and we can perform
 	// the third test without problems.
 	LLInventoryItem* item = (LLInventoryItem*)cargo_data; 
-	if (getEnabled() && (cargo_type == DAD_TEXTURE) && allowDrop(item))
+	if (getEnabled() &&
+		((cargo_type == DAD_TEXTURE) || (cargo_type == DAD_MESH)) &&
+		 allowDrop(item))
 	{
 		if (drop)
 		{
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 394f550f2e6b2218ecd469caeada80e10a8c436f..84b2caeddd18df5feb2a31d3e824db03ad38df2d 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -387,6 +387,7 @@ LLToolDragAndDrop::LLDragAndDropDictionary::LLDragAndDropDictionary()
 	addEntry(DAD_ANIMATION, 	new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dGiveInventory,		&LLToolDragAndDrop::dad3dUpdateInventory,			&LLToolDragAndDrop::dad3dNULL));
 	addEntry(DAD_GESTURE, 		new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dActivateGesture,		&LLToolDragAndDrop::dad3dGiveInventory,		&LLToolDragAndDrop::dad3dUpdateInventory,			&LLToolDragAndDrop::dad3dNULL));
 	addEntry(DAD_LINK, 			new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dNULL,						&LLToolDragAndDrop::dad3dNULL));
+	addEntry(DAD_MESH, 			new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dGiveInventory,		&LLToolDragAndDrop::dad3dMeshObject,			&LLToolDragAndDrop::dad3dNULL));
 	// TODO: animation on self could play it?  edit it?
 	// TODO: gesture on self could play it?  edit it?
 };
@@ -456,7 +457,7 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type,
 			{
 				folder_ids.push_back(cargo_id);
 			}
-			gInventory.collectDescendentsIf (
+			gInventory.collectDescendentsIf(
 				cargo_id,
 				cats,
 				items,
@@ -526,7 +527,7 @@ void LLToolDragAndDrop::beginMultiDrag(
 				{
 					cat_ids.insert(cat->getUUID());
 				}
-				gInventory.collectDescendentsIf (
+				gInventory.collectDescendentsIf(
 					cat->getUUID(),
 					cats,
 					items,
@@ -1087,6 +1088,31 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj,
 	hit_obj->sendTEUpdate();
 }
 
+void LLToolDragAndDrop::dropMesh(LLViewerObject* hit_obj,
+								 LLInventoryItem* item,
+								 LLToolDragAndDrop::ESource source,
+								 const LLUUID& src_id)
+{
+	if (!item)
+	{
+		llwarns << "no inventory item." << llendl;
+		return;
+	}
+	LLUUID asset_id = item->getAssetUUID();
+	BOOL success = handleDropTextureProtections(hit_obj, item, source, src_id);
+	if(!success)
+	{
+		return;
+	}
+
+	LLSculptParams sculpt_params;
+	sculpt_params.setSculptTexture(asset_id);
+	sculpt_params.setSculptType(LL_SCULPT_TYPE_MESH);
+	hit_obj->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, TRUE);
+	
+	dialog_refresh_all();
+}
+
 /*
 void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item)
 {
@@ -1183,9 +1209,9 @@ void LLToolDragAndDrop::dropScript(LLViewerObject* hit_obj,
 }
 
 void LLToolDragAndDrop::dropObject(LLViewerObject* raycast_target,
-								   BOOL bypass_sim_raycast,
-								   BOOL from_task_inventory,
-								   BOOL remove_from_inventory)
+				   BOOL bypass_sim_raycast,
+				   BOOL from_task_inventory,
+				   BOOL remove_from_inventory)
 {
 	LLViewerRegion* regionp = LLWorld::getInstance()->getRegionFromPosGlobal(mLastHitPos);
 	if (!regionp)
@@ -1548,13 +1574,17 @@ void LLToolDragAndDrop::giveInventoryCategory(const LLUUID& to_agent,
 	llinfos << "LLToolDragAndDrop::giveInventoryCategory() - "
 			<< cat->getUUID() << llendl;
 
-	if (!isAgentAvatarValid()) return;
+	LLVOAvatar* my_avatar = gAgentAvatarp;
+	if( !my_avatar )
+	{
+		return;
+	}
 
 	// Test out how many items are being given.
 	LLViewerInventoryCategory::cat_array_t cats;
 	LLViewerInventoryItem::item_array_t items;
 	LLGiveable giveable;
-	gInventory.collectDescendentsIf (cat->getUUID(),
+	gInventory.collectDescendentsIf(cat->getUUID(),
 									cats,
 									items,
 									LLInventoryModel::EXCLUDE_TRASH,
@@ -1620,7 +1650,7 @@ bool LLToolDragAndDrop::handleCopyProtectedCategory(const LLSD& notification, co
 			LLViewerInventoryCategory::cat_array_t cats;
 			LLViewerInventoryItem::item_array_t items;
 			LLUncopyableItems remove;
-			gInventory.collectDescendentsIf (cat->getUUID(),
+			gInventory.collectDescendentsIf(cat->getUUID(),
 											cats,
 											items,
 											LLInventoryModel::EXCLUDE_TRASH,
@@ -1662,7 +1692,7 @@ void LLToolDragAndDrop::commitGiveInventoryCategory(const LLUUID& to_agent,
 	LLViewerInventoryCategory::cat_array_t cats;
 	LLViewerInventoryItem::item_array_t items;
 	LLGiveable giveable;
-	gInventory.collectDescendentsIf (cat->getUUID(),
+	gInventory.collectDescendentsIf(cat->getUUID(),
 									cats,
 									items,
 									LLInventoryModel::EXCLUDE_TRASH,
@@ -1762,20 +1792,24 @@ BOOL LLToolDragAndDrop::isInventoryGiveAcceptable(LLInventoryItem* item)
 	BOOL copyable = FALSE;
 	if (item->getPermissions().allowCopyBy(gAgent.getID())) copyable = TRUE;
 
-	if (!isAgentAvatarValid()) return FALSE;
+	LLVOAvatarSelf* my_avatar = gAgentAvatarp;
+	if(!my_avatar)
+	{
+		return FALSE;
+	}
 
 	BOOL acceptable = TRUE;
 	switch(item->getType())
 	{
 	case LLAssetType::AT_OBJECT:
-		if (gAgentAvatarp->isWearingAttachment(item->getUUID()))
+		if(my_avatar->isWearingAttachment(item->getUUID()))
 		{
 			acceptable = FALSE;
 		}
 		break;
 	case LLAssetType::AT_BODYPART:
 	case LLAssetType::AT_CLOTHING:
-		if (!copyable && gAgentWearables.isWearingItem(item->getUUID()))
+		if(!copyable && gAgentWearables.isWearingItem(item->getUUID()))
 		{
 			acceptable = FALSE;
 		}
@@ -1789,29 +1823,33 @@ BOOL LLToolDragAndDrop::isInventoryGiveAcceptable(LLInventoryItem* item)
 // Static
 BOOL LLToolDragAndDrop::isInventoryGroupGiveAcceptable(LLInventoryItem* item)
 {
-	if (!item)
+	if(!item)
 	{
 		return FALSE;
 	}
 
 	// These permissions are double checked in the simulator in
 	// LLGroupNoticeInventoryItemFetch::result().
-	if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
+	if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
 	{
 		return FALSE;
 	}
-	if (!item->getPermissions().allowCopyBy(gAgent.getID()))
+	if(!item->getPermissions().allowCopyBy(gAgent.getID()))
 	{
 		return FALSE;
 	}
 
-	if (!isAgentAvatarValid()) return FALSE;
+	LLVOAvatarSelf* my_avatar = gAgentAvatarp;
+	if(!my_avatar)
+	{
+		return FALSE;
+	}
 
 	BOOL acceptable = TRUE;
 	switch(item->getType())
 	{
 	case LLAssetType::AT_OBJECT:
-		if (gAgentAvatarp->isWearingAttachment(item->getUUID()))
+		if(my_avatar->isWearingAttachment(item->getUUID()))
 		{
 			acceptable = FALSE;
 		}
@@ -1837,7 +1875,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
 	// help make sure that drops that are from an object to an object
 	// don't have to worry about order of evaluation. Think of this
 	// like check for self in assignment.
-	if (obj->getID() == item->getParentUUID())
+	if(obj->getID() == item->getParentUUID())
 	{
 		return ACCEPT_NO;
 	}
@@ -1846,17 +1884,19 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
 	//							  gAgent.getGroupID())
 	//			 && (obj->mPermModify || obj->mFlagAllowInventoryAdd));
 	BOOL worn = FALSE;
+	LLVOAvatarSelf* my_avatar = NULL;
 	switch(item->getType())
 	{
 	case LLAssetType::AT_OBJECT:
-		if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getUUID()))
+		my_avatar = gAgentAvatarp;
+		if(my_avatar && my_avatar->isWearingAttachment(item->getUUID()))
 		{
 				worn = TRUE;
 		}
 		break;
 	case LLAssetType::AT_BODYPART:
 	case LLAssetType::AT_CLOTHING:
-		if (gAgentWearables.isWearingItem(item->getUUID()))
+		if(gAgentWearables.isWearingItem(item->getUUID()))
 		{
 			worn = TRUE;
 		}
@@ -1867,7 +1907,7 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
 	const LLPermissions& perm = item->getPermissions();
 	BOOL modify = (obj->permModify() || obj->flagAllowInventoryAdd());
 	BOOL transfer = FALSE;
-	if ((obj->permYouOwner() && (perm.getOwner() == gAgent.getID()))
+	if((obj->permYouOwner() && (perm.getOwner() == gAgent.getID()))
 	   || perm.allowOperationBy(PERM_TRANSFER, gAgent.getID()))
 	{
 		transfer = TRUE;
@@ -1875,15 +1915,15 @@ EAcceptance LLToolDragAndDrop::willObjectAcceptInventory(LLViewerObject* obj, LL
 	BOOL volume = (LL_PCODE_VOLUME == obj->getPCode());
 	BOOL attached = obj->isAttachment();
 	BOOL unrestricted = ((perm.getMaskBase() & PERM_ITEM_UNRESTRICTED) == PERM_ITEM_UNRESTRICTED) ? TRUE : FALSE;
-	if (attached && !unrestricted)
+	if(attached && !unrestricted)
 	{
 		return ACCEPT_NO_LOCKED;
 	}
-	else if (modify && transfer && volume && !worn)
+	else if(modify && transfer && volume && !worn)
 	{
 		return ACCEPT_YES_MULTI;
 	}
-	else if (!modify)
+	else if(!modify)
 	{
 		return ACCEPT_NO_LOCKED;
 	}
@@ -1912,14 +1952,15 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_
 	case DAD_ANIMATION:
 	case DAD_GESTURE:
 	case DAD_CALLINGCARD:
+	case DAD_MESH:
 	{
 		LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
-		if (gInventory.getItem(inv_item->getUUID())
+		if(gInventory.getItem(inv_item->getUUID())
 		   && LLToolDragAndDrop::isInventoryGiveAcceptable(inv_item))
 		{
 			// *TODO: get multiple object transfers working
 			*accept = ACCEPT_YES_COPY_SINGLE;
-			if (drop)
+			if(drop)
 			{
 				LLToolDragAndDrop::giveInventory(dest_agent, inv_item, session_id);
 			}
@@ -1937,11 +1978,11 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_
 	case DAD_CATEGORY:
 	{
 		LLViewerInventoryCategory* inv_cat = (LLViewerInventoryCategory*)cargo_data;
-		if (gInventory.getCategory(inv_cat->getUUID()))
+		if( gInventory.getCategory( inv_cat->getUUID() ) )
 		{
 			// *TODO: get multiple object transfers working
 			*accept = ACCEPT_YES_COPY_SINGLE;
-			if (drop)
+			if(drop)
 			{
 				LLToolDragAndDrop::giveInventoryCategory(dest_agent, inv_cat, session_id);
 			}
@@ -1982,7 +2023,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
 {
 	lldebugs << "LLToolDragAndDrop::dad3dRezAttachmentFromInv()" << llendl;
 	// must be in the user's inventory
-	if (mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
+	if(mSource != SOURCE_AGENT && mSource != SOURCE_LIBRARY)
 	{
 		return ACCEPT_NO;
 	}
@@ -1990,24 +2031,25 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
+	if(!item || !item->isComplete()) return ACCEPT_NO;
 
 	// must not be in the trash
 	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
-	if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+	if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
 	{
 		return ACCEPT_NO;
 	}
 
 	// must not be already wearing it
-	if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID()))
+	LLVOAvatarSelf* avatar = gAgentAvatarp;
+	if( !avatar || avatar->isWearingAttachment(item->getUUID()) )
 	{
 		return ACCEPT_NO;
 	}
 
-	if (drop)
+	if( drop )
 	{
-		if (mSource == SOURCE_LIBRARY)
+		if(mSource == SOURCE_LIBRARY)
 		{
 			LLPointer<LLInventoryCallback> cb = new RezAttachmentCallback(0);
 			copy_inventory_item(
@@ -2039,9 +2081,10 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
+	if(!item || !item->isComplete()) return ACCEPT_NO;
 
-	if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID()))
+	LLVOAvatarSelf* my_avatar = gAgentAvatarp;
+	if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
 	{
 		return ACCEPT_NO;
 	}
@@ -2066,7 +2109,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
 
 	// check if the item can be copied. If not, send that to the sim
 	// which will remove the inventory item.
-	if (!item->getPermissions().allowCopyBy(gAgent.getID()))
+	if(!item->getPermissions().allowCopyBy(gAgent.getID()))
 	{
 		accept = ACCEPT_YES_SINGLE;
 		remove_inventory = TRUE;
@@ -2074,13 +2117,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
 
 	// Check if it's in the trash.
 	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
-	if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+	if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
 	{
 		accept = ACCEPT_YES_SINGLE;
 		remove_inventory = TRUE;
 	}
 
-	if (drop)
+	if(drop)
 	{
 		dropObject(obj, TRUE, FALSE, remove_inventory);
 	}
@@ -2101,23 +2144,24 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
-	if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID()))
+	if(!item || !item->isComplete()) return ACCEPT_NO;
+	LLVOAvatarSelf* my_avatar = gAgentAvatarp;
+	if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
 	{
 		return ACCEPT_NO;
 	}
 
-	if ((mask & MASK_CONTROL))
+	if((mask & MASK_CONTROL))
 	{
 		// *HACK: In order to resolve SL-22177, we need to block drags
 		// from notecards and objects onto other objects.
-		if (mSource == SOURCE_NOTECARD)
+		if(mSource == SOURCE_NOTECARD)
 		{
 			return ACCEPT_NO;
 		}
 
 		EAcceptance rv = willObjectAcceptInventory(obj, item);
-		if (drop && (ACCEPT_YES_SINGLE <= rv))
+		if(drop && (ACCEPT_YES_SINGLE <= rv))
 		{
 			dropInventory(obj, item, mSource, mSourceID);
 		}
@@ -2143,7 +2187,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
 	
 	// check if the item can be copied. If not, send that to the sim
 	// which will remove the inventory item.
-	if (!item->getPermissions().allowCopyBy(gAgent.getID()))
+	if(!item->getPermissions().allowCopyBy(gAgent.getID()))
 	{
 		accept = ACCEPT_YES_SINGLE;
 		remove_inventory = TRUE;
@@ -2151,13 +2195,13 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
 
 	// Check if it's in the trash.
 	const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
-	if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+	if(gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
 	{
 		accept = ACCEPT_YES_SINGLE;
 		remove_inventory = TRUE;
 	}
 
-	if (drop)
+	if(drop)
 	{
 		dropObject(obj, FALSE, FALSE, remove_inventory);
 	}
@@ -2172,7 +2216,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript(
 
 	// *HACK: In order to resolve SL-22177, we need to block drags
 	// from notecards and objects onto other objects.
-	if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
+	if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
 	{
 		return ACCEPT_NO;
 	}
@@ -2180,9 +2224,9 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
+	if(!item || !item->isComplete()) return ACCEPT_NO;
 	EAcceptance rv = willObjectAcceptInventory(obj, item);
-	if (drop && (ACCEPT_YES_SINGLE <= rv))
+	if(drop && (ACCEPT_YES_SINGLE <= rv))
 	{
 		// rez in the script active by default, rez in inactive if the
 		// control key is being held down.
@@ -2203,14 +2247,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript(
 	return rv;
 }
 
-EAcceptance LLToolDragAndDrop::dad3dTextureObject(
-	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
+EAcceptance LLToolDragAndDrop::dad3dApplyToObject(
+	LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type)
 {
-	lldebugs << "LLToolDragAndDrop::dad3dTextureObject()" << llendl;
+	lldebugs << "LLToolDragAndDrop::dad3dApplyToObject()" << llendl;
 
 	// *HACK: In order to resolve SL-22177, we need to block drags
 	// from notecards and objects onto other objects.
-	if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
+	if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
 	{
 		return ACCEPT_NO;
 	}
@@ -2218,35 +2262,46 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
+	if(!item || !item->isComplete()) return ACCEPT_NO;
 	EAcceptance rv = willObjectAcceptInventory(obj, item);
-	if ((mask & MASK_CONTROL))
+	if((mask & MASK_CONTROL))
 	{
-		if ((ACCEPT_YES_SINGLE <= rv) && drop)
+		if((ACCEPT_YES_SINGLE <= rv) && drop)
 		{
 			dropInventory(obj, item, mSource, mSourceID);
 		}
 		return rv;
 	}
-	if (!obj->permModify())
+	if(!obj->permModify())
 	{
 		return ACCEPT_NO_LOCKED;
 	}
 	//If texture !copyable don't texture or you'll never get it back.
-	if (!item->getPermissions().allowCopyBy(gAgent.getID()))
+	if(!item->getPermissions().allowCopyBy(gAgent.getID()))
 	{
 		return ACCEPT_NO;
 	}
 
-	if (drop && (ACCEPT_YES_SINGLE <= rv))
+	if(drop && (ACCEPT_YES_SINGLE <= rv))
 	{
-		if ((mask & MASK_SHIFT))
+		if (cargo_type == DAD_TEXTURE)
 		{
-			dropTextureAllFaces(obj, item, mSource, mSourceID);
+			if((mask & MASK_SHIFT))
+			{
+				dropTextureAllFaces(obj, item, mSource, mSourceID);
+			}
+			else
+			{
+				dropTextureOneFace(obj, face, item, mSource, mSourceID);
+			}
+		}
+		else if (cargo_type == DAD_MESH)
+		{
+			dropMesh(obj, item, mSource, mSourceID);
 		}
 		else
 		{
-			dropTextureOneFace(obj, face, item, mSource, mSourceID);
+			llwarns << "unsupported asset type" << llendl;
 		}
 		
 		// VEFFECT: SetTexture
@@ -2260,14 +2315,31 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject(
 	// enable multi-drop, although last texture will win
 	return ACCEPT_YES_MULTI;
 }
+
+
+EAcceptance LLToolDragAndDrop::dad3dTextureObject(
+	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
+{
+	return dad3dApplyToObject(obj, face, mask, drop, DAD_TEXTURE);
+}
+
+EAcceptance LLToolDragAndDrop::dad3dMeshObject(
+	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
+{
+	return dad3dApplyToObject(obj, face, mask, drop, DAD_MESH);
+}
+
+
+
+
 /*
 EAcceptance LLToolDragAndDrop::dad3dTextureSelf(
 	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
 {
 	lldebugs << "LLToolDragAndDrop::dad3dTextureAvatar()" << llendl;
-	if (drop)
+	if(drop)
 	{
-		if (!(mask & MASK_SHIFT))
+		if( !(mask & MASK_SHIFT) )
 		{
 			dropTextureOneFaceAvatar( (LLVOAvatar*)obj, face, (LLInventoryItem*)mCargoData);
 		}
@@ -2283,18 +2355,18 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
+	if(!item || !item->isComplete()) return ACCEPT_NO;
 
-	if (mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
+	if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
 	{
 		// it's in the agent inventory
 		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
-		if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+		if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
 		{
 			return ACCEPT_NO;
 		}
 
-		if (drop)
+		if( drop )
 		{
 			// Don't wear anything until initial wearables are loaded, can
 			// destroy clothing items.
@@ -2304,7 +2376,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem(
 				return ACCEPT_NO;
 			}
 
-			if (mSource == SOURCE_LIBRARY)
+			if(mSource == SOURCE_LIBRARY)
 			{
 				// create item based on that one, and put it on if that
 				// was a success.
@@ -2338,21 +2410,21 @@ EAcceptance LLToolDragAndDrop::dad3dActivateGesture(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
+	if(!item || !item->isComplete()) return ACCEPT_NO;
 
-	if (mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
+	if(mSource == SOURCE_AGENT || mSource == SOURCE_LIBRARY)
 	{
 		// it's in the agent inventory
 		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
-		if (gInventory.isObjectDescendentOf(item->getUUID(), trash_id))
+		if( gInventory.isObjectDescendentOf( item->getUUID(), trash_id ) )
 		{
 			return ACCEPT_NO;
 		}
 
-		if (drop)
+		if( drop )
 		{
 			LLUUID item_id;
-			if (mSource == SOURCE_LIBRARY)
+			if(mSource == SOURCE_LIBRARY)
 			{
 				// create item based on that one, and put it on if that
 				// was a success.
@@ -2387,7 +2459,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* category;
 	locateInventory(item, category);
-	if (!category) return ACCEPT_NO;
+	if(!category) return ACCEPT_NO;
 
 	if (drop)
 	{
@@ -2400,24 +2472,24 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
 		}
 	}
 
-	if (mSource == SOURCE_AGENT)
+	if(mSource == SOURCE_AGENT)
 	{
 		const LLUUID trash_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
-		if (gInventory.isObjectDescendentOf(category->getUUID(), trash_id))
+		if( gInventory.isObjectDescendentOf( category->getUUID(), trash_id ) )
 		{
 			return ACCEPT_NO;
 		}
 
-		if (drop)
+		if(drop)
 		{
-		    BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
+			BOOL append = ( (mask & MASK_SHIFT) ? TRUE : FALSE );
 			LLAppearanceMgr::instance().wearInventoryCategory(category, false, append);
 		}
 		return ACCEPT_YES_MULTI;
 	}
-	else if (mSource == SOURCE_LIBRARY)
+	else if(mSource == SOURCE_LIBRARY)
 	{
-		if (drop)
+		if(drop)
 		{
 			LLAppearanceMgr::instance().wearInventoryCategory(category, true, false);
 		}
@@ -2438,7 +2510,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory(
 
 	// *HACK: In order to resolve SL-22177, we need to block drags
 	// from notecards and objects onto other objects.
-	if ((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
+	if((SOURCE_WORLD == mSource) || (SOURCE_NOTECARD == mSource))
 	{
 		return ACCEPT_NO;
 	}
@@ -2446,7 +2518,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
+	if(!item || !item->isComplete()) return ACCEPT_NO;
 	LLViewerObject* root_object = obj;
 	if (obj && obj->getParent())
 	{
@@ -2458,7 +2530,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventory(
 	}
 
 	EAcceptance rv = willObjectAcceptInventory(root_object, item);
-	if (root_object && drop && (ACCEPT_YES_COPY_SINGLE <= rv))
+	if(root_object && drop && (ACCEPT_YES_COPY_SINGLE <= rv))
 	{
 		dropInventory(root_object, item, mSource, mSourceID);
 	}
@@ -2502,7 +2574,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory(
 	LLDroppableItem droppable(!obj->permYouOwner());
 	LLInventoryModel::cat_array_t cats;
 	LLInventoryModel::item_array_t items;
-	gInventory.collectDescendentsIf (cat->getUUID(),
+	gInventory.collectDescendentsIf(cat->getUUID(),
 					cats,
 					items,
 					LLInventoryModel::EXCLUDE_TRASH,
@@ -2531,7 +2603,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory(
 	{
 		const LLViewerInventoryCategory *cat = (*cat_iter);
 		rv = gInventory.isCategoryComplete(cat->getUUID()) ? ACCEPT_YES_MULTI : ACCEPT_NO;
-		if (rv < ACCEPT_YES_SINGLE)
+		if(rv < ACCEPT_YES_SINGLE)
 		{
 			lldebugs << "Category " << cat->getUUID() << "is not complete." << llendl;
 			break;
@@ -2574,7 +2646,7 @@ EAcceptance LLToolDragAndDrop::dad3dUpdateInventoryCategory(
 		}
 		LLCategoryDropObserver* dropper = new LLCategoryDropObserver(obj->getID(), mSource);
 		dropper->fetchItems(ids);
-		if (dropper->isEverythingComplete())
+		if(dropper->isEverythingComplete())
 		{
 			dropper->done();
 		}
@@ -2599,26 +2671,27 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryObject(
 	lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryObject()" << llendl;
 
 	// item has to be in agent inventory.
-	if (mSource != SOURCE_AGENT) return ACCEPT_NO;
+	if(mSource != SOURCE_AGENT) return ACCEPT_NO;
 
 	// find the item now.
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
-	if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
+	if(!item || !item->isComplete()) return ACCEPT_NO;
+	if(!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
 	{
 		// cannot give away no-transfer objects
 		return ACCEPT_NO;
 	}
-	if (isAgentAvatarValid() && gAgentAvatarp->isWearingAttachment(item->getUUID()))
+	LLVOAvatarSelf* avatar = gAgentAvatarp;
+	if(avatar && avatar->isWearingAttachment( item->getUUID() ) )
 	{
 		// You can't give objects that are attached to you
 		return ACCEPT_NO;
 	}
-	if (obj && isAgentAvatarValid())
+	if( obj && avatar )
 	{
-		if (drop)
+		if(drop)
 		{
 			giveInventory(obj->getID(), item );
 		}
@@ -2635,16 +2708,16 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventory(
 {
 	lldebugs << "LLToolDragAndDrop::dad3dGiveInventory()" << llendl;
 	// item has to be in agent inventory.
-	if (mSource != SOURCE_AGENT) return ACCEPT_NO;
+	if(mSource != SOURCE_AGENT) return ACCEPT_NO;
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
-	if (!isInventoryGiveAcceptable(item))
+	if(!item || !item->isComplete()) return ACCEPT_NO;
+	if(!isInventoryGiveAcceptable(item))
 	{
 		return ACCEPT_NO;
 	}
-	if (drop && obj)
+	if(drop && obj)
 	{
 		giveInventory(obj->getID(), item);
 	}
@@ -2657,12 +2730,12 @@ EAcceptance LLToolDragAndDrop::dad3dGiveInventoryCategory(
 	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
 {
 	lldebugs << "LLToolDragAndDrop::dad3dGiveInventoryCategory()" << llendl;
-	if (drop && obj)
+	if(drop && obj)
 	{
 		LLViewerInventoryItem* item;
 		LLViewerInventoryCategory* cat;
 		locateInventory(item, cat);
-		if (!cat) return ACCEPT_NO;
+		if(!cat) return ACCEPT_NO;
 		giveInventoryCategory(obj->getID(), cat);
 	}
 	// *TODO: deal with all the issues surrounding multi-object
@@ -2678,14 +2751,14 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand(
 	LLViewerInventoryItem* item = NULL;
 	LLViewerInventoryCategory* cat = NULL;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
+	if(!item || !item->isComplete()) return ACCEPT_NO;
 
-	if (!gAgent.allowOperation(PERM_COPY, item->getPermissions())
+	if(!gAgent.allowOperation(PERM_COPY, item->getPermissions())
 		|| !item->getPermissions().allowTransferTo(LLUUID::null))
 	{
 		return ACCEPT_NO_LOCKED;
 	}
-	if (drop)
+	if(drop)
 	{
 		dropObject(obj, TRUE, TRUE, FALSE);
 	}
@@ -2699,8 +2772,8 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!item || !item->isComplete()) return ACCEPT_NO;
-	if ((mask & MASK_CONTROL))
+	if(!item || !item->isComplete()) return ACCEPT_NO;
+	if((mask & MASK_CONTROL))
 	{
 		// *HACK: In order to resolve SL-22177, we need to block drags
 		// from notecards and objects onto other objects.
@@ -2708,19 +2781,19 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject(
 
 		// *HACK: uncomment this when appropriate
 		//EAcceptance rv = willObjectAcceptInventory(obj, item);
-		//if (drop && (ACCEPT_YES_SINGLE <= rv))
+		//if(drop && (ACCEPT_YES_SINGLE <= rv))
 		//{
 		//	dropInventory(obj, item, mSource, mSourceID);
 		//}
 		//return rv;
 	}
-	if (!item->getPermissions().allowCopyBy(gAgent.getID(),
+	if(!item->getPermissions().allowCopyBy(gAgent.getID(),
 										   gAgent.getGroupID())
 	   || !item->getPermissions().allowTransferTo(LLUUID::null))
 	{
 		return ACCEPT_NO_LOCKED;
 	}
-	if (drop)
+	if(drop)
 	{
 		dropObject(obj, FALSE, TRUE, FALSE);
 	}
@@ -2736,23 +2809,23 @@ EAcceptance LLToolDragAndDrop::dad3dCategoryOnLand(
 	LLInventoryItem* item;
 	LLInventoryCategory* cat;
 	locateInventory(item, cat);
-	if (!cat) return ACCEPT_NO;
+	if(!cat) return ACCEPT_NO;
 	EAcceptance rv = ACCEPT_NO;
 
 	// find all the items in the category
 	LLViewerInventoryCategory::cat_array_t cats;
 	LLViewerInventoryItem::item_array_t items;
 	LLDropCopyableItems droppable;
-	gInventory.collectDescendentsIf (cat->getUUID(),
+	gInventory.collectDescendentsIf(cat->getUUID(),
 									cats,
 									items,
 									LLInventoryModel::EXCLUDE_TRASH,
 									droppable);
-	if (items.count() > 0)
+	if(items.count() > 0)
 	{
 		rv = ACCEPT_YES_SINGLE;
 	}
-	if ((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
+	if((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
 	{
 		createContainer(items, cat->getName());
 		return ACCEPT_NO;
@@ -2775,19 +2848,19 @@ EAcceptance LLToolDragAndDrop::dad3dAssetOnLand(
 	LLViewerInventoryItem::item_array_t items;
 	LLViewerInventoryItem::item_array_t copyable_items;
 	locateMultipleInventory(items, cats);
-	if (!items.count()) return ACCEPT_NO;
+	if(!items.count()) return ACCEPT_NO;
 	EAcceptance rv = ACCEPT_NO;
 	for (S32 i = 0; i < items.count(); i++)
 	{
 		LLInventoryItem* item = items[i];
-		if (item->getPermissions().allowCopyBy(gAgent.getID()))
+		if(item->getPermissions().allowCopyBy(gAgent.getID()))
 		{
 			copyable_items.put(item);
 			rv = ACCEPT_YES_SINGLE;
 		}
 	}
 
-	if ((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
+	if((rv >= ACCEPT_YES_COPY_SINGLE) && drop)
 	{
 		createContainer(copyable_items, NULL);
 	}
@@ -2802,20 +2875,20 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory(
 {
 	item = NULL;
 	cat = NULL;
-	if (mCargoIDs.empty()) return NULL;
-	if ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
+	if(mCargoIDs.empty()) return NULL;
+	if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
 	{
 		// The object should be in user inventory.
 		item = (LLViewerInventoryItem*)gInventory.getItem(mCargoIDs[mCurItemIndex]);
 		cat = (LLViewerInventoryCategory*)gInventory.getCategory(mCargoIDs[mCurItemIndex]);
 	}
-	else if (mSource == SOURCE_WORLD)
+	else if(mSource == SOURCE_WORLD)
 	{
 		// This object is in some task inventory somewhere.
 		LLViewerObject* obj = gObjectList.findObject(mSourceID);
-		if (obj)
+		if(obj)
 		{
-			if ((mCargoTypes[mCurItemIndex] == DAD_CATEGORY)
+			if((mCargoTypes[mCurItemIndex] == DAD_CATEGORY)
 			   || (mCargoTypes[mCurItemIndex] == DAD_ROOT_CATEGORY))
 			{
 				cat = (LLViewerInventoryCategory*)obj->getInventoryObject(mCargoIDs[mCurItemIndex]);
@@ -2826,16 +2899,16 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory(
 			}
 		}
 	}
-	else if (mSource == SOURCE_NOTECARD)
+	else if(mSource == SOURCE_NOTECARD)
 	{
 		LLPreviewNotecard* preview = LLFloaterReg::findTypedInstance<LLPreviewNotecard>("preview_notecard", mSourceID);
-		if (preview)
+		if(preview)
 		{
 			item = (LLViewerInventoryItem*)preview->getDragItem();
 		}
 	}
-	if (item) return item;
-	if (cat) return cat;
+	if(item) return item;
+	if(cat) return cat;
 	return NULL;
 }
 
@@ -2843,8 +2916,8 @@ LLInventoryObject* LLToolDragAndDrop::locateInventory(
 LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryCategory::cat_array_t& cats,
 															  LLViewerInventoryItem::item_array_t& items)
 {
-	if (mCargoIDs.count() == 0) return NULL;
-	if ((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
+	if(mCargoIDs.count() == 0) return NULL;
+	if((mSource == SOURCE_AGENT) || (mSource == SOURCE_LIBRARY))
 	{
 		// The object should be in user inventory.
 		for (S32 i = 0; i < mCargoIDs.count(); i++)
@@ -2861,13 +2934,13 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC
 			}
 		}
 	}
-	else if (mSource == SOURCE_WORLD)
+	else if(mSource == SOURCE_WORLD)
 	{
 		// This object is in some task inventory somewhere.
 		LLViewerObject* obj = gObjectList.findObject(mSourceID);
-		if (obj)
+		if(obj)
 		{
-			if ((mCargoType == DAD_CATEGORY)
+			if((mCargoType == DAD_CATEGORY)
 			   || (mCargoType == DAD_ROOT_CATEGORY))
 			{
 				// The object should be in user inventory.
@@ -2893,17 +2966,17 @@ LLInventoryObject* LLToolDragAndDrop::locateMultipleInventory(LLViewerInventoryC
 			}
 		}
 	}
-	else if (mSource == SOURCE_NOTECARD)
+	else if(mSource == SOURCE_NOTECARD)
 	{
 		LLPreviewNotecard* card;
 		card = (LLPreviewNotecard*)LLPreview::find(mSourceID);
-		if (card)
+		if(card)
 		{
 			items.put((LLInventoryItem*)card->getDragItem());
 		}
 	}
-	if (items.count()) return items[0];
-	if (cats.count()) return cats[0];
+	if(items.count()) return items[0];
+	if(cats.count()) return cats[0];
 	return NULL;
 }
 */
diff --git a/indra/newview/lltooldraganddrop.h b/indra/newview/lltooldraganddrop.h
index 85d003e5fccb94094eba1533a89d997e9df44e0a..27e235299c922c120848de48c0240285be849f83 100644
--- a/indra/newview/lltooldraganddrop.h
+++ b/indra/newview/lltooldraganddrop.h
@@ -154,6 +154,8 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 							   MASK mask, BOOL drop);
 	EAcceptance dad3dTextureObject(LLViewerObject* obj, S32 face,
 								   MASK mask, BOOL drop);
+	EAcceptance dad3dMeshObject(LLViewerObject* obj, S32 face,
+								   MASK mask, BOOL drop);
 //	EAcceptance dad3dTextureSelf(LLViewerObject* obj, S32 face,
 //								 MASK mask, BOOL drop);
 	EAcceptance dad3dWearItem(LLViewerObject* obj, S32 face,
@@ -185,6 +187,11 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 	EAcceptance dad3dActivateGesture(LLViewerObject *obj, S32 face,
 								 MASK mask, BOOL drop);
 
+	// helper called by methods above to handle "application" of an item
+	// to an object (texture applied to face, mesh applied to shape, etc.)
+	EAcceptance dad3dApplyToObject(LLViewerObject* obj, S32 face, MASK mask, BOOL drop, EDragAndDropType cargo_type);
+		
+	
 	// set the LLToolDragAndDrop's cursor based on the given acceptance
 	ECursorType acceptanceToCursor( EAcceptance acceptance );
 
@@ -257,6 +264,11 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 									LLInventoryItem* item,
 									ESource source,
 									const LLUUID& src_id);
+	static void dropMesh(LLViewerObject* hit_obj,
+						 LLInventoryItem* item,
+						 ESource source,
+						 const LLUUID& src_id);
+	
 	//static void	dropTextureOneFaceAvatar(LLVOAvatar* avatar,S32 hit_face,
 	//									 LLInventoryItem* item)
 
diff --git a/indra/newview/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp
index b382ff630699c4d3107a2a731ffe6cf9af6b3f13..4c088a72b7fa7d7e230daf2503458c95b90e4d63 100644
--- a/indra/newview/llviewerassettype.cpp
+++ b/indra/newview/llviewerassettype.cpp
@@ -85,6 +85,8 @@ LLViewerAssetDictionary::LLViewerAssetDictionary()
 	addEntry(LLViewerAssetType::AT_LINK, 				new ViewerAssetEntry(DAD_LINK));
 	addEntry(LLViewerAssetType::AT_LINK_FOLDER, 		new ViewerAssetEntry(DAD_LINK));
 
+	addEntry(LLViewerAssetType::AT_MESH, 				new ViewerAssetEntry(DAD_MESH));
+
 	addEntry(LLViewerAssetType::AT_NONE, 				new ViewerAssetEntry(DAD_NONE));
 };
 
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 23349ab9161bc11c37948fda68c91b01d87e330f..87a29e530153d52a0af630159d30c340a604507d 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -298,15 +298,6 @@ static bool handleWLSkyDetailChanged(const LLSD&)
 	return true;
 }
 
-static bool handleRenderLightingDetailChanged(const LLSD& newvalue)
-{
-	if (gPipeline.isInit())
-	{
-		gPipeline.setLightingDetail(newvalue.asInteger());
-	}
-	return true;
-}
-
 static bool handleResetVertexBuffersChanged(const LLSD&)
 {
 	if (gPipeline.isInit())
@@ -516,6 +507,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderAvatarVP")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("VertexShaderEnable")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("RenderUIBuffer")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
+	gSavedSettings.getControl("RenderFSAASamples")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderShadowResolutionScale")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderGlow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
@@ -546,7 +538,8 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderDebugPipeline")->getSignal()->connect(boost::bind(&handleRenderDebugPipelineChanged, _2));
 	gSavedSettings.getControl("RenderResolutionDivisor")->getSignal()->connect(boost::bind(&handleRenderResolutionDivisorChanged, _2));
 	gSavedSettings.getControl("RenderDeferred")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
-	gSavedSettings.getControl("RenderDeferredShadow")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
+	gSavedSettings.getControl("RenderShadowDetail")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
+	gSavedSettings.getControl("RenderDeferredSSAO")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("RenderDeferredGI")->getSignal()->connect(boost::bind(&handleSetShaderChanged, _2));
 	gSavedSettings.getControl("TextureMemory")->getSignal()->connect(boost::bind(&handleVideoMemoryChanged, _2));
 	gSavedSettings.getControl("AuditTexture")->getSignal()->connect(boost::bind(&handleAuditTextureChanged, _2));
@@ -571,8 +564,8 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("MuteAmbient")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
 	gSavedSettings.getControl("MuteUI")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
 	gSavedSettings.getControl("RenderVBOEnable")->getSignal()->connect(boost::bind(&handleRenderUseVBOChanged, _2));
+	gSavedSettings.getControl("RenderUseStreamVBO")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("WLSkyDetail")->getSignal()->connect(boost::bind(&handleWLSkyDetailChanged, _2));
-	gSavedSettings.getControl("RenderLightingDetail")->getSignal()->connect(boost::bind(&handleRenderLightingDetailChanged, _2));
 	gSavedSettings.getControl("NumpadControl")->getSignal()->connect(boost::bind(&handleNumpadControlChanged, _2));
 	gSavedSettings.getControl("JoystickAxis0")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
 	gSavedSettings.getControl("JoystickAxis1")->getSignal()->connect(boost::bind(&handleJoystickChanged, _2));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index 823466e33ed6aa4c5ecc58850e3f9a9d369613c7..5be5dc04447d2560d8cd5036b94148f2d9fdf1e3 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -862,19 +862,29 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
 			{
 				gPipeline.mDeferredScreen.flush();
+				if(LLRenderTarget::sUseFBO)
+				{
+					LLRenderTarget::copyContentsToFramebuffer(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), 
+															  gPipeline.mDeferredScreen.getHeight(), 0, 0, 
+															  gPipeline.mDeferredScreen.getWidth(), 
+															  gPipeline.mDeferredScreen.getHeight(), 
+															  GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+				}
 			}
 			else
 			{
 				gPipeline.mScreen.flush();
+				if(LLRenderTarget::sUseFBO)
+				{				
+					LLRenderTarget::copyContentsToFramebuffer(gPipeline.mScreen, 0, 0, gPipeline.mScreen.getWidth(), 
+															  gPipeline.mScreen.getHeight(), 0, 0, 
+															  gPipeline.mScreen.getWidth(), 
+															  gPipeline.mScreen.getHeight(), 
+															  GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+				}
 			}
 		}
 
-		/// We copy the frame buffer straight into a texture here,
-		/// and then display it again with compositor effects.
-		/// Using render to texture would be faster/better, but I don't have a 
-		/// grasp of their full display stack just yet.
-		// gPostProcess->apply(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
-		
 		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
 		{
 			gPipeline.renderDeferredLighting();
@@ -1117,7 +1127,7 @@ void render_ui(F32 zoom_factor, int subfield)
 		{
 			gPipeline.renderBloom(gSnapshot, zoom_factor, subfield);
 		}
-
+		
 		render_hud_elements();
 		render_hud_attachments();
 	}
diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp
index 65e9d8971a88e925d87481f861cacbd28f45bb0e..e04411d44b7769797611510b2c128d7e934257e9 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -71,6 +71,7 @@
 #include "llimfloater.h"
 #include "llfloaterinspect.h"
 #include "llfloaterinventory.h"
+#include "llfloaterimportcollada.h"
 #include "llfloaterjoystick.h"
 #include "llfloaterlagmeter.h"
 #include "llfloaterland.h"
@@ -126,6 +127,8 @@
 #include "llpreviewtexture.h"
 #include "llsyswellwindow.h"
 #include "llscriptfloater.h"
+#include "llfloatermodelpreview.h"
+
 // *NOTE: Please add files in alphabetical order to keep merges easy.
 
 
@@ -174,6 +177,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>);
 
 	LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>);
+	LLFloaterReg::add("import_collada", "floater_import_collada.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImportCollada>);
 	LLFloaterReg::add("im_container", "floater_im_container.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloaterContainer>);
 	LLFloaterReg::add("im_well_window", "floater_sys_well.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMWellWindow>);
 	LLFloaterReg::add("incoming_call", "floater_incoming_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIncomingCallDialog>);
@@ -254,7 +258,8 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("upload_anim", "floater_animation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload");
 	LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload");
 	LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload");
-	
+	LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload");
+
 	LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>);
 	
 	LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>);	
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 7225aa15238fc5c3cec5a12328fb65c35a435460..92029d10f690dbe70826dbdaeecaaa7bc5ba33ea 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -561,12 +561,6 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 		}
 		else
 		{
-			// This warning will always trigger if you've hacked the avatar to show as incomplete.
-			// Ignore the warning if that's the case.
-			if (!gSavedSettings.getBOOL("RenderUnloadedAvatar"))
-			{
-				//llwarns << "Layerset without composite" << llendl;
-			}
 			gGL.getTexUnit(0)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
 		}
 	}
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index b54305f02160b0c77bb431d672d99050274d2189..6a83f9cb355d844037f12ab9aa164e6459a0e158 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -166,7 +166,6 @@ LLMenuItemCallGL* gBusyMenu = NULL;
 // Local prototypes
 
 // File Menu
-const char* upload_pick(void* data);
 void handle_compress_image(void*);
 
 
@@ -451,7 +450,7 @@ void init_menus()
 	gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost);
 	gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", upload_cost);
 	gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", upload_cost);
-
+	
 	gAFKMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Away", TRUE);
 	gBusyMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Busy", TRUE);
 	gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE);
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index c575656b244d037e079ab6b0b4c880ab2de6c2d3..e436341b41c1b37abe7ea749098186857c7861ce 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -40,6 +40,8 @@
 #include "llfilepicker.h"
 #include "llfloaterreg.h"
 #include "llfloaterbuycurrency.h"
+#include "llfloaterimportcollada.h"
+#include "llfloatermodelpreview.h"
 #include "llfloatersnapshot.h"
 #include "llimage.h"
 #include "llimagebmp.h"
@@ -64,7 +66,7 @@
 #include "llappviewer.h"
 #include "lluploaddialog.h"
 #include "lltrans.h"
-
+#include "llfloaterimportcollada.h"
 
 // linden libraries
 #include "llassetuploadresponders.h"
@@ -72,6 +74,7 @@
 #include "llhttpclient.h"
 #include "llnotificationsutil.h"
 #include "llsdserialize.h"
+#include "llsdutil.h"
 #include "llstring.h"
 #include "lltransactiontypes.h"
 #include "lluuid.h"
@@ -90,6 +93,81 @@ class LLFileEnableUpload : public view_listener_t
 	}
 };
 
+class LLFileEnableUploadModel : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		return true;
+	}
+};
+
+LLMutex* LLFilePickerThread::sMutex = NULL;
+std::queue<LLFilePickerThread*> LLFilePickerThread::sDeadQ;
+
+void LLFilePickerThread::getFile()
+{
+#if LL_WINDOWS
+	start();
+#else
+	run();
+#endif
+}
+
+//virtual 
+void LLFilePickerThread::run()
+{
+	LLFilePicker picker;
+#if LL_WINDOWS
+	if (picker.getOpenFile(mFilter, false))
+	{
+		mFile = picker.getFirstFile();
+	}
+#else
+	if (picker.getOpenFile(mFilter, true))
+	{
+		mFile = picker.getFirstFile();
+	}
+#endif
+
+	{
+		LLMutexLock lock(sMutex);
+		sDeadQ.push(this);
+	}
+
+}
+
+//static
+void LLFilePickerThread::initClass()
+{
+	sMutex = new LLMutex(NULL);
+}
+
+//static
+void LLFilePickerThread::cleanupClass()
+{
+	clearDead();
+	
+	delete sMutex;
+	sMutex = NULL;
+}
+
+//static
+void LLFilePickerThread::clearDead()
+{
+	if (!sDeadQ.empty())
+	{
+		LLMutexLock lock(sMutex);
+		while (!sDeadQ.empty())
+		{
+			LLFilePickerThread* thread = sDeadQ.front();
+			thread->notify(thread->mFile);
+			delete thread;
+			sDeadQ.pop();
+		}
+	}
+}
+
+
 //============================================================================
 
 #if LL_WINDOWS
@@ -103,6 +181,7 @@ static std::string XML_EXTENSIONS = "xml";
 static std::string SLOBJECT_EXTENSIONS = "slobject";
 #endif
 static std::string ALL_FILE_EXTENSIONS = "*.*";
+static std::string MODEL_EXTENSIONS = "dae";
 
 std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
 {
@@ -117,6 +196,8 @@ std::string build_extensions_string(LLFilePicker::ELoadFilter filter)
 		return ANIM_EXTENSIONS;
 	case LLFilePicker::FFLOAD_SLOBJECT:
 		return SLOBJECT_EXTENSIONS;
+	case LLFilePicker::FFLOAD_MODEL:
+		return MODEL_EXTENSIONS;
 #ifdef _CORY_TESTING
 	case LLFilePicker::FFLOAD_GEOMETRY:
 		return GEOMETRY_EXTENSIONS;
@@ -260,6 +341,33 @@ class LLFileUploadImage : public view_listener_t
 	}
 };
 
+class LLFileUploadScene : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		std::string filename = upload_pick((void *)LLFilePicker::FFLOAD_COLLADA);
+		if (!filename.empty())
+		{
+			LLImportCollada::getInstance()->importFile(filename);
+		}
+		return TRUE;
+	}
+};
+
+class LLFileUploadModel : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) LLFloaterReg::getInstance("upload_model");
+		if (fmp)
+		{
+			fmp->loadModel(3);
+		}
+		
+		return TRUE;
+	}
+};
+	
 class LLFileUploadSound : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -318,11 +426,24 @@ class LLFileUploadBulk : public view_listener_t
 			LLStringUtil::trim(asset_name);
 			
 			std::string display_name = LLStringUtil::null;
+			LLAssetStorage::LLStoreAssetCallback callback = NULL;
 			S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
-			upload_new_resource(filename, asset_name, asset_name, LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
-				LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(),
-					    display_name,
-					    NULL, expected_upload_cost);
+			void *userdata = NULL;
+
+			upload_new_resource(
+				filename,
+				asset_name,
+				asset_name,
+				0,
+				LLFolderType::FT_NONE,
+				LLInventoryType::IT_NONE,
+				LLFloaterPerms::getNextOwnerPerms(),
+				LLFloaterPerms::getGroupPerms(),
+				LLFloaterPerms::getEveryonePerms(),
+				display_name,
+				callback,
+				expected_upload_cost,
+				userdata);
 
 			// *NOTE: Ew, we don't iterate over the file list here,
 			// we handle the next files in upload_done_callback()
@@ -478,16 +599,20 @@ void handle_compress_image(void*)
 	}
 }
 
-void upload_new_resource(const std::string& src_filename, std::string name,
-			 std::string desc,
-			 LLFolderType::EType destination_folder_type,
-			 LLInventoryType::EType inv_type,
-			 U32 next_owner_perms,
-			 U32 group_perms,
-			 U32 everyone_perms,
-			 const std::string& display_name,
-			 boost::function<void(const LLUUID& uuid)> callback,
-			 S32 expected_upload_cost)
+LLUUID upload_new_resource(
+	const std::string& src_filename,
+	std::string name,
+	std::string desc,
+	S32 compression_info,
+	LLFolderType::EType destination_folder_type,
+	LLInventoryType::EType inv_type,
+	U32 next_owner_perms,
+	U32 group_perms,
+	U32 everyone_perms,
+	const std::string& display_name,
+	LLAssetStorage::LLStoreAssetCallback callback,
+	S32 expected_upload_cost,
+	void *userdata)
 {	
 	// Generate the temporary UUID.
 	std::string filename = gDirUtilp->getTempFilename();
@@ -512,7 +637,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 				short_name.c_str());
 		args["FILE"] = short_name;
  		upload_error(error_message, "NofileExtension", filename, args);
-		return;
+		return LLUUID();
 	}
 	else if( exten == "bmp")
 	{
@@ -526,7 +651,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 			args["FILE"] = src_filename;
 			args["ERROR"] = LLImage::getLastError();
 			upload_error(error_message, "ProblemWithFile", filename, args);
-			return;
+			return LLUUID();
 		}
 	}
 	else if( exten == "tga")
@@ -541,7 +666,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 			args["FILE"] = src_filename;
 			args["ERROR"] = LLImage::getLastError();
 			upload_error(error_message, "ProblemWithFile", filename, args);
-			return;
+			return LLUUID();
 		}
 	}
 	else if( exten == "jpg" || exten == "jpeg")
@@ -556,7 +681,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 			args["FILE"] = src_filename;
 			args["ERROR"] = LLImage::getLastError();
 			upload_error(error_message, "ProblemWithFile", filename, args);
-			return;
+			return LLUUID();
 		}
 	}
  	else if( exten == "png")
@@ -571,7 +696,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
  			args["FILE"] = src_filename;
  			args["ERROR"] = LLImage::getLastError();
  			upload_error(error_message, "ProblemWithFile", filename, args);
- 			return;
+ 			return LLUUID();
  		}
  	}
 	else if(exten == "wav")
@@ -599,7 +724,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 					upload_error(error_message, "UnknownVorbisEncodeFailure", filename, args);
 					break;	
 			}	
-			return;
+			return LLUUID();
 		}
 	}
 	else if(exten == "tmp")	 	
@@ -639,7 +764,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
                                                  error_message = llformat("corrupt resource file: %s", src_filename.c_str());
 												 args["FILE"] = src_filename;
 												 upload_error(error_message, "CorruptResourceFile", filename, args);
-                                                 return;
+                                                 return LLUUID();
                                          }	 	
 
                                          if (2 == tokens_read)	 	
@@ -667,7 +792,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
                                  error_message = llformat("unknown linden resource file version in file: %s", src_filename.c_str());
 								 args["FILE"] = src_filename;
 								 upload_error(error_message, "UnknownResourceFileVersion", filename, args);
-                                 return;
+                                 return LLUUID();
                          }	 	
                  }	 	
                  else	 	
@@ -709,7 +834,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
                          error_message = llformat( "Unable to create output file: %s", filename.c_str());
 						 args["FILE"] = filename;
 						 upload_error(error_message, "UnableToCreateOutputFile", filename, args);
-                         return;
+                         return LLUUID();
                  }	 	
 
                  fclose(in);	 	
@@ -723,7 +848,7 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 	{
 		error_message = llformat("We do not currently support bulk upload of animation files\n");
 		upload_error(error_message, "DoNotSupportBulkAnimationUpload", filename, args);
-		return;
+		return LLUUID();
 	}
 	else
 	{
@@ -769,9 +894,21 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 		{
 			t_disp_name = src_filename;
 		}
-		upload_new_resource(tid, asset_type, name, desc,
-				    destination_folder_type, inv_type, next_owner_perms, group_perms, everyone_perms,
-				    display_name, callback, expected_upload_cost);
+		upload_new_resource(
+			tid,
+			asset_type,
+			name,
+			desc,
+			compression_info, // tid
+			destination_folder_type,
+			inv_type,
+			next_owner_perms,
+			group_perms,
+			everyone_perms,
+			display_name,
+			callback,
+			expected_upload_cost,
+			userdata);
 	}
 	else
 	{
@@ -785,9 +922,15 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 		}
 		LLFilePicker::instance().reset();
 	}
+
+	return uuid;
 }
 
-void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status) // StoreAssetData callback (fixed)
+void upload_done_callback(
+	const LLUUID& uuid,
+	void* user_data,
+	S32 result,
+	LLExtStat ext_status) // StoreAssetData callback (fixed)
 {
 	LLResourceData* data = (LLResourceData*)user_data;
 	S32 expected_upload_cost = data ? data->mExpectedUploadCost : 0;
@@ -890,98 +1033,325 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt
 		LLStringUtil::trim(asset_name);
 
 		std::string display_name = LLStringUtil::null;
-		upload_new_resource(next_file, asset_name, asset_name,	// file
-				    LLFolderType::FT_NONE, LLInventoryType::IT_NONE,
-				    PERM_NONE, PERM_NONE, PERM_NONE,
-				    display_name,
-				    NULL,
-				    expected_upload_cost); // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
-				
+		LLAssetStorage::LLStoreAssetCallback callback = NULL;
+		void *userdata = NULL;
+		upload_new_resource(
+			next_file,
+			asset_name,
+			asset_name,	// file
+			0,
+			LLFolderType::FT_NONE,
+			LLInventoryType::IT_NONE,
+			PERM_NONE,
+			PERM_NONE,
+			PERM_NONE,
+			display_name,
+			callback,
+			expected_upload_cost, // assuming next in a group of uploads is of roughly the same type, i.e. same upload cost
+			userdata);
 	}
 }
 
-void upload_new_resource(const LLTransactionID &tid, 
-			 LLAssetType::EType asset_type,
-			 std::string name,
-			 std::string desc, 
-			 LLFolderType::EType destination_folder_type,
-			 LLInventoryType::EType inv_type,
-			 U32 next_owner_perms,
-			 U32 group_perms,
-			 U32 everyone_perms,
-			 const std::string& display_name,
-			 boost::function<void(const LLUUID& uuid)> callback,
-			 S32 expected_upload_cost)
+static LLAssetID upload_new_resource_prep(
+	const LLTransactionID& tid,
+	LLAssetType::EType asset_type,
+	LLInventoryType::EType& inventory_type,
+	std::string& name,
+	const std::string& display_name,
+	std::string& description)
 {
-	if(gDisconnected)
+	LLAssetID uuid = generate_asset_id_for_new_upload(tid);
+
+	increase_new_upload_stats(asset_type);
+
+	assign_defaults_and_show_upload_message(
+		asset_type,
+		inventory_type,
+		name,
+		display_name,
+		description);
+
+	return uuid;
+}
+
+LLSD generate_new_resource_upload_capability_body(
+	LLAssetType::EType asset_type,
+	const std::string& name,
+	const std::string& desc,
+	LLFolderType::EType destination_folder_type,
+	LLInventoryType::EType inv_type,
+	U32 next_owner_perms,
+	U32 group_perms,
+	U32 everyone_perms)
+{
+	LLSD body;
+
+	body["folder_id"] = gInventory.findCategoryUUIDForType(
+		(destination_folder_type == LLFolderType::FT_NONE) ?
+		(LLFolderType::EType) asset_type :
+		destination_folder_type);
+
+	body["asset_type"] = LLAssetType::lookup(asset_type);
+	body["inventory_type"] = LLInventoryType::lookup(inv_type);
+	body["name"] = name;
+	body["description"] = desc;
+	body["next_owner_mask"] = LLSD::Integer(next_owner_perms);
+	body["group_mask"] = LLSD::Integer(group_perms);
+	body["everyone_mask"] = LLSD::Integer(everyone_perms);
+
+	return body;
+}
+
+void upload_new_resource(
+	const LLTransactionID &tid,
+	LLAssetType::EType asset_type,
+	std::string name,
+	std::string desc,
+	S32 compression_info,
+	LLFolderType::EType destination_folder_type,
+	LLInventoryType::EType inv_type,
+	U32 next_owner_perms,
+	U32 group_perms,
+	U32 everyone_perms,
+	const std::string& display_name,
+	LLAssetStorage::LLStoreAssetCallback callback,
+	S32 expected_upload_cost,
+	void *userdata)
+{
+	LLAssetID uuid = 
+		upload_new_resource_prep(
+			tid,
+			asset_type,
+			inv_type,
+			name,
+			display_name,
+			desc);
+
+	llinfos << "*** Uploading: " << llendl;
+	llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl;
+	llinfos << "UUID: " << uuid << llendl;
+	llinfos << "Name: " << name << llendl;
+	llinfos << "Desc: " << desc << llendl;
+	llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl;
+	lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type) << llendl;
+	lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
+
+	std::string url = gAgent.getRegion()->getCapability(
+		"NewFileAgentInventory");
+
+	if ( !url.empty() )
+	{
+		llinfos << "New Agent Inventory via capability" << llendl;
+
+		LLSD body;
+		body = generate_new_resource_upload_capability_body(
+			asset_type,
+			name,
+			desc,
+			destination_folder_type,
+			inv_type,
+			next_owner_perms,
+			group_perms,
+			everyone_perms);
+
+		LLHTTPClient::post(
+			url,
+			body,
+			new LLNewAgentInventoryResponder(
+				body,
+				uuid,
+				asset_type));
+	}
+	else
 	{
-		return ;
+		llinfos << "NewAgentInventory capability not found, new agent inventory via asset system." << llendl;
+		// check for adequate funds
+		// TODO: do this check on the sim
+		if (LLAssetType::AT_SOUND == asset_type ||
+			LLAssetType::AT_TEXTURE == asset_type ||
+			LLAssetType::AT_ANIMATION == asset_type)
+		{
+			S32 balance = gStatusBar->getBalance();
+			if (balance < expected_upload_cost)
+			{
+				// insufficient funds, bail on this upload
+				LLStringUtil::format_map_t args;
+				args["AMOUNT"] = llformat("%d", expected_upload_cost);
+				LLFloaterBuyCurrency::buyCurrency(LLTrans::getString("uploading_costs", args), expected_upload_cost);
+				return;
+			}
+		}
+
+		LLResourceData* data = new LLResourceData;
+		data->mAssetInfo.mTransactionID = tid;
+		data->mAssetInfo.mUuid = uuid;
+		data->mAssetInfo.mType = asset_type;
+		data->mAssetInfo.mCreatorID = gAgentID;
+		data->mInventoryType = inv_type;
+		data->mNextOwnerPerm = next_owner_perms;
+		data->mExpectedUploadCost = expected_upload_cost;
+		data->mUserData = userdata;
+		data->mAssetInfo.setName(name);
+		data->mAssetInfo.setDescription(desc);
+		data->mPreferredLocation = destination_folder_type;
+
+		LLAssetStorage::LLStoreAssetCallback asset_callback = &upload_done_callback;
+		if (callback)
+		{
+			asset_callback = callback;
+		}
+		gAssetStorage->storeAssetData(
+			data->mAssetInfo.mTransactionID,
+			data->mAssetInfo.mType,
+			asset_callback,
+			(void*)data,
+			FALSE);
 	}
+}
 
-	LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
-	
-	if( LLAssetType::AT_SOUND == asset_type )
+BOOL upload_new_variable_price_resource(
+	const LLTransactionID &tid, 
+	LLAssetType::EType asset_type,
+	std::string name,
+	std::string desc, 
+	LLFolderType::EType destination_folder_type,
+	LLInventoryType::EType inv_type,
+	U32 next_owner_perms,
+	U32 group_perms,
+	U32 everyone_perms,
+	const std::string& display_name,
+	const LLSD& asset_resources)
+{
+	LLAssetID uuid = 
+		upload_new_resource_prep(
+			tid,
+			asset_type,
+			inv_type,
+			name,
+			display_name,
+			desc);
+
+	llinfos << "*** Uploading: " << llendl;
+	llinfos << "Type: " << LLAssetType::lookup(asset_type) << llendl;
+	llinfos << "UUID: " << uuid << llendl;
+	llinfos << "Name: " << name << llendl;
+	llinfos << "Desc: " << desc << llendl;
+	lldebugs << "Folder: "
+		<< gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? (LLFolderType::EType)asset_type : destination_folder_type) << llendl;
+	lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
+
+	std::string url = gAgent.getRegion()->getCapability(
+		"NewFileAgentInventoryVariablePrice");
+
+	if ( !url.empty() )
 	{
-		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT );
+		lldebugs
+			<< "New Agent Inventory variable price upload" << llendl;
+		
+		// Each of the two capabilities has similar data, so
+		// let's reuse that code
+
+		LLSD body;
+
+		body = generate_new_resource_upload_capability_body(
+			asset_type,
+			name,
+			desc,
+			destination_folder_type,
+			inv_type,
+			next_owner_perms,
+			group_perms,
+			everyone_perms);
+
+		body["asset_resources"] = asset_resources;
+
+		LLHTTPClient::post(
+			url,
+			body,
+			new LLNewAgentInventoryVariablePriceResponder(
+				uuid,
+				asset_type,
+				body));
+
+		return TRUE;
 	}
 	else
-	if( LLAssetType::AT_TEXTURE == asset_type )
 	{
-		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
+		return FALSE;
 	}
-	else
-	if( LLAssetType::AT_ANIMATION == asset_type)
+}
+
+LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid)
+{
+	if ( gDisconnected )
 	{
-		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT );
+		LLAssetID rv;
+
+		rv.setNull();
+		return rv;
 	}
 
-	if(LLInventoryType::IT_NONE == inv_type)
+	LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
+
+	return uuid;
+}
+
+void increase_new_upload_stats(LLAssetType::EType asset_type)
+{
+	if ( LLAssetType::AT_SOUND == asset_type )
+	{
+		LLViewerStats::getInstance()->incStat(
+			LLViewerStats::ST_UPLOAD_SOUND_COUNT );
+	}
+	else if ( LLAssetType::AT_TEXTURE == asset_type )
+	{
+		LLViewerStats::getInstance()->incStat(
+			LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
+	}
+	else if ( LLAssetType::AT_ANIMATION == asset_type )
+	{
+		LLViewerStats::getInstance()->incStat(
+			LLViewerStats::ST_UPLOAD_ANIM_COUNT );
+	}
+}
+
+void assign_defaults_and_show_upload_message(
+	LLAssetType::EType asset_type,
+	LLInventoryType::EType& inventory_type,
+	std::string& name,
+	const std::string& display_name,
+	std::string& description)
+{
+	if ( LLInventoryType::IT_NONE == inventory_type )
 	{
-		inv_type = LLInventoryType::defaultForAssetType(asset_type);
+		inventory_type = LLInventoryType::defaultForAssetType(asset_type);
 	}
 	LLStringUtil::stripNonprintable(name);
-	LLStringUtil::stripNonprintable(desc);
-	if(name.empty())
+	LLStringUtil::stripNonprintable(description);
+
+	if ( name.empty() )
 	{
 		name = "(No Name)";
 	}
-	if(desc.empty())
+	if ( description.empty() )
 	{
-		desc = "(No Description)";
+		description = "(No Description)";
 	}
-	
+
 	// At this point, we're ready for the upload.
 	std::string upload_message = "Uploading...\n\n";
 	upload_message.append(display_name);
 	LLUploadDialog::modalUploadDialog(upload_message);
-
-	std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory");
-	
-	if (url.empty()) {
-		llwarns << "Could not get NewFileAgentInventory capability" << llendl;
-		return;
-	}
-
-	llinfos << "New Agent Inventory via capability" << llendl;
-	LLSD body;
-	body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLFolderType::FT_NONE) ? LLFolderType::assetTypeToFolderType(asset_type) : destination_folder_type);
-	body["asset_type"] = LLAssetType::lookup(asset_type);
-	body["inventory_type"] = LLInventoryType::lookup(inv_type);
-	body["name"] = name;
-	body["description"] = desc;
-	body["next_owner_mask"] = LLSD::Integer(next_owner_perms);
-	body["group_mask"] = LLSD::Integer(group_perms);
-	body["everyone_mask"] = LLSD::Integer(everyone_perms);
-	body["expected_upload_cost"] = LLSD::Integer(expected_upload_cost);
-
-	LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type, callback));
 }
 
+
 void init_menu_file()
 {
 	view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage");
 	view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound");
 	view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim");
+	view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
+	view_listener_t::addCommit(new LLFileUploadScene(), "File.UploadScene");
 	view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
 	view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
 	view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
@@ -991,6 +1361,7 @@ void init_menu_file()
 	view_listener_t::addCommit(new LLFileQuit(), "File.Quit");
 
 	view_listener_t::addEnable(new LLFileEnableUpload(), "File.EnableUpload");
+	view_listener_t::addEnable(new LLFileEnableUploadModel(), "File.EnableUploadModel");
 	
 	// "File.SaveTexture" moved to llpanelmaininventory so that it can be properly handled.
 }
diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h
index 33f8243ac0db1c00fe91118823c23b9e1a475392..08444551a9fc3fb942ec6bf8e1f9e4ba9cac8edf 100644
--- a/indra/newview/llviewermenufile.h
+++ b/indra/newview/llviewermenufile.h
@@ -34,35 +34,120 @@
 #define LLVIEWERMENUFILE_H
 
 #include "llfoldertype.h"
+#include "llassetstorage.h"
 #include "llinventorytype.h"
+#include "llfilepicker.h"
 
 class LLTransactionID;
 
+
 void init_menu_file();
 
-void upload_new_resource(const std::string& src_filename, 
-			 std::string name,
-			 std::string desc, 
-			 LLFolderType::EType destination_folder_type,
-			 LLInventoryType::EType inv_type,
-			 U32 next_owner_perms,
-			 U32 group_perms,
-			 U32 everyone_perms,
-			 const std::string& display_name,
-			 boost::function<void(const LLUUID& uuid)> callback,
-			 S32 expected_upload_cost);
-
-void upload_new_resource(const LLTransactionID &tid, 
-			 LLAssetType::EType type,
-			 std::string name,
-			 std::string desc, 
-			 LLFolderType::EType destination_folder_type,
-			 LLInventoryType::EType inv_type,
-			 U32 next_owner_perms,
-			 U32 group_perms,
-			 U32 everyone_perms,
-			 const std::string& display_name,
-			 boost::function<void(const LLUUID& uuid)> callback,
-			 S32 expected_upload_cost);
+LLUUID upload_new_resource(
+	const std::string& src_filename, 
+	std::string name,
+	std::string desc, 
+	S32 compression_info,
+	LLFolderType::EType destination_folder_type,
+	LLInventoryType::EType inv_type,
+	U32 next_owner_perms,
+	U32 group_perms,
+	U32 everyone_perms,
+	const std::string& display_name,
+	LLAssetStorage::LLStoreAssetCallback callback,
+	S32 expected_upload_cost,
+	void *userdata);
+
+void upload_new_resource(
+	const LLTransactionID &tid, 
+	LLAssetType::EType type,
+	std::string name,
+	std::string desc, 
+	S32 compression_info,
+	LLFolderType::EType destination_folder_type,
+	LLInventoryType::EType inv_type,
+	U32 next_owner_perms,
+	U32 group_perms,
+	U32 everyone_perms,
+	const std::string& display_name,
+	LLAssetStorage::LLStoreAssetCallback callback,
+	S32 expected_upload_cost,
+	void *userdata);
+
+// TODO* : Move all uploads to use this new function
+// since at some point, that upload path will be deprecated and no longer
+// used
+
+// We make a new function here to ensure that previous code is not broken
+BOOL upload_new_variable_price_resource(
+	const LLTransactionID& tid, 
+	LLAssetType::EType type,
+	std::string name,
+	std::string desc, 
+	LLFolderType::EType destination_folder_type,
+	LLInventoryType::EType inv_type,
+	U32 next_owner_perms,
+	U32 group_perms,
+	U32 everyone_perms,
+	const std::string& display_name,
+	const LLSD& asset_resources);
+
+LLAssetID generate_asset_id_for_new_upload(const LLTransactionID& tid);
+void increase_new_upload_stats(LLAssetType::EType asset_type);
+void assign_defaults_and_show_upload_message(
+	LLAssetType::EType asset_type,
+	LLInventoryType::EType& inventory_type,
+	std::string& name,
+	const std::string& display_name,
+	std::string& description);
+
+LLSD generate_new_resource_upload_capability_body(
+	LLAssetType::EType asset_type,
+	const std::string& name,
+	const std::string& desc,
+	LLFolderType::EType destination_folder_type,
+	LLInventoryType::EType inv_type,
+	U32 next_owner_perms,
+	U32 group_perms,
+	U32 everyone_perms);
+
+void on_new_single_inventory_upload_complete(
+	LLAssetType::EType asset_type,
+	LLInventoryType::EType inventory_type,
+	const std::string inventory_type_string,
+	const LLUUID& item_folder_id,
+	const std::string& item_name,
+	const std::string& item_description,
+	const LLSD& server_response,
+	S32 upload_price);
+
+class LLFilePickerThread : public LLThread
+{ //multi-threaded file picker (runs system specific file picker in background and calls "notify" from main thread)
+public:
+
+	static std::queue<LLFilePickerThread*> sDeadQ;
+	static LLMutex* sMutex;
+
+	static void initClass();
+	static void cleanupClass();
+	static void clearDead();
+
+	std::string mFile; 
+
+	LLFilePicker::ELoadFilter mFilter;
+
+	LLFilePickerThread(LLFilePicker::ELoadFilter filter)
+		: LLThread("file picker"), mFilter(filter)
+	{
+
+	}
+
+	void getFile();
+
+	virtual void run();
+
+	virtual void notify(const std::string& filename) = 0;
+};
+
 
 #endif
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 1426c0b9e2b7e2bd2e374f984a3111cb6fb0ee7f..cde78e1cc866cdaa59523064e3eae0b55d3754d7 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3315,6 +3315,7 @@ const F32 THRESHOLD_HEAD_ROT_QDOT = 0.9997f;	// ~= 2.5 degrees -- if its less th
 const F32 MAX_HEAD_ROT_QDOT = 0.99999f;			// ~= 0.5 degrees -- if its greater than this then no need to update head_rot
 												// between these values we delay the updates (but no more than one second)
 
+static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE_SEND("Send Message");
 
 void send_agent_update(BOOL force_send, BOOL send_reliable)
 {
@@ -3473,6 +3474,7 @@ void send_agent_update(BOOL force_send, BOOL send_reliable)
 
 	if (duplicate_count < DUP_MSGS && !gDisconnected)
 	{
+		LLFastTimer t(FTM_AGENT_UPDATE_SEND);
 		// Build the message
 		msg->newMessageFast(_PREHASH_AgentUpdate);
 		msg->nextBlockFast(_PREHASH_AgentData);
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 8860b734bbaed200f06ba63d781986212985460d..6820ad42cd2eef1bd02cab0323b14c7d3778fcdb 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2940,7 +2940,7 @@ void LLViewerObject::boostTexturePriority(BOOL boost_children /* = TRUE */)
  		getTEImage(i)->setBoostLevel(LLViewerTexture::BOOST_SELECTED);
 	}
 
-	if (isSculpted())
+	if (isSculpted() && !isMesh())
 	{
 		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
 		LLUUID sculpt_id = sculpt_params->getSculptTexture();
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 266c40d49359616b5dd3941d96a2f7c09fc73079..bf5e0b66563e86066fb35c58065c6fbef08aecdf 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -229,6 +229,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 
 	virtual BOOL isFlexible() const					{ return FALSE; }
 	virtual BOOL isSculpted() const 				{ return FALSE; }
+	virtual BOOL isMesh() const						{ return FALSE; }
 	virtual BOOL hasLightTexture() const			{ return FALSE; }
 
 	// This method returns true if the object is over land owned by
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 752aeaaab01a157c7d58c6e3f40751d1fa3ca96a..7ba28fef32a07c407e98fbb23da3236b6adf28f6 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -871,8 +871,12 @@ void LLViewerObjectList::cleanupReferences(LLViewerObject *objectp)
 	mNumDeadObjects++;
 }
 
+static LLFastTimer::DeclareTimer FTM_REMOVE_DRAWABLE("Remove Drawable");
+
 void LLViewerObjectList::removeDrawable(LLDrawable* drawablep)
 {
+	LLFastTimer t(FTM_REMOVE_DRAWABLE);
+
 	if (!drawablep)
 	{
 		return;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 07d4ac664f4e7e3a79f325dc215fcb0cb8854468..c6fe78eb7489846444355552a8b593631654bea6 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1476,12 +1476,15 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("FetchLib");
 	capabilityNames.append("FetchLibDescendents");
 	capabilityNames.append("GetTexture");
+	capabilityNames.append("GetMesh");
 	capabilityNames.append("GroupProposalBallot");
 	capabilityNames.append("HomeLocation");
 	capabilityNames.append("LandResources");
 	capabilityNames.append("MapLayer");
 	capabilityNames.append("MapLayerGod");
 	capabilityNames.append("NewFileAgentInventory");
+	capabilityNames.append("NewFileAgentInventoryVariablePrice");
+	capabilityNames.append("ObjectAdd");
 	capabilityNames.append("ParcelPropertiesUpdate");
 	capabilityNames.append("ParcelMediaURLFilterList");
 	capabilityNames.append("ParcelNavigateMedia");
@@ -1508,6 +1511,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("UpdateNotecardTaskInventory");
 	capabilityNames.append("UpdateScriptTask");
 	capabilityNames.append("UploadBakedTexture");
+	capabilityNames.append("UploadObjectAsset");
 	capabilityNames.append("ViewerStartAuction");
 	capabilityNames.append("ViewerStats");
 	capabilityNames.append("WebFetchInventoryDescendents");
@@ -1550,6 +1554,7 @@ std::string LLViewerRegion::getCapability(const std::string& name) const
 	{
 		return "";
 	}
+
 	return iter->second;
 }
 
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index 86b1a8c9100c5094a32c6b36861881e636eb834a..a0d0b9d4904051637f17ced6b5dda4340c6e6824 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -317,10 +317,16 @@ S32 LLViewerShaderMgr::getVertexShaderLevel(S32 type)
 
 void LLViewerShaderMgr::setShaders()
 {
-	if (!gPipeline.mInitialized || !sInitialized)
+	//setShaders might be called redundantly by gSavedSettings, so return on reentrance
+	static bool reentrance = false;
+	
+	if (!gPipeline.mInitialized || !sInitialized || reentrance)
 	{
 		return;
 	}
+
+	reentrance = true;
+
 	// Make sure the compiled shader map is cleared before we recompile shaders.
 	mShaderObjects.clear();
 	
@@ -368,17 +374,10 @@ void LLViewerShaderMgr::setShaders()
 		S32 wl_class = 2;
 		S32 water_class = 2;
 		S32 deferred_class = 0;
-		if (!(LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")
-			  && gSavedSettings.getBOOL("WindLightUseAtmosShaders")))
-		{
-			// user has disabled WindLight in their settings, downgrade
-			// windlight shaders to stub versions.
-			wl_class = 1;
-		}
-
-		if (LLPipeline::sRenderDeferred)
+		
+		if (gSavedSettings.getBOOL("RenderDeferred"))
 		{
-			if (gSavedSettings.getBOOL("RenderDeferredShadow"))
+			if (gSavedSettings.getS32("RenderShadowDetail") > 0)
 			{
 				if (gSavedSettings.getBOOL("RenderDeferredGI"))
 				{ //shadows + gi
@@ -393,6 +392,24 @@ void LLViewerShaderMgr::setShaders()
 			{ //no shadows
 				deferred_class = 1;
 			}
+
+			//make sure framebuffer objects are enabled
+			gSavedSettings.setBOOL("RenderUseFBO", TRUE);
+
+			//make sure hardware skinning is enabled
+			gSavedSettings.setBOOL("RenderAvatarVP", TRUE);
+			
+			//make sure atmospheric shaders are enabled
+			gSavedSettings.setBOOL("WindLightUseAtmosShaders", TRUE);
+		}
+
+
+		if (!(LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")
+			  && gSavedSettings.getBOOL("WindLightUseAtmosShaders")))
+		{
+			// user has disabled WindLight in their settings, downgrade
+			// windlight shaders to stub versions.
+			wl_class = 1;
 		}
 
 		if(!gSavedSettings.getBOOL("EnableRippleWater"))
@@ -517,6 +534,8 @@ void LLViewerShaderMgr::setShaders()
 		gViewerWindow->setCursor(UI_CURSOR_ARROW);
 	}
 	gPipeline.createGLBuffers();
+
+	reentrance = false;
 }
 
 void LLViewerShaderMgr::unloadShaders()
@@ -973,10 +992,21 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 	if (success)
 	{
+		std::string fragment;
+
+		if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
+		{
+			fragment = "deferred/sunLightSSAOF.glsl";
+		}
+		else
+		{
+			fragment = "deferred/sunLightF.glsl";
+		}
+
 		gDeferredSunProgram.mName = "Deferred Sun Shader";
 		gDeferredSunProgram.mShaderFiles.clear();
 		gDeferredSunProgram.mShaderFiles.push_back(make_pair("deferred/sunLightV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSunProgram.mShaderFiles.push_back(make_pair("deferred/sunLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSunProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER_ARB));
 		gDeferredSunProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredSunProgram.createShader(NULL, NULL);
 	}
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index b7c265be59722502745d63ede413a6a1c5b5f5da..b0c4b6fc8a0dcac3ea3be3dbf71dcc2f7e9c9b5a 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -592,7 +592,7 @@ void update_statistics(U32 frame_count)
 		}
 	}
 	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_ENABLE_VBO, (F64)gSavedSettings.getBOOL("RenderVBOEnable"));
-	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gSavedSettings.getS32("RenderLightingDetail"));
+	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_LIGHTING_DETAIL, (F64)gPipeline.getLightingDetail());
 	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_DRAW_DIST, (F64)gSavedSettings.getF32("RenderFarClip"));
 	LLViewerStats::getInstance()->setStat(LLViewerStats::ST_CHAT_BUBBLES, (F64)gSavedSettings.getBOOL("UseChatBubbles"));
 #if 0 // 1.9.2
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index c9b3886fefa082fce84a699d2d02d1fd08d5597b..e3bc664473a8ba24bd29c2cc89544ba56b2f60ee 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -535,6 +535,7 @@ LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const
 			case LLAssetType::AT_BODYPART:		img_name = "Inv_Skin";		break;
 			case LLAssetType::AT_ANIMATION:		img_name = "Inv_Animation";	break;
 			case LLAssetType::AT_GESTURE:		img_name = "Inv_Gesture";	break;
+			case LLAssetType::AT_MESH:          img_name = "Inv_Mesh";	    break;
 			default: llassert(0);
 		}
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index af0dcd8e355ccfc97a7ca2a2c4ef899d91efc881..7d75d7a18361179fe9fb33937759231d1829f9db 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -796,7 +796,7 @@ BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* image
 	llassert(mGLTexturep.notNull()) ;	
 
 	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename, to_create, category) ;
-	
+
 	if(ret)
 	{
 		mFullWidth = mGLTexturep->getCurrentWidth() ;
@@ -1367,8 +1367,15 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
 			mOrigWidth = mRawImage->getWidth();
 			mOrigHeight = mRawImage->getHeight();
 
-			// leave black border, do not scale image content
-			mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE);
+			
+			if (mBoostLevel == BOOST_PREVIEW)
+			{ 
+				mRawImage->biasedScaleToPowerOfTwo(1024);
+			}
+			else
+			{ // leave black border, do not scale image content
+				mRawImage->expandToPowerOfTwo(MAX_IMAGE_SIZE, FALSE);
+			}
 			
 			mFullWidth = mRawImage->getWidth();
 			mFullHeight = mRawImage->getHeight();
@@ -2581,7 +2588,7 @@ BOOL LLViewerFetchedTexture::insertToAtlas()
 	}
 
 	//process the waiting_list
-	for(ll_face_list_t::iterator iter = waiting_list.begin(); iter != waiting_list.end(); ++iter)
+	for(std::vector<LLFace*>::iterator iter = waiting_list.begin(); iter != waiting_list.end(); ++iter)
 	{
 		facep = (LLFace*)*iter ;	
 		groupp = facep->getDrawable()->getSpatialGroup() ;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index d7d5cbbd1027010fb2ec0770ce92f11b078d0012..3508f92a2fb1db5d3012d02920c13f2a96257603 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -31,7 +31,6 @@
  */
 
 #include "llviewerprecompiledheaders.h"
-
 #include "llviewerwindow.h"
 
 #if LL_WINDOWS
@@ -47,6 +46,7 @@
 #include "llagent.h"
 #include "llagentcamera.h"
 #include "llfloaterreg.h"
+#include "llmeshrepository.h"
 #include "llpanellogin.h"
 #include "llviewerkeyboard.h"
 #include "llviewermenu.h"
@@ -321,7 +321,7 @@ class LLDebugText
 		mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
 
 		// Draw stuff growing up from right lower corner of screen
-		U32 xpos = mWindow->getWindowWidthScaled() - 350;
+		U32 xpos = mWindow->getWorldViewWidthScaled() - 350;
 		U32 ypos = 64;
 		const U32 y_inc = 20;
 
@@ -586,6 +586,50 @@ class LLDebugText
 				ypos += y_inc;
 			}
 		}
+
+
+		if (gSavedSettings.getBOOL("DebugShowUploadCost"))
+		{
+			addText(xpos, ypos, llformat("       Meshes: L$%d", gPipeline.mDebugMeshUploadCost));
+			ypos += y_inc/2;
+			addText(xpos, ypos, llformat("    Sculpties: L$%d", gPipeline.mDebugSculptUploadCost));
+			ypos += y_inc/2;
+			addText(xpos, ypos, llformat("     Textures: L$%d", gPipeline.mDebugTextureUploadCost));
+			ypos += y_inc/2;
+			addText(xpos, ypos, "Upload Cost: ");
+						
+			ypos += y_inc;
+		}
+
+		//temporary hack to give feedback on mesh upload progress
+		if (!gMeshRepo.mUploads.empty())
+		{
+			for (std::vector<LLMeshUploadThread*>::iterator iter = gMeshRepo.mUploads.begin(); 
+				iter != gMeshRepo.mUploads.end(); ++iter)
+			{
+				LLMeshUploadThread* thread = *iter;
+
+				addText(xpos, ypos, llformat("Mesh Upload -- price quote: %d:%d | upload: %d:%d | create: %d", 
+								thread->mPendingConfirmations, thread->mUploadQ.size()+thread->mTextureQ.size(),
+								thread->mPendingUploads, thread->mConfirmedQ.size()+thread->mConfirmedTextureQ.size(),
+								thread->mInstanceQ.size()));
+				ypos += y_inc;
+			}
+		}
+
+		S32 pending = (S32) gMeshRepo.mPendingRequests.size();
+		S32 header = (S32) gMeshRepo.mThread->mHeaderReqQ.size();
+		S32 lod = (S32) gMeshRepo.mThread->mLODReqQ.size();
+
+		if (pending + header + lod + LLMeshRepoThread::sActiveHeaderRequests + LLMeshRepoThread::sActiveLODRequests != 0)
+		{
+			addText(xpos, ypos, llformat ("Mesh Queue - %d pending (%d:%d header | %d:%d LOD)", 
+												pending,
+												LLMeshRepoThread::sActiveHeaderRequests, header,
+												LLMeshRepoThread::sActiveLODRequests, lod));
+
+			ypos += y_inc;
+		}
 	}
 
 	void draw()
@@ -1377,7 +1421,7 @@ LLViewerWindow::LLViewerWindow(
 		gSavedSettings.getBOOL("DisableVerticalSync"),
 		!gNoRender,
 		ignore_pixel_depth,
-		gSavedSettings.getU32("RenderFSAASamples"));
+		0); //gSavedSettings.getU32("RenderFSAASamples"));
 
 	if (!LLAppViewer::instance()->restoreErrorTrap())
 	{
@@ -3892,140 +3936,6 @@ void LLViewerWindow::playSnapshotAnimAndSound()
 BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
 {
 	return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type);
-	
-	// *TODO below code was broken in deferred pipeline
-	/*
-	if ((!raw) || preview_width < 10 || preview_height < 10)
-	{
-		return FALSE;
-	}
-
-	if(gResizeScreenTexture) //the window is resizing
-	{
-		return FALSE ;
-	}
-
-	setCursor(UI_CURSOR_WAIT);
-
-	// Hide all the UI widgets first and draw a frame
-	BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
-
-	if ( prev_draw_ui != show_ui)
-	{
-		LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
-	}
-
-	BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments;
-	if (hide_hud)
-	{
-		LLPipeline::sShowHUDAttachments = FALSE;
-	}
-
-	S32 render_name = gSavedSettings.getS32("RenderName");
-	gSavedSettings.setS32("RenderName", 0);
-	LLVOAvatar::updateFreezeCounter(1) ; //pause avatar updating for one frame
-	
-	S32 w = preview_width ;
-	S32 h = preview_height ;
-	LLVector2 display_scale = mDisplayScale ;
-	mDisplayScale.setVec((F32)w / mWindowRectRaw.getWidth(), (F32)h / mWindowRectRaw.getHeight()) ;
-	LLRect window_rect = mWindowRectRaw;
-	mWindowRectRaw.set(0, h, w, 0);
-	
-	gDisplaySwapBuffers = FALSE;
-	gDepthDirty = TRUE;
-	glClearColor(0.f, 0.f, 0.f, 0.f);
-	glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-	setup3DRender();
-
-	LLFontGL::setFontDisplay(FALSE) ;
-	LLHUDText::setDisplayText(FALSE) ;
-	if (type == SNAPSHOT_TYPE_OBJECT_ID)
-	{
-		gObjectList.renderPickList(gViewerWindow->getWindowRectScaled(), FALSE, FALSE);
-	}
-	else
-	{
-		display(do_rebuild, 1.0f, 0, TRUE);
-		render_ui();
-	}
-
-	S32 glformat, gltype, glpixel_length ;
-	if(SNAPSHOT_TYPE_DEPTH == type)
-	{
-		glpixel_length = 4 ;
-		glformat = GL_DEPTH_COMPONENT ; 
-		gltype = GL_FLOAT ;
-	}
-	else
-	{
-		glpixel_length = 3 ;
-		glformat = GL_RGB ;
-		gltype = GL_UNSIGNED_BYTE ;
-	}
-
-	raw->resize(w, h, glpixel_length);
-	glReadPixels(0, 0, w, h, glformat, gltype, raw->getData());
-
-	if(SNAPSHOT_TYPE_DEPTH == type)
-	{
-		LLViewerCamera* camerap = LLViewerCamera::getInstance();
-		F32 depth_conversion_factor_1 = (camerap->getFar() + camerap->getNear()) / (2.f * camerap->getFar() * camerap->getNear());
-		F32 depth_conversion_factor_2 = (camerap->getFar() - camerap->getNear()) / (2.f * camerap->getFar() * camerap->getNear());
-
-		//calculate the depth 
-		for (S32 y = 0 ; y < h ; y++)
-		{
-			for(S32 x = 0 ; x < w ; x++)
-			{
-				S32 i = (w * y + x) << 2 ;
-				
-				F32 depth_float_i = *(F32*)(raw->getData() + i);
-				
-				F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float_i * depth_conversion_factor_2));
-				U8 depth_byte = F32_to_U8(linear_depth_float, camerap->getNear(), camerap->getFar());
-				*(raw->getData() + i + 0) = depth_byte;
-				*(raw->getData() + i + 1) = depth_byte;
-				*(raw->getData() + i + 2) = depth_byte;
-				*(raw->getData() + i + 3) = 255;
-			}
-		}		
-	}
-
-	LLFontGL::setFontDisplay(TRUE) ;
-	LLHUDText::setDisplayText(TRUE) ;
-	mDisplayScale.setVec(display_scale) ;
-	mWindowRectRaw = window_rect;	
-	setup3DRender();
-	gDisplaySwapBuffers = FALSE;
-	gDepthDirty = TRUE;
-
-	// POST SNAPSHOT
-	if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
-	{
-		LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
-	}
-
-	if (hide_hud)
-	{
-		LLPipeline::sShowHUDAttachments = TRUE;
-	}
-
-	setCursor(UI_CURSOR_ARROW);
-
-	if (do_rebuild)
-	{
-		// If we had to do a rebuild, that means that the lists of drawables to be rendered
-		// was empty before we started.
-		// Need to reset these, otherwise we call state sort on it again when render gets called the next time
-		// and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of
-		// objects on them.
-		gPipeline.resetDrawOrders();
-	}
-	
-	gSavedSettings.setS32("RenderName", render_name);	
-	
-	return TRUE;*/
 }
 
 // Saves the image from the screen to the specified filename and path.
@@ -4785,8 +4695,9 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size,
 		return TRUE;
 	}
 
-	U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
-	U32 old_fsaa = mWindow->getFSAASamples();
+	//U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
+	//U32 old_fsaa = mWindow->getFSAASamples();
+
 	// going from windowed to windowed
 	if (!old_fullscreen && !fullscreen)
 	{
@@ -4796,7 +4707,7 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size,
 			mWindow->setSize(size);
 		}
 
-		if (fsaa == old_fsaa)
+		//if (fsaa == old_fsaa)
 		{
 			return TRUE;
 		}
@@ -4825,13 +4736,13 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size,
 		gSavedSettings.setS32("WindowY", old_pos.mY);
 	}
 	
-	mWindow->setFSAASamples(fsaa);
+	//mWindow->setFSAASamples(fsaa);
 
 	result_first_try = mWindow->switchContext(fullscreen, size, disable_vsync);
 	if (!result_first_try)
 	{
 		// try to switch back
-		mWindow->setFSAASamples(old_fsaa);
+		//mWindow->setFSAASamples(old_fsaa);
 		result_second_try = mWindow->switchContext(old_fullscreen, old_size, disable_vsync);
 
 		if (!result_second_try)
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 2238acd64376a1402c602640bf21a71f3ed11d1a..2e5d4f1776a3b381d39236526d4667c4018cf31a 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -1176,7 +1176,7 @@ void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 vo
 	{
 		mSpeakersData[speaker_id] = volume;
 
-		// Enable this when debugging voice slider issues.  It's way to spammy even for debug-level logging.
+		// Enable this when debugging voice slider issues.  It's way too spammy even for debug-level logging.
 		// LL_DEBUGS("Voice") << "Stored volume = " << volume <<  " for " << id << LL_ENDL;
 	}
 	else
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 6b052b8e9919718b39077bcd9be230521dfdb3af..bc83e11fd27c8bdaa55d8a4ce7976777ce3bc797 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -36,6 +36,8 @@
 
 #include "llvovolume.h"
 
+#include <sstream>
+
 #include "llviewercontrol.h"
 #include "lldir.h"
 #include "llflexibleobject.h"
@@ -59,6 +61,7 @@
 #include "lltexturefetch.h"
 #include "llviewercamera.h"
 #include "llviewertexturelist.h"
+#include "llviewerobjectlist.h"
 #include "llviewerregion.h"
 #include "llviewertextureanim.h"
 #include "llworld.h"
@@ -67,6 +70,7 @@
 #include "llsdutil.h"
 #include "llmediaentry.h"
 #include "llmediadataclient.h"
+#include "llmeshrepository.h"
 #include "llagent.h"
 #include "llviewermediafocus.h"
 
@@ -88,6 +92,12 @@ LLPointer<LLObjectMediaNavigateClient> LLVOVolume::sObjectMediaNavigateClient =
 
 static LLFastTimer::DeclareTimer FTM_GEN_TRIANGLES("Generate Triangles");
 static LLFastTimer::DeclareTimer FTM_GEN_VOLUME("Generate Volumes");
+static LLFastTimer::DeclareTimer FTM_BUILD_MESH("Mesh");
+static LLFastTimer::DeclareTimer FTM_MESH_VFS("VFS");
+static LLFastTimer::DeclareTimer FTM_MESH_STREAM("Stream");
+static LLFastTimer::DeclareTimer FTM_MESH_FACES("Faces");
+static LLFastTimer::DeclareTimer FTM_VOLUME_TEXTURES("Volume Textures");
+
 
 // Implementation class of LLMediaDataClientObject.  See llmediadataclient.h
 class LLMediaDataClientObjectImpl : public LLMediaDataClientObject
@@ -653,6 +663,7 @@ void LLVOVolume::updateTextures()
 
 void LLVOVolume::updateTextureVirtualSize()
 {
+	LLFastTimer ftm(FTM_VOLUME_TEXTURES);
 	// Update the pixel area of all faces
 
 	if(mDrawable.isNull() || !mDrawable->isVisible())
@@ -745,10 +756,12 @@ void LLVOVolume::updateTextureVirtualSize()
 	if (isSculpted())
 	{
 		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
-		LLUUID id =  sculpt_params->getSculptTexture(); 
+		LLUUID id =  sculpt_params->getSculptTexture();
 		
 		updateSculptTexture();
 		
+		
+
 		if (mSculptTexture.notNull())
 		{
 			mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
@@ -789,6 +802,7 @@ void LLVOVolume::updateTextureVirtualSize()
 										  mSculptTexture->getHeight(), mSculptTexture->getWidth()));
 			}
 		}
+
 	}
 
 	if (getLightTextureID().notNull())
@@ -804,7 +818,7 @@ void LLVOVolume::updateTextureVirtualSize()
 																	*camera));
 		}	
 	}
-
+	
 	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXTURE_AREA))
 	{
 		setDebugText(llformat("%.0f:%.0f", fsqrtf(min_vsize),fsqrtf(max_vsize)));
@@ -900,8 +914,34 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 	return mDrawable;
 }
 
-BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume)
+BOOL LLVOVolume::setVolume(const LLVolumeParams &params, const S32 detail, bool unique_volume)
 {
+	LLVolumeParams volume_params = params;
+
+	S32 lod = mLOD;
+
+	BOOL is404 = FALSE;
+
+	if (isSculpted())
+	{
+		// if it's a mesh
+		if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+		{ //meshes might not have all LODs, get the force detail to best existing LOD
+
+			LLUUID mesh_id = params.getSculptID();
+
+			//profile and path params don't matter for meshes
+			volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+
+			lod = gMeshRepo.getActualMeshLOD(volume_params, lod);
+			if (lod == -1)
+			{
+				is404 = TRUE;
+				lod = 0;
+			}
+		}
+	}
+
 	// Check if we need to change implementations
 	bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
 	if (is_flexible)
@@ -929,13 +969,18 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
 		}
 	}
 	
-	if ((LLPrimitive::setVolume(volume_params, mLOD, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
+	if (is404)
+	{
+		setIcon(LLViewerTextureManager::getFetchedTextureFromFile("icons/Inv_Mesh.png", TRUE, LLViewerTexture::BOOST_UI));
+	}
+
+	if ((LLPrimitive::setVolume(volume_params, lod, (mVolumeImpl && mVolumeImpl->isVolumeUnique()))) || mSculptChanged)
 	{
 		mFaceMappingChanged = TRUE;
 		
 		if (mVolumeImpl)
 		{
-			mVolumeImpl->onSetVolume(volume_params, detail);
+			mVolumeImpl->onSetVolume(volume_params, mLOD);
 		}
 	
 		updateSculptTexture();
@@ -944,9 +989,26 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
 		{
 			updateSculptTexture();
 
-			if (mSculptTexture.notNull())
+			// if it's a mesh
+			if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+			{
+				if (getVolume()->getNumVolumeFaces() == 0 || getVolume()->isTetrahedron())
+				{ 
+					//load request not yet issued, request pipeline load this mesh
+					LLUUID asset_id = volume_params.getSculptID();
+					S32 available_lod = gMeshRepo.loadMesh(this, volume_params, lod);
+					if (available_lod != lod)
+					{
+						LLPrimitive::setVolume(volume_params, available_lod);
+					}
+				}
+			}
+			else // otherwise is sculptie
 			{
-				sculpt();
+				if (mSculptTexture.notNull())
+				{
+					sculpt();
+				}
 			}
 		}
 
@@ -959,7 +1021,7 @@ void LLVOVolume::updateSculptTexture()
 {
 	LLPointer<LLViewerFetchedTexture> old_sculpt = mSculptTexture;
 
-	if (isSculpted())
+	if (isSculpted() && !isMesh())
 	{
 		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
 		LLUUID id =  sculpt_params->getSculptTexture();
@@ -987,6 +1049,15 @@ void LLVOVolume::updateSculptTexture()
 	
 }
 
+
+
+void LLVOVolume::notifyMeshLoaded()
+{ 
+	mSculptChanged = TRUE;
+	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY, TRUE);
+	dirtySpatialGroup(TRUE);
+}
+
 // sculpt replaces generate() for sculpted surfaces
 void LLVOVolume::sculpt()
 {	
@@ -1173,6 +1244,11 @@ void LLVOVolume::updateFaceFlags()
 	for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
 	{
 		LLFace *face = mDrawable->getFace(i);
+		if (!face)
+		{
+			return;
+		}
+
 		BOOL fullbright = getTE(i)->getFullbright();
 		face->clearState(LLFace::FULLBRIGHT | LLFace::HUD_RENDER | LLFace::LIGHT);
 
@@ -1256,9 +1332,13 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 
 	BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION);
 
-	for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
+	for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++)
 	{
 		LLFace *face = mDrawable->getFace(i);
+		if (!face)
+		{
+			continue;
+		}
 		res &= face->genVolumeBBoxes(*getVolume(), i,
 										mRelativeXform, mRelativeXformInvTrans,
 										(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
@@ -2451,6 +2531,17 @@ void LLVOVolume::updateSpotLightPriority()
 }
 
 
+bool LLVOVolume::isLightSpotlight() const
+{
+	LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
+	if (params)
+	{
+		return params->isLightSpotlight();
+	}
+	return false;
+}
+
+
 LLViewerTexture* LLVOVolume::getLightTexture()
 {
 	LLUUID id = getLightTextureID();
@@ -2561,6 +2652,23 @@ BOOL LLVOVolume::isSculpted() const
 	return FALSE;
 }
 
+BOOL LLVOVolume::isMesh() const
+{
+	if (isSculpted())
+	{
+		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+		U8 sculpt_type = sculpt_params->getSculptType();
+
+		if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+			// mesh is a mesh
+		{
+			return TRUE;	
+		}
+	}
+
+	return FALSE;
+}
+
 BOOL LLVOVolume::hasLightTexture() const
 {
 	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
@@ -2899,6 +3007,30 @@ F32 LLVOVolume::getBinRadius()
 {
 	F32 radius;
 	
+	F32 scale = 1.f;
+
+	if (isSculpted())
+	{
+		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+		LLUUID id =  sculpt_params->getSculptTexture();
+		U8 sculpt_type = sculpt_params->getSculptType();
+
+		if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+			// mesh is a mesh
+		{
+			LLVolume* volume = getVolume();
+			U32 vert_count = 0;
+
+			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+			{
+				const LLVolumeFace& face = volume->getVolumeFace(i);
+				vert_count += face.mVertices.size();
+			}
+
+			scale = 1.f/llmax(vert_count/1024.f, 1.f);
+		}
+	}
+
 	const LLVector3* ext = mDrawable->getSpatialExtents();
 	
 	BOOL shrink_wrap = mDrawable->isAnimating();
@@ -2957,7 +3089,7 @@ F32 LLVOVolume::getBinRadius()
 		radius = 8.f;
 	}
 
-	return llclamp(radius, 0.5f, 256.f);
+	return llclamp(radius*scale, 0.5f, 256.f);
 }
 
 const LLVector3 LLVOVolume::getPivotPositionAgent() const
@@ -3188,11 +3320,10 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 
 	S32 idx = draw_vec.size()-1;
 
-
 	BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
-					  (type == LLRenderPass::PASS_INVISIBLE) ||
-					  (type == LLRenderPass::PASS_ALPHA ? facep->isState(LLFace::FULLBRIGHT) : FALSE);
-
+		(type == LLRenderPass::PASS_INVISIBLE) ||
+		(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT));
+	
 	if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL))
 	{
 		llwarns << "Non fullbright face has no normals!" << llendl;
@@ -3221,12 +3352,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 	
 	LLViewerTexture* tex = facep->getTexture();
 
-	U8 glow = 0;
-		
-	if (type == LLRenderPass::PASS_GLOW)
-	{
-		glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
-	}
+	U8 glow = (U8) (facep->getTextureEntry()->getGlow() * 255);
 
 	if (facep->mVertexBuffer.isNull())
 	{
@@ -3291,9 +3417,22 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
 static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume");
 static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
 
+bool LLVolumeGeometryManager::canRenderAsMask(LLFace* facep)
+{
+	const LLTextureEntry* te = facep->getTextureEntry();
+	return (
+		LLPipeline::sFastAlpha && // do we want masks at all?
+
+		(te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha
+		!(LLPipeline::sRenderDeferred && te->getFullbright()) && // hack: alpha masking renders fullbright faces invisible in deferred rendering mode, need to figure out why - for now, avoid
+		(te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask
+
+		facep->getTexture()->getIsAlphaMask() // texture actually qualifies for masking (lazily calculated but expensive)
+		);
+}
+
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
-	llpushcallstacks ;
 	if (group->changeLOD())
 	{
 		group->mLastUpdateDistance = group->mDistance;
@@ -3417,10 +3556,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 				if (type == LLDrawPool::POOL_ALPHA)
 				{
-					if (LLPipeline::sFastAlpha &&
-					    (te->getColor().mV[VW] == 1.0f) &&
-					    (!te->getFullbright()) && // hack: alpha masking renders fullbright faces invisible, need to figure out why - for now, avoid
-					    facep->getTexture()->getIsAlphaMask())
+					if (canRenderAsMask(facep))
 					{ //can be treated as alpha mask
 						simple_faces.push_back(facep);
 					}
@@ -3522,9 +3658,10 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 }
 
 static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM("Volume Geometry");
+static LLFastTimer::DeclareTimer FTM_VOLUME_GEOM_PARTIAL("Terse Rebuild");
+
 void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 {
-	llpushcallstacks ;
 	llassert(group);
 	if (group && group->isState(LLSpatialGroup::MESH_DIRTY) && !group->isState(LLSpatialGroup::GEOM_DIRTY))
 	{
@@ -3535,6 +3672,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 		
 		for (LLSpatialGroup::element_iter drawable_iter = group->getData().begin(); drawable_iter != group->getData().end(); ++drawable_iter)
 		{
+			LLFastTimer t(FTM_VOLUME_GEOM_PARTIAL);
 			LLDrawable* drawablep = *drawable_iter;
 
 			if (drawablep->isDead() || drawablep->isState(LLDrawable::FORCE_INVISIBLE) )
@@ -3555,6 +3693,11 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 						face->getGeometryVolume(*volume, face->getTEOffset(), 
 							vobj->getRelativeXform(), vobj->getRelativeXformInvTrans(), face->getGeomIndex());
 					}
+
+					if (!face)
+					{
+						llerrs << "WTF?" << llendl;
+					}
 				}
 
 				drawablep->clearState(LLDrawable::REBUILD_ALL);
@@ -3616,7 +3759,6 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group)
 
 void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort)
 {
-	llpushcallstacks ;
 	//calculate maximum number of vertices to store in a single buffer
 	U32 max_vertices = (gSavedSettings.getS32("RenderMaxVBOSize")*1024)/LLVertexBuffer::calcStride(group->mSpatialPartition->mVertexDataMask);
 	max_vertices = llmin(max_vertices, (U32) 65535);
@@ -3763,15 +3905,12 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 
 			const LLTextureEntry* te = facep->getTextureEntry();
 
-			BOOL is_alpha = facep->getPoolType() == LLDrawPool::POOL_ALPHA ? TRUE : FALSE;
+			BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE;
 		
 			if (is_alpha)
 			{
 				// can we safely treat this as an alpha mask?
-				if (LLPipeline::sFastAlpha &&
-				    (te->getColor().mV[VW] == 1.0f) &&
-				    (!te->getFullbright()) && // hack: alpha masking renders fullbright faces invisible, need to figure out why - for now, avoid
-				    facep->getTexture()->getIsAlphaMask())
+				if (canRenderAsMask(facep))
 				{
 					if (te->getFullbright())
 					{
@@ -3839,7 +3978,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				}
 				else
 				{
-					if (LLPipeline::sRenderDeferred && te->getBumpmap())
+					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
 					{
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
@@ -3867,7 +4006,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				}
 			}
 
-			if (LLPipeline::sRenderGlow && te->getGlow() > 0.f)
+			if (!is_alpha && LLPipeline::sRenderGlow && te->getGlow() > 0.f)
 			{
 				registerFace(group, facep, LLRenderPass::PASS_GLOW);
 			}
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index a8bb597f93a2cf50203c98f3a030fe509b864055..2776988a122724b7aa3b29eb486efc75b3c5d68a 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -184,6 +184,11 @@ class LLVOVolume : public LLViewerObject
 				void	updateSculptTexture();
 				void    setIndexInTex(S32 index) { mIndexInTex = index ;}
 				void	sculpt();
+	 static     void    rebuildMeshAssetCallback(LLVFS *vfs,
+														  const LLUUID& asset_uuid,
+														  LLAssetType::EType type,
+														  void* user_data, S32 status, LLExtStat ext_status);
+					
 				void	updateRelativeXform();
 	/*virtual*/ BOOL	updateGeometry(LLDrawable *drawable);
 	/*virtual*/ void	updateFaceSize(S32 idx);
@@ -215,6 +220,7 @@ class LLVOVolume : public LLViewerObject
 	LLColor3 getLightBaseColor() const; // not scaled by intensity
 	LLColor3 getLightColor() const; // scaled by intensity
 	LLUUID	getLightTextureID() const;
+	bool isLightSpotlight() const;
 	LLVector3 getSpotLightParams() const;
 	void	updateSpotLightPriority();
 	F32		getSpotLightPriority() const;
@@ -229,6 +235,7 @@ class LLVOVolume : public LLViewerObject
 	U32 getVolumeInterfaceID() const;
 	virtual BOOL isFlexible() const;
 	virtual BOOL isSculpted() const;
+	virtual BOOL isMesh() const;
 	virtual BOOL hasLightTexture() const;
 
 	BOOL isVolumeGlobal() const;
@@ -253,6 +260,7 @@ class LLVOVolume : public LLViewerObject
     
 	void mediaNavigated(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, std::string new_location);
 	void mediaEvent(LLViewerMediaImpl *impl, LLPluginClassMedia* plugin, LLViewerMediaObserver::EMediaEvent event);
+			
 
 	// Sync the given media data with the impl and the given te
 	void syncMediaData(S32 te, const LLSD &media_data, bool merge, bool ignore_agent);
@@ -268,9 +276,11 @@ class LLVOVolume : public LLViewerObject
 	
 	LLVector3 getApproximateFaceNormal(U8 face_id);
 	
+	void notifyMeshLoaded();
+	
 	// Returns 'true' iff the media data for this object is in flight
 	bool isMediaDataBeingFetched() const;
-	
+
 	// Returns the "last fetched" media version, or -1 if not fetched yet
 	S32 getLastFetchedMediaVersion() const { return mLastFetchedMediaVersion; }
 	
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 0b63f5efbde8023e9dba3b608cbd33bb2bdf7fcc..c7148f88260c806a906ac23fdf94580155c9d871 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1028,9 +1028,11 @@ void LLWorld::disconnectRegions()
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_ENABLE_SIMULATOR("Enable Sim");
 
 void process_enable_simulator(LLMessageSystem *msg, void **user_data)
 {
+	LLFastTimer t(FTM_ENABLE_SIMULATOR);
 	// enable the appropriate circuit for this simulator and 
 	// add its values into the gSimulator structure
 	U64		handle;
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 4ca251af3e22bfc5cdf7737f63df30c23f311780..3778cae201c816abdcdfdff757ed0a4014d647b1 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -71,6 +71,7 @@
 #include "llgldbg.h"
 #include "llhudmanager.h"
 #include "lllightconstants.h"
+#include "llmeshrepository.h"
 #include "llresmgr.h"
 #include "llselectmgr.h"
 #include "llsky.h"
@@ -104,6 +105,7 @@
 #include "llspatialpartition.h"
 #include "llmutelist.h"
 #include "lltoolpie.h"
+#include "llcurl.h"
 
 
 #ifdef _DEBUG
@@ -361,6 +363,7 @@ void LLPipeline::init()
 	sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
 	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
 	sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
+	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
 	sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
 	sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
 
@@ -407,6 +410,8 @@ void LLPipeline::init()
 	{
 		mSpotLightFade[i] = 1.f;
 	}
+
+	setLightingDetail(-1);
 }
 
 LLPipeline::~LLPipeline()
@@ -509,6 +514,7 @@ void LLPipeline::destroyGL()
 }
 
 static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
+
 void LLPipeline::resizeScreenTexture()
 {
 	LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE);
@@ -1141,9 +1147,15 @@ void LLPipeline::allocDrawable(LLViewerObject *vobj)
 }
 
 
+static LLFastTimer::DeclareTimer FTM_UNLINK("Unlink");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_MOVE_LIST("Movelist");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_SPATIAL_PARTITION("Spatial Partition");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_LIGHT_SET("Light Set");
+static LLFastTimer::DeclareTimer FTM_REMOVE_FROM_HIGHLIGHT_SET("Highlight Set");
+
 void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 {
-	LLFastTimer t(FTM_PIPELINE);
+	LLFastTimer t(FTM_UNLINK);
 
 	assertInitialized();
 
@@ -1152,6 +1164,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 	// Based on flags, remove the drawable from the queues that it's on.
 	if (drawablep->isState(LLDrawable::ON_MOVE_LIST))
 	{
+		LLFastTimer t(FTM_REMOVE_FROM_MOVE_LIST);
 		LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep);
 		if (iter != mMovedList.end())
 		{
@@ -1161,6 +1174,7 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 
 	if (drawablep->getSpatialGroup())
 	{
+		LLFastTimer t(FTM_REMOVE_FROM_SPATIAL_PARTITION);
 		if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup()))
 		{
 #ifdef LL_RELEASE_FOR_DOWNLOAD
@@ -1171,18 +1185,23 @@ void LLPipeline::unlinkDrawable(LLDrawable *drawable)
 		}
 	}
 
-	mLights.erase(drawablep);
-	for (light_set_t::iterator iter = mNearbyLights.begin();
-				iter != mNearbyLights.end(); iter++)
 	{
-		if (iter->drawable == drawablep)
+		LLFastTimer t(FTM_REMOVE_FROM_LIGHT_SET);
+		mLights.erase(drawablep);
+
+		for (light_set_t::iterator iter = mNearbyLights.begin();
+					iter != mNearbyLights.end(); iter++)
 		{
-			mNearbyLights.erase(iter);
-			break;
+			if (iter->drawable == drawablep)
+			{
+				mNearbyLights.erase(iter);
+				break;
+			}
 		}
 	}
 
 	{
+		LLFastTimer t(FTM_REMOVE_FROM_HIGHLIGHT_SET);
 		HighlightItem item(drawablep);
 		mHighlightSet.erase(item);
 
@@ -1785,6 +1804,8 @@ void LLPipeline::rebuildPriorityGroups()
 	
 	assertInitialized();
 
+	gMeshRepo.notifyLoadedMeshes();
+
 	// Iterate through all drawables on the priority build queue,
 	for (LLSpatialGroup::sg_list_t::iterator iter = mGroupQ1.begin();
 		 iter != mGroupQ1.end(); ++iter)
@@ -1795,11 +1816,11 @@ void LLPipeline::rebuildPriorityGroups()
 	}
 
 	mGroupQ1.clear();
+
 }
 		
 void LLPipeline::rebuildGroups()
 {
-	llpushcallstacks ;
 	// Iterate through some drawables on the non-priority build queue
 	S32 size = (S32) mGroupQ2.size();
 	S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size);
@@ -1947,6 +1968,7 @@ void LLPipeline::updateGeom(F32 max_dtime)
 void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
 {
 	LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE);
+
 	if(!drawablep || drawablep->isDead())
 	{
 		return;
@@ -3424,6 +3446,8 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 		gGLLastMatrix = NULL;
 		glLoadMatrixd(gGLModelView);
 		doOcclusion(camera);
+		gGLLastMatrix = NULL;
+		glLoadMatrixd(gGLModelView);
 	}
 }
 
@@ -3548,6 +3572,63 @@ void LLPipeline::renderDebug()
 		}
 	}
 
+	if (gSavedSettings.getBOOL("DebugShowUploadCost"))
+	{
+		std::set<LLUUID> textures;
+		std::set<LLUUID> sculpts;
+		std::set<LLUUID> meshes;
+		
+		BOOL selected = TRUE;
+		if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
+		{
+			selected = FALSE;
+		}
+			
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			LLSpatialGroup::OctreeNode* node = group->mOctreeNode;
+			for (LLSpatialGroup::OctreeNode::element_iter elem = node->getData().begin(); elem != node->getData().end(); ++elem)
+			{
+				LLDrawable* drawable = *elem;
+				LLVOVolume* volume = drawable->getVOVolume();
+				if (volume && volume->isSelected() == selected)
+				{
+					for (U32 i = 0; i < volume->getNumTEs(); ++i)
+					{
+						LLTextureEntry* te = volume->getTE(i);
+						textures.insert(te->getID());
+					}
+
+					if (volume->isSculpted())
+					{
+						LLUUID sculpt_id = volume->getVolume()->getParams().getSculptID();
+						if (volume->isMesh())
+						{
+							meshes.insert(sculpt_id);
+						}
+						else
+						{
+							sculpts.insert(sculpt_id);
+						}
+					}
+				}
+			}
+		}
+
+		gPipeline.mDebugTextureUploadCost = textures.size() * 10;
+		gPipeline.mDebugSculptUploadCost = sculpts.size()*10;
+		
+		U32 mesh_cost = 0;
+
+		for (std::set<LLUUID>::iterator iter = meshes.begin(); iter != meshes.end(); ++iter)
+		{
+			mesh_cost += gMeshRepo.getResourceCost(*iter)*10;
+		}
+
+		gPipeline.mDebugMeshUploadCost = mesh_cost;
+	}
+
 	for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
 	{
 		LLSpatialBridge* bridge = *i;
@@ -4267,7 +4348,7 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
 		glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 	 0.0f);
 		glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f);
 		glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 		 0.0f);
-		glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 			 180.0f);
+		glLightf (GL_LIGHT1, GL_SPOT_CUTOFF,		 180.0f);
 	}
 	else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini)
 	{
@@ -4361,7 +4442,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera)
 		// mNearbyLight (and all light_set_t's) are sorted such that
 		// begin() == the closest light and rbegin() == the farthest light
 		const S32 MAX_LOCAL_LIGHTS = 6;
-// 		LLVector3 cam_pos = gAgentCamera.getCameraPositionAgent();
+// 		LLVector3 cam_pos = gAgent.getCameraPositionAgent();
 		LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ?
 						camera.getOrigin() : 
 						gAgent.getPositionAgent();
@@ -4555,32 +4636,41 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 			LLVector4 light_pos_gl(light_pos, 1.0f);
 	
 			F32 light_radius = llmax(light->getLightRadius(), 0.001f);
-			F32 atten, quad;
 
-#if 0 //1.9.1
-			if (pool->getVertexShaderLevel() > 0)
-			{
-				atten = light_radius;
-				quad = llmax(light->getLightFalloff(), 0.0001f);
-			}
-			else
-#endif
-			{
-				F32 x = (3.f * (1.f + light->getLightFalloff()));
-				atten = x / (light_radius); // % of brightness at radius
-				quad = 0.0f;
-			}
+			F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic?  probably trying to match a historic behavior.
+			float linatten = x / (light_radius); // % of brightness at radius
+
 			mHWLightColors[cur_light] = light_color;
 			S32 gllight = GL_LIGHT0+cur_light;
 			glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
 			glLightfv(gllight, GL_DIFFUSE,  light_color.mV);
 			glLightfv(gllight, GL_AMBIENT,  LLColor4::black.mV);
-			glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
 			glLightf (gllight, GL_CONSTANT_ATTENUATION,   0.0f);
-			glLightf (gllight, GL_LINEAR_ATTENUATION,     atten);
-			glLightf (gllight, GL_QUADRATIC_ATTENUATION,  quad);
-			glLightf (gllight, GL_SPOT_EXPONENT,          0.0f);
-			glLightf (gllight, GL_SPOT_CUTOFF,            180.0f);
+			glLightf (gllight, GL_LINEAR_ATTENUATION,     linatten);
+			glLightf (gllight, GL_QUADRATIC_ATTENUATION,  0.0f);
+			if (light->isLightSpotlight()) // directional (spot-)light
+			{
+				LLVector3 spotparams = light->getSpotLightParams();
+				LLQuaternion quat = light->getRenderRotation();
+				LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction
+				at_axis *= quat;
+				//llinfos << "SPOT!!!!!!! fov: " << spotparams.mV[0] << " focus: " << spotparams.mV[1] << " dir: " << at_axis << llendl;
+				glLightfv(gllight, GL_SPOT_DIRECTION, at_axis.mV);
+				glLightf (gllight, GL_SPOT_EXPONENT,  2.0f); // 2.0 = good old dot product ^ 2
+				glLightf (gllight, GL_SPOT_CUTOFF,    90.0f); // hemisphere
+				const float specular[] = {0.f, 0.f, 0.f, 0.f};
+				glLightfv(gllight, GL_SPECULAR, specular);
+			}
+			else // omnidirectional (point) light
+			{
+				glLightf (gllight, GL_SPOT_EXPONENT, 0.0f);
+				glLightf (gllight, GL_SPOT_CUTOFF,   180.0f);
+
+				// we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight
+				const float specular[] = {0.f, 0.f, 0.f, 1.f};
+				glLightfv(gllight, GL_SPECULAR, specular);
+				//llinfos << "boring light" << llendl;
+			}
 			cur_light++;
 			if (cur_light >= 8)
 			{
@@ -4596,8 +4686,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 		glLightfv(gllight, GL_AMBIENT,  LLColor4::black.mV);
 		glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
 	}
-
-	if (isAgentAvatarValid() &&
+	if (gAgentAvatarp &&
 		gAgentAvatarp->mSpecialRenderMode == 3)
 	{
 		LLColor4  light_color = LLColor4::white;
@@ -4607,13 +4696,10 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 		LLVector4 light_pos_gl(light_pos, 1.0f);
 
 		F32 light_radius = 16.f;
-		F32 atten, quad;
 
-		{
-			F32 x = 3.f;
-			atten = x / (light_radius); // % of brightness at radius
-			quad = 0.0f;
-		}
+		F32 x = 3.f;
+		float linatten = x / (light_radius); // % of brightness at radius
+
 		mHWLightColors[2] = light_color;
 		S32 gllight = GL_LIGHT2;
 		glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
@@ -4621,8 +4707,8 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 		glLightfv(gllight, GL_AMBIENT,  LLColor4::black.mV);
 		glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
 		glLightf (gllight, GL_CONSTANT_ATTENUATION,   0.0f);
-		glLightf (gllight, GL_LINEAR_ATTENUATION,     atten);
-		glLightf (gllight, GL_QUADRATIC_ATTENUATION,  quad);
+		glLightf (gllight, GL_LINEAR_ATTENUATION,     linatten);
+		glLightf (gllight, GL_QUADRATIC_ATTENUATION,  0.0f);
 		glLightf (gllight, GL_SPOT_EXPONENT,          0.0f);
 		glLightf (gllight, GL_SPOT_CUTOFF,            180.0f);
 	}
@@ -4743,16 +4829,16 @@ void LLPipeline::enableLightsFullbright(const LLColor4& color)
 	enableLights(mask);
 
 	glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
-	if (mLightingDetail >= 2)
+	/*if (mLightingDetail >= 2)
 	{
 		glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default
-	}
+	}*/
 }
 
 void LLPipeline::disableLights()
 {
 	enableLights(0); // no lighting (full bright)
-	glColor4f(1.f, 1.f, 1.f, 1.f); // lighting color = white by default
+	//glColor4f(1.f, 1.f, 1.f, 1.f); // lighting color = white by default
 }
 
 //============================================================================
@@ -5355,6 +5441,7 @@ void LLPipeline::resetVertexBuffers()
 {
 	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
 	sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
+	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
 
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
@@ -5490,6 +5577,7 @@ void LLPipeline::bindScreenToTexture()
 }
 
 static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom");
+
 void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 {
 	LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM);
@@ -5812,6 +5900,12 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 
 		gGL.getTexUnit(0)->activate();
 		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+		if (LLRenderTarget::sUseFBO)
+		{ //copy depth buffer from mScreen to framebuffer
+			LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(), 
+				0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+		}
 	}
 	
 
@@ -6169,7 +6263,6 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRen
 
 	shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
 	shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f);
-	shader.uniform1f("alpha_soften", gSavedSettings.getF32("RenderDeferredAlphaSoften"));
 	shader.uniform1f ("shadow_offset", gSavedSettings.getF32("RenderShadowOffset"));
 	shader.uniform1f("shadow_bias", gSavedSettings.getF32("RenderShadowBias"));
 	shader.uniform1f("lum_scale", gSavedSettings.getF32("RenderLuminanceScale"));
@@ -6265,16 +6358,16 @@ void LLPipeline::renderDeferredLighting()
 			glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
 		}
 
-		if (gSavedSettings.getBOOL("RenderDeferredShadow"))
-		{
-			glPushMatrix();
-			glLoadIdentity();
-			glMatrixMode(GL_PROJECTION);
-			glPushMatrix();
-			glLoadIdentity();
+		glPushMatrix();
+		glLoadIdentity();
+		glMatrixMode(GL_PROJECTION);
+		glPushMatrix();
+		glLoadIdentity();
 
-			mDeferredLight[0].bindTarget();
-			if (gSavedSettings.getBOOL("RenderDeferredSun"))
+		mDeferredLight[0].bindTarget();
+
+		if (gSavedSettings.getBOOL("RenderDeferredSSAO") || gSavedSettings.getS32("RenderShadowDetail") > 0)
+		{
 			{ //paint shadow/SSAO light map (direct lighting lightmap)
 				LLFastTimer ftm(FTM_SUN_SHADOW);
 				bindDeferredShader(gDeferredSunProgram, 0);
@@ -6315,18 +6408,22 @@ void LLPipeline::renderDeferredLighting()
 				
 				unbindDeferredShader(gDeferredSunProgram);
 			}
-			else
-			{
-				mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
-			}
+		}
+		else
+		{
+			glClearColor(1,1,1,1);
+			mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
+			glClearColor(0,0,0,0);
+		}
 
-			mDeferredLight[0].flush();
+		mDeferredLight[0].flush();
 
+		{ //global illumination specific block (still experimental)
 			if (gSavedSettings.getBOOL("RenderDeferredBlurLight") &&
-			    gSavedSettings.getBOOL("RenderDeferredGI"))
-			{
+				gSavedSettings.getBOOL("RenderDeferredGI"))
+			{ 
 				LLFastTimer ftm(FTM_EDGE_DETECTION);
-				//get edge map
+				//generate edge map
 				LLGLDisable blend(GL_BLEND);
 				LLGLDisable test(GL_ALPHA_TEST);
 				LLGLDepthTest depth(GL_FALSE);
@@ -6423,79 +6520,79 @@ void LLPipeline::renderDeferredLighting()
 					unbindDeferredShader(gDeferredPostGIProgram);
 				}
 			}
+		}
 
-			if (gSavedSettings.getBOOL("RenderDeferredBlurLight"))
-			{ //soften direct lighting lightmap
-				LLFastTimer ftm(FTM_SOFTEN_SHADOW);
-				//blur lightmap
-				mDeferredLight[1].bindTarget();
+		if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
+		{ //soften direct lighting lightmap
+			LLFastTimer ftm(FTM_SOFTEN_SHADOW);
+			//blur lightmap
+			mDeferredLight[1].bindTarget();
 
-				glClearColor(1,1,1,1);
-				mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT);
-				glClearColor(0,0,0,0);
-				
-				bindDeferredShader(gDeferredBlurLightProgram);
+			glClearColor(1,1,1,1);
+			mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT);
+			glClearColor(0,0,0,0);
+			
+			bindDeferredShader(gDeferredBlurLightProgram);
 
-				LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian");
-				const U32 kern_length = 4;
-				F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize");
-				F32 dist_factor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
+			LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian");
+			const U32 kern_length = 4;
+			F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize");
+			F32 dist_factor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
 
-				// sample symmetrically with the middle sample falling exactly on 0.0
-				F32 x = 0.f;
+			// sample symmetrically with the middle sample falling exactly on 0.0
+			F32 x = 0.f;
 
-				LLVector3 gauss[32]; // xweight, yweight, offset
+			LLVector3 gauss[32]; // xweight, yweight, offset
 
-				for (U32 i = 0; i < kern_length; i++)
-				{
-					gauss[i].mV[0] = llgaussian(x, go.mV[0]);
-					gauss[i].mV[1] = llgaussian(x, go.mV[1]);
-					gauss[i].mV[2] = x;
-					x += 1.f;
-				}
+			for (U32 i = 0; i < kern_length; i++)
+			{
+				gauss[i].mV[0] = llgaussian(x, go.mV[0]);
+				gauss[i].mV[1] = llgaussian(x, go.mV[1]);
+				gauss[i].mV[2] = x;
+				x += 1.f;
+			}
 
-				gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
-				gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor);
-				gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV);
-				gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
-				gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+			gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
+			gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor);
+			gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV);
+			gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
+			gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+		
+			{
+				LLGLDisable blend(GL_BLEND);
+				LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+				stop_glerror();
+				glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+				stop_glerror();
+			}
 			
-				{
-					LLGLDisable blend(GL_BLEND);
-					LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
-					stop_glerror();
-					glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
-					stop_glerror();
-				}
-				
-				mDeferredLight[1].flush();
-				unbindDeferredShader(gDeferredBlurLightProgram);
+			mDeferredLight[1].flush();
+			unbindDeferredShader(gDeferredBlurLightProgram);
 
-				bindDeferredShader(gDeferredBlurLightProgram, 1);
-				mDeferredLight[0].bindTarget();
+			bindDeferredShader(gDeferredBlurLightProgram, 1);
+			mDeferredLight[0].bindTarget();
 
-				gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
+			gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
 
-				{
-					LLGLDisable blend(GL_BLEND);
-					LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
-					stop_glerror();
-					glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
-					stop_glerror();
-				}
-				mDeferredLight[0].flush();
-				unbindDeferredShader(gDeferredBlurLightProgram);
+			{
+				LLGLDisable blend(GL_BLEND);
+				LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+				stop_glerror();
+				glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+				stop_glerror();
 			}
-
-			stop_glerror();
-			glPopMatrix();
-			stop_glerror();
-			glMatrixMode(GL_MODELVIEW);
-			stop_glerror();
-			glPopMatrix();
-			stop_glerror();
+			mDeferredLight[0].flush();
+			unbindDeferredShader(gDeferredBlurLightProgram);
 		}
 
+		stop_glerror();
+		glPopMatrix();
+		stop_glerror();
+		glMatrixMode(GL_MODELVIEW);
+		stop_glerror();
+		glPopMatrix();
+		stop_glerror();
+
 		//copy depth and stencil from deferred screen
 		//mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
 		//					0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
@@ -6647,7 +6744,7 @@ void LLPipeline::renderDeferredLighting()
 					{ //draw box if camera is outside box
 						if (render_local)
 						{
-							if (volume->getLightTexture())
+							if (volume->isLightSpotlight())
 							{
 								drawablep->getVOVolume()->updateSpotLightPriority();
 								spot_lights.push_back(drawablep);
@@ -6664,7 +6761,7 @@ void LLPipeline::renderDeferredLighting()
 					}
 					else if (render_fullscreen)
 					{	
-						if (volume->getLightTexture())
+						if (volume->isLightSpotlight())
 						{
 							drawablep->getVOVolume()->updateSpotLightPriority();
 							fullscreen_spot_lights.push_back(drawablep);
@@ -6890,6 +6987,23 @@ void LLPipeline::renderDeferredLighting()
 		mRenderTypeMask = render_mask;
 	}
 
+	{
+		//render highlights, etc.
+		renderHighlights();
+		mHighlightFaces.clear();
+
+		renderDebug();
+
+		LLVertexBuffer::unbind();
+
+		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+		{
+			// Render debugging beacons.
+			gObjectList.renderObjectBeacons();
+			gObjectList.resetObjectBeacons();
+		}
+	}
+
 	mScreen.flush();
 						
 }
@@ -7217,17 +7331,16 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 									  (1<<LLPipeline::RENDER_TYPE_SKY) |
 									  (1<<LLPipeline::RENDER_TYPE_CLOUDS));	
 
-				if (gSavedSettings.getBOOL("RenderWaterReflections"))
+				S32 detail = gSavedSettings.getS32("RenderReflectionDetail");
+				if (detail > 0)
 				{ //mask out selected geometry based on reflection detail
-
-					S32 detail = gSavedSettings.getS32("RenderReflectionDetail");
-					if (detail < 3)
+					if (detail < 4)
 					{
 						mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_PARTICLES);
-						if (detail < 2)
+						if (detail < 3)
 						{
 							mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_AVATAR);
-							if (detail < 1)
+							if (detail < 2)
 							{
 								mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_VOLUME);
 							}
@@ -7238,7 +7351,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 					LLGLDisable cull(GL_CULL_FACE);
 					updateCull(camera, ref_result, 1);
 					stateSort(camera, ref_result);
-				}
+				}	
 				
 				ref_mask = mRenderTypeMask;
 				mRenderTypeMask = mask;
@@ -7247,7 +7360,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			if (LLDrawPoolWater::sNeedsDistortionUpdate)
 			{
 				mRenderTypeMask = ref_mask;
-				if (gSavedSettings.getBOOL("RenderWaterReflections"))
+				if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
 				{
 					gPipeline.grabReferences(ref_result);
 					LLGLUserClipPlane clip_plane(plane, mat, projection);
@@ -7885,30 +7998,11 @@ void LLPipeline::generateHighlight(LLCamera& camera)
 
 void LLPipeline::generateSunShadow(LLCamera& camera)
 {
-	if (!sRenderDeferred || !gSavedSettings.getBOOL("RenderDeferredShadow"))
+	if (!sRenderDeferred || gSavedSettings.getS32("RenderShadowDetail") <= 0)
 	{
 		return;
 	}
 
-	//temporary hack to disable shadows but keep local lights
-	static BOOL clear = TRUE;
-	BOOL gen_shadow = gSavedSettings.getBOOL("RenderDeferredSunShadow");
-	if (!gen_shadow)
-	{
-		if (clear)
-		{
-			clear = FALSE;
-			for (U32 i = 0; i < 6; i++)
-			{
-				mShadow[i].bindTarget();
-				mShadow[i].clear();
-				mShadow[i].flush();
-			}
-		}
-		return;
-	}
-	clear = TRUE;
-
 	F64 last_modelview[16];
 	F64 last_projection[16];
 	for (U32 i = 0; i < 16; i++)
@@ -8424,135 +8518,155 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		}
 	}
 
-	
-
-	F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
 
-	//update shadow targets
-	for (U32 i = 0; i < 2; i++)
-	{ //for each current shadow
-		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i;
+	//hack to disable projector shadows 
+	static bool clear = true;
+	bool gen_shadow = gSavedSettings.getS32("RenderShadowDetail") > 1;
+	
+	if (gen_shadow)
+	{
+		clear = true;
+		F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
 
-		if (mShadowSpotLight[i].notNull() && 
-			(mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
-			mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
-		{ //keep this spotlight
-			mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
-		}
-		else
-		{ //fade out this light
-			mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
-			
-			if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
-			{ //faded out, grab one of the pending spots (whichever one isn't already taken)
-				if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
-				{
-					mShadowSpotLight[i] = mTargetShadowSpotLight[0];
-				}
-				else
-				{
-					mShadowSpotLight[i] = mTargetShadowSpotLight[1];
+		//update shadow targets
+		for (U32 i = 0; i < 2; i++)
+		{ //for each current shadow
+			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i;
+
+			if (mShadowSpotLight[i].notNull() && 
+				(mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
+				mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
+			{ //keep this spotlight
+				mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
+			}
+			else
+			{ //fade out this light
+				mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
+				
+				if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
+				{ //faded out, grab one of the pending spots (whichever one isn't already taken)
+					if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
+					{
+						mShadowSpotLight[i] = mTargetShadowSpotLight[0];
+					}
+					else
+					{
+						mShadowSpotLight[i] = mTargetShadowSpotLight[1];
+					}
 				}
 			}
 		}
-	}
-
-	for (S32 i = 0; i < 2; i++)
-	{
-		glh_set_current_modelview(saved_view);
-		glh_set_current_projection(saved_proj);
-
-		if (mShadowSpotLight[i].isNull())
+		
+		for (S32 i = 0; i < 2; i++)
 		{
-			continue;
-		}
+			glh_set_current_modelview(saved_view);
+			glh_set_current_projection(saved_proj);
 
-		LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
+			if (mShadowSpotLight[i].isNull())
+			{
+				continue;
+			}
 
-		if (!volume)
-		{
-			mShadowSpotLight[i] = NULL;
-			continue;
-		}
+			LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
 
-		LLDrawable* drawable = mShadowSpotLight[i];
+			if (!volume)
+			{
+				mShadowSpotLight[i] = NULL;
+				continue;
+			}
 
-		LLVector3 params = volume->getSpotLightParams();
-		F32 fov = params.mV[0];
+			LLDrawable* drawable = mShadowSpotLight[i];
 
-		//get agent->light space matrix (modelview)
-		LLVector3 center = drawable->getPositionAgent();
-		LLQuaternion quat = volume->getRenderRotation();
+			LLVector3 params = volume->getSpotLightParams();
+			F32 fov = params.mV[0];
 
-		//get near clip plane
-		LLVector3 scale = volume->getScale();
-		LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
-		at_axis *= quat;
+			//get agent->light space matrix (modelview)
+			LLVector3 center = drawable->getPositionAgent();
+			LLQuaternion quat = volume->getRenderRotation();
 
-		LLVector3 np = center+at_axis;
-		at_axis.normVec();
+			//get near clip plane
+			LLVector3 scale = volume->getScale();
+			LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+			at_axis *= quat;
 
-		//get origin that has given fov for plane np, at_axis, and given scale
-		F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+			LLVector3 np = center+at_axis;
+			at_axis.normVec();
 
-		LLVector3 origin = np - at_axis*dist;
+			//get origin that has given fov for plane np, at_axis, and given scale
+			F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
 
-		LLMatrix4 mat(quat, LLVector4(origin, 1.f));
+			LLVector3 origin = np - at_axis*dist;
 
-		view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
+			LLMatrix4 mat(quat, LLVector4(origin, 1.f));
 
-		view[i+4] = view[i+4].inverse();
+			view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
 
-		//get perspective matrix
-		F32 near_clip = dist+0.01f;
-		F32 width = scale.mV[VX];
-		F32 height = scale.mV[VY];
-		F32 far_clip = dist+volume->getLightRadius()*1.5f;
+			view[i+4] = view[i+4].inverse();
 
-		F32 fovy = fov * RAD_TO_DEG;
-		F32 aspect = width/height;
-		
-		proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
+			//get perspective matrix
+			F32 near_clip = dist+0.01f;
+			F32 width = scale.mV[VX];
+			F32 height = scale.mV[VY];
+			F32 far_clip = dist+volume->getLightRadius()*1.5f;
 
-		//translate and scale to from [-1, 1] to [0, 1]
-		glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
-						0.f, 0.5f, 0.f, 0.5f,
-						0.f, 0.f, 0.5f, 0.5f,
-						0.f, 0.f, 0.f, 1.f);
+			F32 fovy = fov * RAD_TO_DEG;
+			F32 aspect = width/height;
+			
+			proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
 
-		glh_set_current_modelview(view[i+4]);
-		glh_set_current_projection(proj[i+4]);
+			//translate and scale to from [-1, 1] to [0, 1]
+			glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+							0.f, 0.5f, 0.f, 0.5f,
+							0.f, 0.f, 0.5f, 0.5f,
+							0.f, 0.f, 0.f, 1.f);
 
-		mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
-		
-		for (U32 j = 0; j < 16; j++)
-		{
-			gGLLastModelView[j] = mShadowModelview[i+4].m[j];
-			gGLLastProjection[j] = mShadowProjection[i+4].m[j];
-		}
+			glh_set_current_modelview(view[i+4]);
+			glh_set_current_projection(proj[i+4]);
 
-		mShadowModelview[i+4] = view[i+4];
-		mShadowProjection[i+4] = proj[i+4];
+			mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
+			
+			for (U32 j = 0; j < 16; j++)
+			{
+				gGLLastModelView[j] = mShadowModelview[i+4].m[j];
+				gGLLastProjection[j] = mShadowProjection[i+4].m[j];
+			}
 
-		LLCamera shadow_cam = camera;
-		shadow_cam.setFar(far_clip);
-		shadow_cam.setOrigin(origin);
+			mShadowModelview[i+4] = view[i+4];
+			mShadowProjection[i+4] = proj[i+4];
 
-		LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+			LLCamera shadow_cam = camera;
+			shadow_cam.setFar(far_clip);
+			shadow_cam.setOrigin(origin);
 
-		stop_glerror();
+			LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
 
-		mShadow[i+4].bindTarget();
-		mShadow[i+4].getViewport(gGLViewport);
+			stop_glerror();
+
+			mShadow[i+4].bindTarget();
+			mShadow[i+4].getViewport(gGLViewport);
 
-		static LLCullResult result[2];
+			static LLCullResult result[2];
 
-		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
+			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
 
-		renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
+			renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
 
-		mShadow[i+4].flush();
- 	}
+			mShadow[i+4].flush();
+ 		}
+	}
+	else
+	{
+		if (clear)
+		{
+			clear = false;
+			for (U32 i = 4; i < 6; i++)
+			{
+				mShadow[i].bindTarget();
+				mShadow[i].clear();
+				mShadow[i].flush();
+			}
+		}
+	}
 
 	if (!gSavedSettings.getBOOL("CameraOffset"))
 	{
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 6aecc23aac7ad9cfc5902c14e6a9693f5eed3e12..814c54326a7135cd86831108d4af5ac3bab92edf 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -58,6 +58,8 @@ class LLCubeMap;
 class LLCullResult;
 class LLVOAvatar;
 class LLGLSLShader;
+class LLCurlRequest;
+class LLMeshResponder;
 
 typedef enum e_avatar_skinning_method
 {
@@ -433,6 +435,10 @@ class LLPipeline
 	S32						 mNumVisibleNodes;
 	S32						 mVerticesRelit;
 
+	S32						 mDebugTextureUploadCost;
+	S32						 mDebugSculptUploadCost;
+	S32						 mDebugMeshUploadCost;
+
 	S32						 mLightingChanges;
 	S32						 mGeometryChanges;
 
@@ -672,6 +678,13 @@ class LLPipeline
 protected:
 	std::vector<LLFace*>		mSelectedFaces;
 
+
+	typedef std::map<LLUUID, std::set<LLUUID> > mesh_load_map;
+	mesh_load_map mLoadingMeshes[4];
+	
+	typedef std::list<LLMeshResponder*> mesh_response_list;
+	mesh_response_list			mMeshResponseList;
+
 	LLPointer<LLViewerFetchedTexture>	mFaceSelectImagep;
 	
 	U32						mLightMask;
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index fed326c25e496e09c3388988ea5d7b32081fe37f..2bbb7b2b85cff04f3ea45079f1e9c31adcf415a2 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -245,6 +245,7 @@ with the same filename but different name
   <texture name="Inv_LookFolderOpen" file_name="icons/Inv_LookFolderOpen.png" preload="false" />
   <texture name="Inv_LookFolderClosed" file_name="icons/Inv_LookFolderClosed.png" preload="false" />
   <texture name="Inv_Landmark" file_name="icons/Inv_Landmark.png" preload="false" />
+  <texture name="Inv_Mesh" file_name="icons/Inv_Mesh.png" preload="false" />  
   <texture name="Inv_Notecard" file_name="icons/Inv_Notecard.png" preload="false" />
   <texture name="Inv_Object" file_name="icons/Inv_Object.png" preload="false" />
   <texture name="Inv_Object_Multi" file_name="icons/Inv_Object_Multi.png" preload="false" />
@@ -739,6 +740,8 @@ with the same filename but different name
   <texture name="icon_place_for_sale.tga" />
   <texture name="icon_top_pick.tga" />
 
+  <texture name="inv_folder_mesh.tga"/>
+  <texture name="inv_item_mesh.tga"/>
   <texture name="lag_status_critical.tga" />
   <texture name="lag_status_good.tga" />
   <texture name="lag_status_warning.tga" />
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index d03231a3fa26d45b05077fe606c2bc7ad064ca4c..46208d311df6d3115e9fcb235cfcd3aa7fd91dcc 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -144,17 +144,20 @@ It is a rare mind indeed that can render the hitherto non-existent blindingly ob
        word_wrap="true">
 3Dconnexion SDK Copyright (C) 1992-2007 3Dconnexion
 APR Copyright (C) 2000-2004 The Apache Software Foundation
+  Collada DOM Copyright 2005 Sony Computer Entertainment Inc.
 cURL Copyright (C) 1996-2002, Daniel Stenberg, (daniel@haxx.se)
 DBus/dbus-glib Copyright (C) 2002, 2003  CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc.
 expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
 FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org).
 GL Copyright (C) 1999-2004 Brian Paul.
+  GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
 google-perftools Copyright (c) 2005, Google Inc.
 Havok.com(TM) Copyright (C) 1999-2001, Telekinesys Research Limited.
 jpeg2000 Copyright (C) 2001, David Taubman, The University of New South Wales (UNSW)
 jpeglib Copyright (C) 1991-1998, Thomas G. Lane.
 ogg/vorbis Copyright (C) 2001, Xiphophorus
 OpenSSL Copyright (C) 1998-2002 The OpenSSL Project.
+  PCRE Copyright (c) 1997-2008 University of Cambridge
 Pth Copyright (C) 1999-2006 Ralf S. Engelschall &lt;rse@gnu.org&gt;
 SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
 SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
diff --git a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml
index 90fee857fbb8e6dcd26a6d505662d50b91a9e0af..388825d31a1b4efb8db9f8f2314a657739413a5a 100644
--- a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml
+++ b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml
@@ -102,6 +102,23 @@
      name="icon_notecard"
      top="122"
      width="16" />
+    <check_box
+     height="16"
+     label="Meshes"
+     layout="topleft"
+     left_pad="2"
+     name="check_mesh"
+     top_delta="0"
+     width="126" />
+    <icon
+     height="16"
+     image_name="Inv_Mesh"
+     layout="topleft"
+     left="8"
+     mouse_opaque="true"
+     name="icon_mesh"
+     top="142"
+     width="16" />
     <check_box
      height="16"
      label="Notecards"
@@ -117,7 +134,7 @@
      left="8"
      mouse_opaque="true"
      name="icon_object"
-     top="142"
+     top="162"
      width="16" />
     <check_box
      height="16"
@@ -134,7 +151,7 @@
      left="8"
      mouse_opaque="true"
      name="icon_script"
-     top="162"
+     top="182"
      width="16" />
     <check_box
      height="16"
@@ -151,7 +168,7 @@
      left="8"
      mouse_opaque="true"
      name="icon_sound"
-     top="182"
+     top="202"
      width="16" />
     <check_box
      height="16"
@@ -168,7 +185,7 @@
      left="8"
      mouse_opaque="true"
      name="icon_texture"
-     top="202"
+     top="222"
      width="16" />
     <check_box
      height="16"
@@ -185,7 +202,7 @@
      left="8"
      mouse_opaque="true"
      name="icon_snapshot"
-     top="222"
+     top="242"
      width="16" />
     <check_box
      height="16"
@@ -203,7 +220,7 @@
      layout="topleft"
      left="8"
      name="All"
-     top="242"
+     top="262"
      width="100" />
     <button
      follows="left|top"
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 4c6769894316ffb938eaf747668bd57adfb4288c..c594448df753352ee283b6e36d427503e3240288 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -1996,6 +1996,9 @@ even though the user gets a free copy.
                  label="Cylinder"
                  name="Cylinder"
                  value="Cylinder" />
+                <combo_box.item
+                 label="Mesh"
+                 value="Mesh" />
             </combo_box>
         </panel>
         <panel
diff --git a/indra/newview/skins/default/xui/en/menu_inventory_add.xml b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
index 5ad099e2d9e7f93deb0f7075c25160aad138af2b..4e178eef96436b28a746d4c0dfad1540eb589322 100644
--- a/indra/newview/skins/default/xui/en/menu_inventory_add.xml
+++ b/indra/newview/skins/default/xui/en/menu_inventory_add.xml
@@ -41,6 +41,16 @@
                      parameter="" />
                     <menu_item_call.on_enable
                      function="File.EnableUpload" />
+                </menu_item_call>
+		            <menu_item_call
+                 label="Model..."
+                 layout="topleft"
+                 name="Upload Model">
+                <menu_item_call.on_click
+                 function="File.UploadModel"
+                 parameter="" />
+                <menu_item_call.on_enable
+                 function="File.EnableUploadModel" />
                 </menu_item_call>
                 <menu_item_call
                  label="Bulk (L$[COST] per file)..."
@@ -226,4 +236,4 @@
                      parameter="eyes" />
                 </menu_item_call>
             </menu>
-</menu>
\ No newline at end of file
+</menu>
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index ac31636ed2f1f9e76139d2b1374b80d0a8e595fa..77029e6f6a15b859eebaa5ac2af57c7edb63ef5d 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2063,6 +2063,17 @@
                  function="ToggleControl"
                  parameter="DebugShowTime" />
             </menu_item_check>
+          <menu_item_check
+             label="Show Upload Cost"
+             layout="topleft"
+             name="Show Upload Cost">
+            <menu_item_check.on_check
+             function="CheckControl"
+             parameter="DebugShowUploadCost" />
+            <menu_item_check.on_click
+             function="ToggleControl"
+             parameter="DebugShowUploadCost" />
+          </menu_item_check>
             <menu_item_check
              label="Show Render Info"
              layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 3d41989e545258b44c8af921a8e239783eb13fdf..0e1a77a2f15c23983e9d617536b6b71d30d7d4b7 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -5870,7 +5870,7 @@ Attachment has been saved.
 Unable to find the help topic for this element.
   </notification>
 
-    <notification
+     <notification
  icon="alertmodal.tga"
  name="ObjectMediaFailure"
  type="alertmodal">
@@ -5900,6 +5900,17 @@ Your voice has been muted by moderator.
          name="okbutton"
          yestext="OK"/>
     </notification>
+  
+   <notification
+    icon="alertmodal.tga"
+    name="UploadCostConfirmation"
+    type="alertmodal">
+This upload will cost L$[PRICE], do you wish to continue with the upload?
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Cancel"
+     yestext="Upload"/>
+  </notification>
 
   <notification
    icon="alertmodal.tga"
@@ -5920,6 +5931,12 @@ Selected button can not be shown right now.
 The button will be shown when there is enough space for it.
   </notification>
 
+  <notification
+    name="MeshUploadError"
+    icon="alert.tga"
+    type="alert">
+    [LABEL] failed to upload: [MESSAGE] [IDENTIFIER] [INVALIDITY_IDENTIFIER]
+  </notification>
 
   <global name="UnsupportedCPU">
 - Your CPU speed does not meet the minimum requirements.
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 6c81107ddea4dae472295c3855c95bd921ab60c8..869bbd234107d8a51891d711816d64ac5d492558 100644
--- a/indra/newview/skins/default/xui/en/panel_main_inventory.xml
+++ b/indra/newview/skins/default/xui/en/panel_main_inventory.xml
@@ -104,6 +104,16 @@
                     <menu_item_call.on_enable
                      function="File.EnableUpload" />
                 </menu_item_call>
+                <menu_item_call
+                 label="Model..."
+                 layout="topleft"
+                 name="Upload Model">
+                    <menu_item_call.on_click
+                     function="File.UploadModel"
+                     parameter="" />
+                    <menu_item_call.on_enable
+                     function="File.EnableUploadModel" />
+                </menu_item_call>
                 <menu_item_call
                  label="Bulk (L$[COST] per file)..."
                  layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
index c74de043e923f5f369c4a0888679d90111a6968b..66eae5f51633314020bdbcb87bb398623e3db53e 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -182,12 +182,12 @@
 	 visiblity_control="ShowAdvancedGraphicsSettings"
      border="false"
 	 follows="top|left"
-     height="260"
+     height="283"
      label="CustomGraphics"
      layout="topleft"
      left="5"
      name="CustomGraphics Panel"
-     top="124"
+     top="101"
      width="485">
 		<text
 		type="string"
@@ -238,119 +238,111 @@
 			<check_box.commit_callback
 			function="Pref.VertexShaderEnable" />
 		</check_box>
-		<check_box
-		control_name="RenderWaterReflections"
+    <check_box
+		control_name="RenderDeferred"
 		height="16"
 		initial_value="true"
-		label="Water reflections"
+		label="Lighting and Shadows"
 		layout="topleft"
 		left_delta="0"
-		name="Reflections"
+		name="UseLightShaders"
 		top_pad="1"
 		width="256">
-			<check_box.commit_callback
+      <check_box.commit_callback
 			function="Pref.VertexShaderEnable" />
-		</check_box>
-		<text
-		type="string"
-		length="1"
-		follows="left|top"
-		height="12"
-		layout="topleft"
-		left_delta="0"
-		name="ReflectionDetailText"
-		top_pad="7"
-		width="128">
-			Reflection detail:
-		</text>
-		<radio_group
-		control_name="RenderReflectionDetail"
-		draw_border="false"
-		height="70"
-		layout="topleft"
-		left_delta="-2"
-		name="ReflectionDetailRadio"
-		top_pad="3"
-		width="321">
-			<radio_item
-			height="16"
-			label="Terrain and trees"
-			layout="topleft"
-			left="3"
-			name="0"
-			top="3"
-			width="315" />
-			<radio_item
-			height="16"
-			label="All static objects"
-			layout="topleft"
-			left_delta="0"
-			name="1"
-			top_delta="16"
-			width="315" />
-			<radio_item
-			height="16"
-			label="All avatars and objects"
-			layout="topleft"
-			left_delta="0"
-			name="2"
-			top_delta="16"
-			width="315" />
-			<radio_item
-			height="16"
-			label="Everything"
-			layout="topleft"
-			left_delta="0"
-			name="3"
-			top_delta="16"
-			width="315" />
-		</radio_group>
-		<text
-		type="string"
-		length="1"
-		follows="left|top"
-		height="12"
-		layout="topleft"
-		left_delta="2"
-		name="AvatarRenderingText"
-		top_pad="5"
-		width="128">
-			Avatar rendering:
-		</text>
-		<check_box
-		control_name="RenderUseImpostors"
-		height="16"
-		initial_value="true"
-		label="Avatar impostors"
-		layout="topleft"
-		left_delta="0"
-		name="AvatarImpostors"
-		top_pad="7"
-		width="256" />
-		<check_box
-		control_name="RenderAvatarVP"
+    </check_box>
+    <check_box
+		control_name="RenderDeferredSSAO"
 		height="16"
 		initial_value="true"
-		label="Hardware skinning"
+		label="Ambient Occlusion"
 		layout="topleft"
 		left_delta="0"
-		name="AvatarVertexProgram"
+		name="UseSSAO"
 		top_pad="1"
 		width="256">
-			<check_box.commit_callback
+      <check_box.commit_callback
 			function="Pref.VertexShaderEnable" />
-		</check_box>
-		<check_box
-		control_name="RenderAvatarCloth"
-		height="16"
-		initial_value="true"
-		label="Avatar cloth"
-		layout="topleft"
-		left_delta="0"
-		name="AvatarCloth"
-		top_pad="1"
-		width="256" />
+    </check_box>
 
+     <text
+    type="string"
+    length="1"
+    top_pad="8"
+    follows="top|left"
+    height="23"
+    width="110"
+    word_wrap="true"
+    layout="topleft"
+    left="10"
+    name="shadows_label">
+        Shadows:
+      </text>
+      <combo_box
+      control_name="RenderShadowDetail"
+      height="23"
+      layout="topleft"
+      left="10"
+      top_pad="0" 
+      name="ShadowDetail"
+      width="150">
+        <combo_box.item
+        label="None"
+        name="0"
+        value="0"/>
+        <combo_box.item
+        label="Sun/Moon"
+        name="1"
+        value="1"/>
+        <combo_box.item
+        label="Sun/Moon + Projectors"
+        name="2"
+        value="2"/>
+      </combo_box>
+
+      <text
+  type="string"
+  length="1"
+  top_pad="8"
+  follows="top|left"
+  height="23"
+  width="110"
+  word_wrap="true"
+  layout="topleft"
+  left="10"
+  name="reflection_label">
+        Water Reflections:
+      </text>
+      <combo_box
+      control_name="RenderReflectionDetail"
+      height="23"
+      layout="topleft"
+      left_="10"
+      top_pad ="0"
+      name="Reflections"
+      width="150">
+        <combo_box.item
+        label="Minimal"
+        name="0"
+        value="0"/>
+        <combo_box.item
+        label="Terrain and trees"
+        name="1"
+        value="1"/>
+        <combo_box.item
+        label="All static objects"
+        name="2"
+        value="2"/>
+        <combo_box.item
+        label="All avatars and objects"
+        name="3"
+        value="3"/>
+        <combo_box.item
+        label="Everything"
+        name="4"
+        value="4"/>
+      </combo_box>
+    
 		<slider
 		control_name="RenderFarClip"
 		decimal_digits="0"
@@ -549,7 +541,7 @@
         layout="topleft"
         left="444"
         name="PostProcessText"
-        top="305"
+        top="328"
         width="128">
            Low
         </text>
@@ -626,46 +618,51 @@
         width="128">
            Low
         </text>
-        <text
-        type="string"
-        length="1"
-        follows="left|top"
-        height="12"
-        layout="topleft"
-        left_delta="-230"
-        name="LightingDetailText"
-        top_pad="8"
-        width="140">
-           Lighting detail:
-        </text>
-        <radio_group
-        control_name="RenderLightingDetail"
-        draw_border="false"
-        height="38"
-        layout="topleft"
-        left_delta="0"
-        name="LightingDetailRadio"
-        top_pad="5"
-        width="321">
-           <radio_item
-            height="16"
-            label="Sun and moon only"
-            layout="topleft"
-            left="3"
-            name="SunMoon"
-            value="0"
-            top="3"
-            width="156" />
-           <radio_item
-            height="16"
-            label="Nearby local lights"
-            layout="topleft"
-            left_delta="0"
-            name="LocalLights"
-            value="1"
-            top_delta="16"
-            width="156" />
-        </radio_group>
+      <text
+      type="string"
+      length="1"
+      follows="left|top"
+      height="12"
+      layout="topleft"
+      left_delta="-230"
+      name="AvatarRenderingText"
+      top_pad="8"
+      width="128">
+        Avatar rendering:
+      </text>
+      <check_box
+      control_name="RenderUseImpostors"
+      height="16"
+      initial_value="true"
+      label="Avatar impostors"
+      layout="topleft"
+      left_delta="0"
+      name="AvatarImpostors"
+      top_pad="7"
+      width="256" />
+      <check_box
+      control_name="RenderAvatarVP"
+      height="16"
+      initial_value="true"
+      label="Hardware skinning"
+      layout="topleft"
+      left_delta="0"
+      name="AvatarVertexProgram"
+      top_pad="1"
+      width="256">
+        <check_box.commit_callback
+        function="Pref.VertexShaderEnable" />
+      </check_box>
+      <check_box
+      control_name="RenderAvatarCloth"
+      height="16"
+      initial_value="true"
+      label="Avatar cloth"
+      layout="topleft"
+      left_delta="0"
+      name="AvatarCloth"
+      top_pad="1"
+      width="256" />
         <text
         type="string"
         length="1"
@@ -674,7 +671,7 @@
         layout="topleft"
         left="358"
         name="TerrainDetailText"
-        top="465"
+        top="488"
         width="155">
            Terrain detail:
         </text>
@@ -703,7 +700,7 @@
             name="2"
             top_delta="16"
             width="315" />
-        </radio_group>
+        </radio_group> -->
 	</panel>
 	
         <button
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 0c73b8d7692eef339fb731053adee4e7e10e170c..69f2f61b801545a76ce20d65dd4299b9b2129273 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -1911,6 +1911,7 @@ Clears (deletes) the media and all params from the given face.
 	<string name="InvFolder Current Outfit">Current Outfit</string>
 	<string name="InvFolder My Outfits">My Outfits</string>
 	<string name="InvFolder Accessories">Accessories</string>
+	<string name="InvFolder Meshes">Meshes</string>
 
   <!-- are used for Friends and Friends/All folders in Inventory "Calling cards" folder. See EXT-694-->
 	<string name="InvFolder Friends">Friends</string>
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 18ac10fe389ef2f91ae46f89605914d8d7056ee0..659ce4a47b964cbc44ab271790a56d40d25af23a 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -268,12 +268,17 @@ def construct(self):
                 self.path('libapr-1.dll')
                 self.path('libaprutil-1.dll')
                 self.path('libapriconv-1.dll')
+                
             except RuntimeError, err:
                 print err.message
                 print "Skipping llcommon.dll (assuming llcommon was linked statically)"
 
             self.disable_manifest_check()
 
+            # Mesh 3rd party libs needed for auto LOD and collada reading
+            self.path("libcollada14dom21.dll")
+            self.path("glod.dll")
+
             # For textures
             if self.args['configuration'].lower() == 'debug':
                 self.path("openjpegd.dll")
@@ -319,9 +324,9 @@ def construct(self):
 
         # For using FMOD for sound... DJS
         self.path("fmod.dll")
-
+       
         self.enable_no_crt_manifest_check()
-        
+
         # Media plugins - QuickTime
         if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"):
             self.path("media_plugin_quicktime.dll")
diff --git a/install.xml b/install.xml
index a74b97230efd351eca5a722432f4b82eedeb698d..4483666fd25f33ab318c309c330aeee0326cf761 100644
--- a/install.xml
+++ b/install.xml
@@ -43,6 +43,39 @@
           </map>
         </map>
       </map>
+      <key>GLOD</key>
+      <map>
+        <key>copyright</key>
+        <string>Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia. All rights reserved.</string>
+        <key>description</key>
+        <string>Geometric Level of Detail for OpenGL</string>
+        <key>license</key>
+        <string>GLOD</string>
+        <key>packages</key>
+        <map>
+          <key>darwin</key>
+          <map>
+            <key>md5sum</key>
+            <string>ab78835bafcad3bb7223eaeecb5a6a4b</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GLOD-1.0pre4-darwin-20090918.tar.bz2</uri>
+          </map>
+          <key>linux</key>
+          <map>
+            <key>md5sum</key>
+            <string>66ae292063b80f3a9fecb46dcd4fe5ec</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GLOD-1.0pre4-linux-20091023.tar.bz2</uri>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>md5sum</key>
+            <string>39fae44d406aa56a0b3d00f5433bbf15</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GLOD-1.0pre4-windows-20100129.tar.bz2</uri>
+          </map>
+        </map>
+      </map>
       <key>SDL</key>
       <map>
         <key>copyright</key>
@@ -220,6 +253,39 @@
           </map>
         </map>
       </map>
+      <key>colladadom</key>
+      <map>
+        <key>copyright</key>
+        <string>Copyright 2005 Sony Computer Entertainment Inc.</string>
+        <key>description</key>
+        <string>Library for processing collada file format</string>
+        <key>license</key>
+        <string>scea</string>
+        <key>packages</key>
+        <map>
+          <key>darwin</key>
+          <map>
+            <key>md5sum</key>
+            <string>786de8bfebb5df3a3b51a7832119f8d8</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-darwin-20090731.tar.bz2</uri>
+          </map>
+          <key>linux</key>
+          <map>
+            <key>md5sum</key>
+            <string>dde909f84fd2b7c56138f8fd193664c4</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-linux-20091203.tar.bz2</uri>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>md5sum</key>
+            <string>6c2267ba2735bb5bc6229bc4366fce86</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-windows-20100129.tar.bz2</uri>
+          </map>
+        </map>
+      </map>
       <key>curl</key>
       <map>
         <key>copyright</key>
@@ -1219,6 +1285,32 @@ anguage Infrstructure (CLI) international standard</string>
           </map>
         </map>
       </map>
+      <key>pcre</key>
+      <map>
+        <key>copyright</key>
+        <string>Copyright (c) 1997-2008 University of Cambridge</string>
+        <key>description</key>
+        <string>Regular expression library</string>
+        <key>license</key>
+        <string>bsd</string>
+        <key>packages</key>
+        <map>
+          <key>darwin</key>
+          <map>
+            <key>md5sum</key>
+            <string>63e2dc55142b8b36521c1b0c9b6ed6bb</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pcre-7.6-darwin-20090730.tar.bz2</uri>
+          </map>
+          <key>linux</key>
+          <map>
+            <key>md5sum</key>
+            <string>0886d0b1cdf104b6341df1832a8a7e09</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/pcre-7.6-linux-20090804.tar.bz2</uri>
+          </map>
+        </map>
+      </map>
       <key>pth</key>
       <map>
         <key>copyright</key>
@@ -1499,6 +1591,75 @@ anguage Infrstructure (CLI) international standard</string>
         <key>url</key>
         <string>http://www.xfree86.org/4.4.0/LICENSE9.html#sgi</string>
       </map>
+      <key>GLOD</key>
+      <map>
+        <key>text</key>
+        <string>The GLOD Open-Source License   Version 1.0             July 22, 2003
+
+Copyright (C) 2003 Jonathan Cohen, Nat Duca, Johns Hopkins University
+and David Luebke, Brenden Schubert, University of Virginia. All rights
+reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, is permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer and
+   request.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer and
+   request in the documentation and/or other materials provided with
+   the distribution.
+
+3. The name "GLOD" must not be used to endorse or promote products
+   derived from this software without prior written permission.
+
+4. Redistributions of any modified version of this source, whether in
+   source or binary form , must include a form of the following
+   acknowledgment: "This product is derived from the GLOD library,
+   which is available from http://www.cs.jhu.edu/~graphics/GLOD."
+
+5. Redistributions of any modified version of this source in binary
+   form must provide, free of charge, access to the modified version
+   of the code.
+
+6. This license shall be governed by and construed and enforced in
+   accordance with the laws of the State of Maryland, without
+   reference to its conflicts of law provisions. The exclusive
+   jurisdiction and venue for all legal actions relating to this
+   license shall be in courts of competent subject matter jurisdiction
+   located in the State of Maryland.
+
+TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, GLOD IS PROVIDED
+UNDER THIS LICENSE ON AN AS IS BASIS, WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
+THAT GLOD IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR
+PURPOSE OR NON-INFRINGING. ALL WARRANTIES ARE DISCLAIMED AND THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE CODE IS WITH
+YOU. SHOULD ANY CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE
+COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY
+NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY
+CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY CODE IS
+AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL
+THE COPYRIGHT HOLDER OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
+SPECIAL, INCIDENTAL, INDIRECT, OR CONSEQUENTIAL DAMAGES FOR LOSS OF
+PROFITS, REVENUE, OR FOR LOSS OF INFORMATION OR ANY OTHER LOSS.
+
+YOU EXPRESSLY AGREE TO FOREVER INDEMNIFY, DEFEND AND HOLD HARMLESS THE
+COPYRIGHT HOLDERS AND CONTRIBUTORS OF GLOD AGAINST ALL CLAIMS,
+DEMANDS, SUITS OR OTHER ACTIONS ARISING DIRECTLY OR INDIRECTLY FROM
+YOUR ACCEPTANCE AND USE OF GLOD.
+
+Although NOT REQUIRED, we would appreciate it if active users of GLOD
+put a link on their web site to the GLOD web site when possible.
+</string>
+        <key>url</key>
+        <string>http://www.cs.jhu.edu/~graphics/GLOD/license/</string>
+      </map>
       <key>MSDTW</key>
       <map>
         <key>text</key>
@@ -1824,6 +1985,11 @@ IMPORTANT NOTE: To the extent this software may be used to reproduce materials,
 EA0300
 </string>
       </map>
+      <key>scea</key>
+      <map>
+        <key>url</key>
+        <string>http://research.scea.com/scea_shared_source_license.html</string>
+      </map>
       <key>sleepycat</key>
       <map>
         <key>url</key>