diff --git a/.hgignore b/.hgignore
index 1221b80357b399f9d0a0a208ac76640d22f34e31..dd878b0c1676bb1c69743ff03f880842160073cc 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/etc/message.xml b/etc/message.xml
index c17ae3656d0d8850b496a8f5ce36879bc1062040..7283d903b9ae6c017fe3a583e4d57bffbba1fa11 100644
--- a/etc/message.xml
+++ b/etc/message.xml
@@ -572,6 +572,13 @@
 					<boolean>false</boolean>
 				</map>
 
+				<key>ObjectPhysicsProperties</key>
+				<map>
+					<key>flavor</key>
+					<string>llsd</string>
+					<key>trusted-sender</key>
+					<boolean>true</boolean>
+				</map>
 
 		  </map>
   	  	<key>capBans</key>
diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 592e9fc901b5dbd73581320c256c33c77823df6c..25cc05332b92def14df879031115d49651fd06e6 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
@@ -168,6 +169,8 @@ if (LINUX)
     add_definitions(-fvisibility=hidden)
     # don't catch SIGCHLD in our base application class for the viewer - some of our 3rd party libs may need their *own* SIGCHLD handler to work.  Sigh!  The viewer doesn't need to catch SIGCHLD anyway.
     add_definitions(-DLL_IGNORE_SIGCHLD)
+    add_definitions(-march=pentium4 -mfpmath=sse)
+    #add_definitions(-ftree-vectorize) # THIS CRASHES GCC 3.1-3.2
     if (NOT STANDALONE)
       # this stops us requiring a really recent glibc at runtime
       add_definitions(-fno-stack-protector)
@@ -207,7 +210,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 89422fbdb2d8fa76dca4b0464cf0c208ce2714c7..9900a8fb455565cf9704d7fb3398bb108bf5dbc0 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -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 bfaf3f4f26fc4d88958f0652c96f075c01623d5e..28feb523ea97ad35077e49275f890e98f88accc8 100644
--- a/indra/cmake/Variables.cmake
+++ b/indra/cmake/Variables.cmake
@@ -81,7 +81,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
   # otherwise CMAKE_OSX_SYSROOT will be overridden here. We can't just check
   # for it being unset, as it gets set to the system default :(
 
-  # Default to building against the 10.4 SDK if no deployment target is
+  # Default to building against the 10.4u SDK if no deployment target is
   # specified.
   if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
     # NOTE: setting -isysroot is NOT adequate: http://lists.apple.com/archives/Xcode-users/2007/Oct/msg00696.html
diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 2cd29448ae4ef7ba9c628b737818087902dc2311..476a23ec6440082a1842088dfad969c009c802ce 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -99,8 +99,12 @@ 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));
+#if LL_MESH_ENABLED
+	addEntry(LLAssetType::AT_MESH,              new AssetEntry("MESH",              "mesh",     "mesh",             false, false, false));
+#endif
+	
+	addEntry(LLAssetType::AT_NONE, 				new AssetEntry("NONE",				"-1",		NULL,		  		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..ebc43134cbe4ccc93b078c05880aa9a5cce19567 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -114,8 +114,12 @@ class LL_COMMON_API LLAssetType
 
 		AT_LINK_FOLDER = 25,
 			// Inventory folder link
-		
-		AT_COUNT = 26,
+#if LL_MESH_ENABLED
+		AT_MESH = 49,
+		    // Mesh data in our proprietary SLM format
+#endif
+
+		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/lldefs.h b/indra/llcommon/lldefs.h
index f3b5ca361f8a82a44200025c63440131dafb493b..10e6cb34bfa04ce95c3e32101347dc1847bb6231 100644
--- a/indra/llcommon/lldefs.h
+++ b/indra/llcommon/lldefs.h
@@ -242,5 +242,13 @@ inline LLDATATYPE llclampb(const LLDATATYPE& a)
 	return llmin(llmax(a, (LLDATATYPE)0), (LLDATATYPE)255);
 }
 
+template <class LLDATATYPE> 
+inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs)
+{
+	LLDATATYPE tmp = lhs;
+	lhs = rhs;
+	rhs = tmp;
+}
+
 #endif // LL_LLDEFS_H
 
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/llmemory.cpp b/indra/llcommon/llmemory.cpp
index 2a8015e26d9542e392e1219859e49ab44dcdecc2..5c6ca30cdd0292819615fb24a56f12cd5956c5a3 100644
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -73,25 +73,6 @@ void LLMemory::freeReserve()
 	reserveMem = NULL;
 }
 
-void* ll_allocate (size_t size)
-{
-	if (size == 0)
-	{
-		llwarns << "Null allocation" << llendl;
-	}
-	void *p = malloc(size);
-	if (p == NULL)
-	{
-		LLMemory::freeReserve();
-		llerrs << "Out of memory Error" << llendl;
-	}
-	return p;
-}
-
-void ll_release (void *p)
-{
-	free(p);
-}
 
 //----------------------------------------------------------------------------
 
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index 1c6f64dd8bcc5ad0fb112abce920352156adca74..1c8c91f57e2e5c4e3b3fdc4e7b3b79f3b9f85978 100644
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -32,14 +32,59 @@
 #ifndef LLMEMORY_H
 #define LLMEMORY_H
 
+#include <stdlib.h>
 
+inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
+{
+#if defined(LL_WINDOWS)
+	return _mm_malloc(size, 16);
+#elif defined(LL_DARWIN)
+	return malloc(size); // default osx malloc is 16 byte aligned.
+#else
+	void *rtn;
+	if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
+		return rtn;
+	else // bad alignment requested, or out of memory
+		return NULL;
+#endif
+}
 
-extern S32 gTotalDAlloc;
-extern S32 gTotalDAUse;
-extern S32 gDACount;
+inline void ll_aligned_free_16(void *p)
+{
+#if defined(LL_WINDOWS)
+	_mm_free(p);
+#elif defined(LL_DARWIN)
+	return free(p);
+#else
+	free(p); // posix_memalign() is compatible with heap deallocator
+#endif
+}
 
-extern void* ll_allocate (size_t size);
-extern void ll_release (void *p);
+inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
+{
+#if defined(LL_WINDOWS)
+	return _mm_malloc(size, 32);
+#elif defined(LL_DARWIN)
+# error implement me.
+#else
+	void *rtn;
+	if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
+		return rtn;
+	else // bad alignment requested, or out of memory
+		return NULL;
+#endif
+}
+
+inline void ll_aligned_free_32(void *p)
+{
+#if defined(LL_WINDOWS)
+	_mm_free(p);
+#elif defined(LL_DARWIN)
+# error implement me.
+#else
+	free(p); // posix_memalign() is compatible with heap deallocator
+#endif
+}
 
 class LL_COMMON_API LLMemory
 {
diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp
index cf337be1615fc7860c478d1772ebc9c6b9f14f3b..fdeb93e27f23bef50a1635ab7d8b2fc3a5a7b7d4 100644
--- a/indra/llcommon/llsdserialize.cpp
+++ b/indra/llcommon/llsdserialize.cpp
@@ -39,6 +39,7 @@
 
 #include <iostream>
 #include "apr_base64.h"
+#include "zlib/zlib.h"  // for davep's dirty little zip functions
 
 #if !LL_WINDOWS
 #include <netinet/in.h> // htonl & ntohl
@@ -1989,3 +1990,141 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
 	return s;
 }
 
+
+//dirty little zippers -- yell at davep if these are horrid
+
+//return a string containing gzipped bytes of binary serialized LLSD
+// VERY inefficient -- creates several copies of LLSD block in memory
+std::string zip_llsd(LLSD& data)
+{ 
+	std::stringstream llsd_strm;
+
+	LLSDSerialize::serialize(data, llsd_strm, LLSDSerialize::LLSD_BINARY);
+
+	z_stream strm;
+	strm.zalloc = Z_NULL;
+	strm.zfree = Z_NULL;
+	strm.opaque = Z_NULL;
+
+	S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION);
+	if (ret != Z_OK)
+	{
+		llwarns << "Failed to compress LLSD block." << llendl;
+		return std::string();
+	}
+
+	std::string source = llsd_strm.str();
+
+	strm.avail_in = source.size();
+	strm.next_in = (U8*) source.data();
+	U8* output = new U8[strm.avail_in];
+	strm.avail_out = strm.avail_in;
+	strm.next_out = output;
+	ret = deflate(&strm, Z_FINISH);
+	if (ret != Z_STREAM_END)
+	{
+		delete [] output;
+		llwarns << "Failed to compress LLSD block." << llendl;
+		return std::string();
+	}
+
+	std::string::size_type size = source.size()-strm.avail_out;
+
+	std::string result((char*) output, size);
+	deflateEnd(&strm);
+	delete [] output;
+
+	return result;
+}
+
+//decompress a block of LLSD from provided istream
+// not very efficient -- creats a copy of decompressed LLSD block in memory
+// and deserializes from that copy using LLSDSerialize
+bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
+{
+	U8* result = NULL;
+	U32 cur_size = 0;
+	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
+	{
+		std::string res_str((char*) result, cur_size);
+		std::istringstream istr(res_str);
+
+		if (!LLSDSerialize::deserialize(data, istr, cur_size))
+		{
+			llwarns << "Failed to unzip LLSD block" << llendl;
+			free(result);
+			return false;
+		}
+	}
+
+	free(result);
+	return true;
+}
+
+
+
diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h
index 2f2b292189bf099373899d3eb48d0ddddc16d74c..390eaca783828ae5b3c21159b89aeff2f1988e81 100644
--- a/indra/llcommon/llsdserialize.h
+++ b/indra/llcommon/llsdserialize.h
@@ -796,4 +796,8 @@ class LL_COMMON_API LLSDSerialize
 	}
 };
 
+//dirty little zip functions -- yell at davep
+LL_COMMON_API std::string zip_llsd(LLSD& data);
+LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
+
 #endif // LL_LLSDSERIALIZE_H
diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h
index 369b06b48a9be92b2dbcbabb28c4c31a934fdea0..44ea80a36b3b2ebe414655d431137d12ad448517 100644
--- a/indra/llcommon/llstrider.h
+++ b/indra/llcommon/llstrider.h
@@ -51,7 +51,7 @@ template <class Object> class LLStrider
 	void setStride (S32 skipBytes)	{ mSkip = (skipBytes ? skipBytes : sizeof(Object));}
 
 	void skip(const U32 index)     { mBytep += mSkip*index;}
-
+	U32 getSkip() const			   { return mSkip; }
 	Object* get()                  { return mObjectp; }
 	Object* operator->()           { return mObjectp; }
 	Object& operator *()           { return *mObjectp; }
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 dbb8ec5231ac8fb9eafd6fe82874268e28f57815..0dc3e0b694ac2e09de4a645cbfd7237e3c0939bf 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
 	virtual ~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 51e5f14bfe033de01e9a5e1329d5589ea3045339..792a7f1c3cf74f4b66e983eb0093337b27f55e2f 100755
--- a/indra/llcrashlogger/llcrashlogger.cpp
+++ b/indra/llcrashlogger/llcrashlogger.cpp
@@ -375,6 +375,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 c050f20a9dea4f02a743e49a052e8bfcb656cfa4..82cd22a83226f1e90400dc76ded1277e225dd792 100644
--- a/indra/llinventory/llinventorytype.cpp
+++ b/indra/llinventory/llinventorytype.cpp
@@ -89,6 +89,10 @@ 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)); 
+#if LL_MESH_ENABLED
+	addEntry(LLInventoryType::IT_MESH,                new InventoryEntry("mesh",      "mesh",          1, LLAssetType::AT_MESH));
+#endif
+
 }
 
 
@@ -123,6 +127,34 @@ 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
+#if LL_MESH_ENABLED
+	LLInventoryType::IT_MESH            // AT_MESH
+#endif
 };
 
 // static
diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h
index 20da95400225f11f073a9e85965e742f71e3a73f..d2fc67ef6451d8ba55600dba1f5f5b5770974433 100644
--- a/indra/llinventory/llinventorytype.h
+++ b/indra/llinventory/llinventorytype.h
@@ -67,7 +67,11 @@ class LLInventoryType
 		IT_WEARABLE = 18,
 		IT_ANIMATION = 19,
 		IT_GESTURE = 20,
-		IT_COUNT = 21,
+
+#if LL_MESH_ENABLED
+		IT_MESH = 22,
+#endif
+		IT_COUNT = 23,
 
 		IT_NONE = -1
 	};
diff --git a/indra/llmath/CMakeLists.txt b/indra/llmath/CMakeLists.txt
index e93fe906505cb9e406b5db16457c969f019d392d..dda07133d5933c37bf1bcc8da36937ea8d14f393 100644
--- a/indra/llmath/CMakeLists.txt
+++ b/indra/llmath/CMakeLists.txt
@@ -22,6 +22,7 @@ set(llmath_SOURCE_FILES
     llsphere.cpp
     llvolume.cpp
     llvolumemgr.cpp
+    llvolumeoctree.cpp
     llsdutil_math.cpp
     m3math.cpp
     m4math.cpp
@@ -62,8 +63,11 @@ set(llmath_HEADER_FILES
     llv4matrix3.h
     llv4matrix4.h
     llv4vector3.h
+    llvector4a.h
+    llmatrix4a.h
     llvolume.h
     llvolumemgr.h
+    llvolumeoctree.h
     llsdutil_math.h
     m3math.h
     m4math.h
diff --git a/indra/llmath/llcamera.cpp b/indra/llmath/llcamera.cpp
index 487ed6451f44b0ea28f0ea00c9621fcbddd58685..6b56e4870ed45903d2c30282a17e15368ff66def 100644
--- a/indra/llmath/llcamera.cpp
+++ b/indra/llmath/llcamera.cpp
@@ -48,10 +48,10 @@ LLCamera::LLCamera() :
 	mPlaneCount(6),
 	mFrustumCornerDist(0.f)
 {
+	alignPlanes();
 	calculateFrustumPlanes();
 } 
 
-
 LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane) :
 	LLCoordFrame(),
 	mViewHeightInPixels(view_height_in_pixels),
@@ -59,6 +59,7 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p
 	mPlaneCount(6),
 	mFrustumCornerDist(0.f)
 {
+	alignPlanes();
 	mAspect = llclamp(aspect_ratio, MIN_ASPECT_RATIO, MAX_ASPECT_RATIO);
 	mNearPlane = llclamp(near_plane, MIN_NEAR_PLANE, MAX_NEAR_PLANE);
 	if(far_plane < 0) far_plane = DEFAULT_FAR_PLANE;
@@ -67,6 +68,23 @@ LLCamera::LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_p
 	setView(vertical_fov_rads);
 } 
 
+LLCamera::~LLCamera()
+{
+
+}
+
+const LLCamera& LLCamera::operator=(const LLCamera& rhs)
+{
+	memcpy(this, &rhs, sizeof(LLCamera));
+	alignPlanes();
+	LLVector4a::memcpyNonAliased16((F32*) mAgentPlanes, (F32*) rhs.mAgentPlanes, 4*7);
+	return *this;
+}
+
+void LLCamera::alignPlanes()
+{
+	mAgentPlanes = (LLPlane*) LL_NEXT_ALIGNED_ADDRESS<U8>(mAgentPlaneBuffer);
+}
 
 // ---------------- LLCamera::getFoo() member functions ----------------
 
@@ -91,8 +109,8 @@ F32 LLCamera::getMaxView() const
 void LLCamera::setUserClipPlane(LLPlane plane)
 {
 	mPlaneCount = 7;
-	mAgentPlanes[6].p = plane;
-	mAgentPlanes[6].mask = calcPlaneMask(plane);
+	mAgentPlanes[6] = plane;
+	mPlaneMask[6] = calcPlaneMask(plane);
 }
 
 void LLCamera::disableUserClipPlane()
@@ -164,129 +182,66 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
 
 // ---------------- test methods  ---------------- 
 
-S32 LLCamera::AABBInFrustum(const LLVector3 &center, const LLVector3& radius) 
-{
-	static const LLVector3 scaler[] = {
-		LLVector3(-1,-1,-1),
-		LLVector3( 1,-1,-1),
-		LLVector3(-1, 1,-1),
-		LLVector3( 1, 1,-1),
-		LLVector3(-1,-1, 1),
-		LLVector3( 1,-1, 1),
-		LLVector3(-1, 1, 1),
-		LLVector3( 1, 1, 1)
+S32 LLCamera::AABBInFrustum(const LLVector4a &center, const LLVector4a& radius) 
+{
+	static const LLVector4a scaler[] = {
+		LLVector4a(-1,-1,-1),
+		LLVector4a( 1,-1,-1),
+		LLVector4a(-1, 1,-1),
+		LLVector4a( 1, 1,-1),
+		LLVector4a(-1,-1, 1),
+		LLVector4a( 1,-1, 1),
+		LLVector4a(-1, 1, 1),
+		LLVector4a( 1, 1, 1)
 	};
 
 	U8 mask = 0;
 	S32 result = 2;
 
-	/*if (mFrustumCornerDist > 0.f && radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
-	{ //box is larger than frustum, check frustum quads against box planes
-
-		static const LLVector3 dir[] = 
-		{
-			LLVector3(1, 0, 0),
-			LLVector3(-1, 0, 0),
-			LLVector3(0, 1, 0),
-			LLVector3(0, -1, 0),
-			LLVector3(0, 0, 1),
-			LLVector3(0, 0, -1)
-		};
-
-		U32 quads[] = 
+	for (U32 i = 0; i < mPlaneCount; i++)
+	{
+		mask = mPlaneMask[i];
+		if (mask == 0xff)
 		{
-			0, 1, 2, 3,
-			0, 1, 5, 4,
-			2, 3, 7, 6,
-			3, 0, 7, 4,
-			1, 2, 6, 4,
-			4, 5, 6, 7
-		};
-
-		result = 0;
-
-		BOOL total_inside = TRUE;
-		for (U32 i = 0; i < 6; i++)
-		{ 
-			LLVector3 p = center + radius.scaledVec(dir[i]);
-			F32 d = -p*dir[i];
-
-			for (U32 j = 0; j <	6; j++)
-			{ //for each quad
-				F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d;
-				if (dist > 0)
-				{ //at least one frustum point is outside the AABB
-					total_inside = FALSE;
-					for (U32 k = 1; k < 4; k++)
-					{ //for each other point on quad
-						if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d  <= 0.f)
-						{ //quad is straddling some plane of AABB
-							return 1;
-						}
-					}
-				}
-				else
-				{
-					for (U32 k = 1; k < 4; k++)
-					{
-						if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f)
-						{
-							return 1;
-						}
-					}
-				}
-			}
+			continue;
 		}
 
-		if (total_inside)
+		const LLPlane& p = mAgentPlanes[i];
+		const LLVector4a& n = reinterpret_cast<const LLVector4a&>(p);
+		float d = p.mV[3];
+		LLVector4a rscale;
+		rscale.setMul(radius, scaler[mask]);
+
+		LLVector4a minp, maxp;
+		minp.setSub(center, rscale);
+		maxp.setAdd(center, rscale);
+
+		if (n.dot3(minp) > -d) 
 		{
-			result = 1;
+			return 0;
 		}
-	}
-	else*/
-	{
-		for (U32 i = 0; i < mPlaneCount; i++)
+	
+		if (n.dot3(maxp) > -d)
 		{
-			mask = mAgentPlanes[i].mask;
-			if (mask == 0xff)
-			{
-				continue;
-			}
-			LLPlane p = mAgentPlanes[i].p;
-			LLVector3 n = LLVector3(p);
-			float d = p.mV[3];
-			LLVector3 rscale = radius.scaledVec(scaler[mask]);
-
-			LLVector3 minp = center - rscale;
-			LLVector3 maxp = center + rscale;
-
-			if (n * minp > -d) 
-			{
-				return 0;
-			}
-		
-			if (n * maxp > -d)
-			{
-				result = 1;
-			}
+			result = 1;
 		}
 	}
 
-	
 	return result;
 }
 
-S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius) 
-{
-	static const LLVector3 scaler[] = {
-		LLVector3(-1,-1,-1),
-		LLVector3( 1,-1,-1),
-		LLVector3(-1, 1,-1),
-		LLVector3( 1, 1,-1),
-		LLVector3(-1,-1, 1),
-		LLVector3( 1,-1, 1),
-		LLVector3(-1, 1, 1),
-		LLVector3( 1, 1, 1)
+
+S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius) 
+{
+	static const LLVector4a scaler[] = {
+		LLVector4a(-1,-1,-1),
+		LLVector4a( 1,-1,-1),
+		LLVector4a(-1, 1,-1),
+		LLVector4a( 1, 1,-1),
+		LLVector4a(-1,-1, 1),
+		LLVector4a( 1,-1, 1),
+		LLVector4a(-1, 1, 1),
+		LLVector4a( 1, 1, 1)
 	};
 
 	U8 mask = 0;
@@ -299,25 +254,28 @@ S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& r
 			continue;
 		}
 
-		mask = mAgentPlanes[i].mask;
+		mask = mPlaneMask[i];
 		if (mask == 0xff)
 		{
 			continue;
 		}
-		LLPlane p = mAgentPlanes[i].p;
-		LLVector3 n = LLVector3(p);
+
+		const LLPlane& p = mAgentPlanes[i];
+		const LLVector4a& n = reinterpret_cast<const LLVector4a&>(p);
 		float d = p.mV[3];
-		LLVector3 rscale = radius.scaledVec(scaler[mask]);
+		LLVector4a rscale;
+		rscale.setMul(radius, scaler[mask]);
 
-		LLVector3 minp = center - rscale;
-		LLVector3 maxp = center + rscale;
+		LLVector4a minp, maxp;
+		minp.setSub(center, rscale);
+		maxp.setAdd(center, rscale);
 
-		if (n * minp > -d) 
+		if (n.dot3(minp) > -d) 
 		{
 			return 0;
 		}
 	
-		if (n * maxp > -d)
+		if (n.dot3(maxp) > -d)
 		{
 			result = 1;
 		}
@@ -447,12 +405,12 @@ int LLCamera::sphereInFrustum(const LLVector3 &sphere_center, const F32 radius)
 	int res = 2;
 	for (int i = 0; i < 6; i++)
 	{
-		if (mAgentPlanes[i].mask == 0xff)
+		if (mPlaneMask[i] == 0xff)
 		{
 			continue;
 		}
 
-		float d = mAgentPlanes[i].p.dist(sphere_center);
+		float d = mAgentPlanes[i].dist(sphere_center);
 
 		if (d > radius) 
 		{
@@ -644,12 +602,14 @@ void LLCamera::ignoreAgentFrustumPlane(S32 idx)
 		return;
 	}
 
-	mAgentPlanes[idx].mask = 0xff;
-	mAgentPlanes[idx].p.clearVec();
+	mPlaneMask[idx] = 0xff;
+	mAgentPlanes[idx].clearVec();
 }
 
 void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
 {
+	alignPlanes();
+
 	for (int i = 0; i < 8; i++)
 	{
 		mAgentFrustum[i] = frust[i];
@@ -662,27 +622,27 @@ void LLCamera::calcAgentFrustumPlanes(LLVector3* frust)
 	//order of planes is important, keep most likely to fail in the front of the list
 
 	//near - frust[0], frust[1], frust[2]
-	mAgentPlanes[2].p = planeFromPoints(frust[0], frust[1], frust[2]);
+	mAgentPlanes[2] = planeFromPoints(frust[0], frust[1], frust[2]);
 
 	//far  
-	mAgentPlanes[5].p = planeFromPoints(frust[5], frust[4], frust[6]);
+	mAgentPlanes[5] = planeFromPoints(frust[5], frust[4], frust[6]);
 
 	//left  
-	mAgentPlanes[0].p = planeFromPoints(frust[4], frust[0], frust[7]);
+	mAgentPlanes[0] = planeFromPoints(frust[4], frust[0], frust[7]);
 
 	//right  
-	mAgentPlanes[1].p = planeFromPoints(frust[1], frust[5], frust[6]);
+	mAgentPlanes[1] = planeFromPoints(frust[1], frust[5], frust[6]);
 
 	//top  
-	mAgentPlanes[4].p = planeFromPoints(frust[3], frust[2], frust[6]);
+	mAgentPlanes[4] = planeFromPoints(frust[3], frust[2], frust[6]);
 
 	//bottom  
-	mAgentPlanes[3].p = planeFromPoints(frust[1], frust[0], frust[4]);
+	mAgentPlanes[3] = planeFromPoints(frust[1], frust[0], frust[4]);
 
 	//cache plane octant facing mask for use in AABBInFrustum
 	for (U32 i = 0; i < mPlaneCount; i++)
 	{
-		mAgentPlanes[i].mask = calcPlaneMask(mAgentPlanes[i].p);
+		mPlaneMask[i] = calcPlaneMask(mAgentPlanes[i]);
 	}
 }
 
diff --git a/indra/llmath/llcamera.h b/indra/llmath/llcamera.h
index 0c81067919acb567b1bdb32891b2e2b213f043fc..c40e819dcf0b95c2dbaf4950c55bb81edde36c80 100644
--- a/indra/llmath/llcamera.h
+++ b/indra/llmath/llcamera.h
@@ -37,6 +37,7 @@
 #include "llmath.h"
 #include "llcoordframe.h"
 #include "llplane.h"
+#include "llvector4a.h"
 
 const F32 DEFAULT_FIELD_OF_VIEW 	= 60.f * DEG_TO_RAD;
 const F32 DEFAULT_ASPECT_RATIO 		= 640.f / 480.f;
@@ -79,6 +80,14 @@ class LLCamera
 : 	public LLCoordFrame
 {
 public:
+	
+	LLCamera(const LLCamera& rhs)
+	{
+		*this = rhs;
+	}
+
+	const LLCamera& operator=(const LLCamera& rhs);
+	
 	enum {
 		PLANE_LEFT = 0,
 		PLANE_RIGHT = 1,
@@ -129,13 +138,9 @@ class LLCamera
 	LLPlane mWorldPlanes[PLANE_NUM];
 	LLPlane mHorizPlanes[HORIZ_PLANE_NUM];
 
-	struct frustum_plane
-	{
-		frustum_plane() : mask(0) {}
-		LLPlane p;
-		U8 mask;
-	};
-	frustum_plane mAgentPlanes[7];  //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
+	LLPlane* mAgentPlanes;  //frustum planes in agent space a la gluUnproject (I'm a bastard, I know) - DaveP
+	U8 mAgentPlaneBuffer[sizeof(LLPlane)*8];
+	U8 mPlaneMask[7];
 
 	U32 mPlaneCount;  //defaults to 6, if setUserClipPlane is called, uses user supplied clip plane in
 
@@ -143,12 +148,14 @@ class LLCamera
 public:
 	LLVector3 mAgentFrustum[8];  //8 corners of 6-plane frustum
 	F32	mFrustumCornerDist;		//distance to corner of frustum against far clip plane
-	LLPlane getAgentPlane(U32 idx) { return mAgentPlanes[idx].p; }
+	LLPlane& getAgentPlane(U32 idx) { return mAgentPlanes[idx]; }
 
 public:
 	LLCamera();
 	LLCamera(F32 vertical_fov_rads, F32 aspect_ratio, S32 view_height_in_pixels, F32 near_plane, F32 far_plane);
-	virtual ~LLCamera(){} // no-op virtual destructor
+	virtual ~LLCamera();
+	
+	void alignPlanes();
 
 	void setUserClipPlane(LLPlane plane);
 	void disableUserClipPlane();
@@ -199,8 +206,8 @@ class LLCamera
 	S32 sphereInFrustum(const LLVector3 &center, const F32 radius) const;
 	S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
 	S32 sphereInFrustumFull(const LLVector3 &center, const F32 radius) const { return sphereInFrustum(center, radius); }
-	S32 AABBInFrustum(const LLVector3 &center, const LLVector3& radius);
-	S32 AABBInFrustumNoFarClip(const LLVector3 &center, const LLVector3& radius);
+	S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
+	S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
 
 	//does a quick 'n dirty sphere-sphere check
 	S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius); 
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 2f34fb1bb047181df7aa875b71c982e06208b227..59828ae565010df816eb70ab531e4c5868d12415 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -35,6 +35,7 @@
 
 #include "lltreenode.h"
 #include "v3math.h"
+#include "llvector4a.h"
 #include <vector>
 #include <set>
 
@@ -72,6 +73,13 @@ class LLOctreeTraveler
 	virtual void visit(const LLOctreeNode<T>* branch) = 0;
 };
 
+template <class T>
+class LLOctreeTravelerDepthFirst : public LLOctreeTraveler<T>
+{
+public:
+	virtual void traverse(const LLOctreeNode<T>* node);
+};
+
 template <class T>
 class LLOctreeNode : public LLTreeNode<T>
 {
@@ -87,23 +95,22 @@ class LLOctreeNode : public LLTreeNode<T>
 	typedef LLOctreeNode<T>		oct_node;
 	typedef LLOctreeListener<T>	oct_listener;
 
-	static const U8 OCTANT_POSITIVE_X = 0x01;
-	static const U8 OCTANT_POSITIVE_Y = 0x02;
-	static const U8 OCTANT_POSITIVE_Z = 0x04;
-		
-	LLOctreeNode(	LLVector3d center, 
-					LLVector3d size, 
+	LLOctreeNode(	const LLVector4a& center, 
+					const LLVector4a& size, 
 					BaseType* parent, 
-					U8 octant = 255)
+					S32 octant = -1)
 	:	mParent((oct_node*)parent), 
-		mCenter(center), 
-		mSize(size), 
 		mOctant(octant) 
 	{ 
+		mD = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*4);
+
+		mD[CENTER] = center;
+		mD[SIZE] = size;
+
 		updateMinMax();
-		if ((mOctant == 255) && mParent)
+		if ((mOctant == -1) && mParent)
 		{
-			mOctant = ((oct_node*) mParent)->getOctant(mCenter.mdV);
+			mOctant = ((oct_node*) mParent)->getOctant(mD[CENTER]);
 		}
 
 		clearChildren();
@@ -117,43 +124,30 @@ class LLOctreeNode : public LLTreeNode<T>
 		{
 			delete getChild(i);
 		} 
+
+		ll_aligned_free_16(mD);
 	}
 
 	inline const BaseType* getParent()	const			{ return mParent; }
-	inline void setParent(BaseType* parent)			{ mParent = (oct_node*) parent; }
-	inline const LLVector3d& getCenter() const			{ return mCenter; }
-	inline const LLVector3d& getSize() const			{ return mSize; }
-	inline void setCenter(LLVector3d center)			{ mCenter = center; }
-	inline void setSize(LLVector3d size)				{ mSize = size; }
-    inline oct_node* getNodeAt(T* data)				{ return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
-	inline U8 getOctant() const						{ return mOctant; }
-	inline void setOctant(U8 octant)					{ mOctant = octant; }
+	inline void setParent(BaseType* parent)				{ mParent = (oct_node*) parent; }
+	inline const LLVector4a& getCenter() const			{ return mD[CENTER]; }
+	inline const LLVector4a& getSize() const			{ return mD[SIZE]; }
+	inline void setCenter(const LLVector4a& center)		{ mD[CENTER] = center; }
+	inline void setSize(const LLVector4a& size)			{ mD[SIZE] = size; }
+    inline oct_node* getNodeAt(T* data)					{ return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
+	inline S32 getOctant() const						{ return mOctant; }
+	inline void setOctant(S32 octant)					{ mOctant = octant; }
 	inline const oct_node*	getOctParent() const		{ return (const oct_node*) getParent(); }
 	inline oct_node* getOctParent() 					{ return (oct_node*) getParent(); }
 	
-	U8 getOctant(const F64 pos[]) const	//get the octant pos is in
+	S32 getOctant(const LLVector4a& pos) const			//get the octant pos is in
 	{
-		U8 ret = 0;
-
-		if (pos[0] > mCenter.mdV[0])
-		{
-			ret |= OCTANT_POSITIVE_X;
-		}
-		if (pos[1] > mCenter.mdV[1])
-		{
-			ret |= OCTANT_POSITIVE_Y;
-		}
-		if (pos[2] > mCenter.mdV[2])
-		{
-			ret |= OCTANT_POSITIVE_Z;
-		}
-
-		return ret;
+		return pos.greaterThan4(mD[CENTER]).getComparisonMask() & 0x7;
 	}
 	
-	inline bool isInside(const LLVector3d& pos, const F64& rad) const
+	inline bool isInside(const LLVector4a& pos, const F32& rad) const
 	{
-		return rad <= mSize.mdV[0]*2.0 && isInside(pos); 
+		return rad <= mD[SIZE][0]*2.f && isInside(pos); 
 	}
 
 	inline bool isInside(T* data) const			
@@ -161,29 +155,27 @@ class LLOctreeNode : public LLTreeNode<T>
 		return isInside(data->getPositionGroup(), data->getBinRadius());
 	}
 
-	bool isInside(const LLVector3d& pos) const
+	bool isInside(const LLVector4a& pos) const
 	{
-		const F64& x = pos.mdV[0];
-		const F64& y = pos.mdV[1];
-		const F64& z = pos.mdV[2];
-			
-		if (x > mMax.mdV[0] || x <= mMin.mdV[0] ||
-			y > mMax.mdV[1] || y <= mMin.mdV[1] ||
-			z > mMax.mdV[2] || z <= mMin.mdV[2])
+		S32 gt = pos.greaterThan4(mD[MAX]).getComparisonMask() & 0x7;
+		if (gt)
 		{
 			return false;
 		}
-		
+
+		S32 lt = pos.lessEqual4(mD[MIN]).getComparisonMask() & 0x7;
+		if (lt)
+		{
+			return false;
+		}
+				
 		return true;
 	}
 	
 	void updateMinMax()
 	{
-		for (U32 i = 0; i < 3; i++)
-		{
-			mMax.mdV[i] = mCenter.mdV[i] + mSize.mdV[i];
-			mMin.mdV[i] = mCenter.mdV[i] - mSize.mdV[i];
-		}
+		mD[MAX].setAdd(mD[CENTER], mD[SIZE]);
+		mD[MIN].setSub(mD[CENTER], mD[SIZE]);
 	}
 
 	inline oct_listener* getOctListener(U32 index) 
@@ -196,34 +188,34 @@ class LLOctreeNode : public LLTreeNode<T>
 		return contains(xform->getBinRadius());
 	}
 
-	bool contains(F64 radius)
+	bool contains(F32 radius)
 	{
 		if (mParent == NULL)
 		{	//root node contains nothing
 			return false;
 		}
 
-		F64 size = mSize.mdV[0];
-		F64 p_size = size * 2.0;
+		F32 size = mD[SIZE][0];
+		F32 p_size = size * 2.f;
 
-		return (radius <= 0.001 && size <= 0.001) ||
+		return (radius <= 0.001f && size <= 0.001f) ||
 				(radius <= p_size && radius > size);
 	}
 
-	static void pushCenter(LLVector3d &center, const LLVector3d &size, const T* data)
+	static void pushCenter(LLVector4a &center, const LLVector4a &size, const T* data)
 	{
-		const LLVector3d& pos = data->getPositionGroup();
-		for (U32 i = 0; i < 3; i++)
-		{
-			if (pos.mdV[i] > center.mdV[i])
-			{
-				center.mdV[i] += size.mdV[i];
-			}
-			else 
-			{
-				center.mdV[i] -= size.mdV[i];
-			}
-		}
+		const LLVector4a& pos = data->getPositionGroup();
+
+		LLVector4a gt = pos.greaterThan4(center);
+
+		LLVector4a up;
+		up.mQ = _mm_and_ps(size.mQ, gt.mQ);
+
+		LLVector4a down;
+		down.mQ = _mm_andnot_ps(gt.mQ, size.mQ);
+
+		center.add(up);
+		center.sub(down);
 	}
 
 	void accept(oct_traveler* visitor)				{ visitor->visit(this); }
@@ -242,21 +234,21 @@ class LLOctreeNode : public LLTreeNode<T>
 	void accept(tree_traveler* visitor) const		{ visitor->visit(this); }
 	void accept(oct_traveler* visitor) const		{ visitor->visit(this); }
 	
-	oct_node* getNodeAt(const LLVector3d& pos, const F64& rad)
+	oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
 	{ 
 		LLOctreeNode<T>* node = this;
 
 		if (node->isInside(pos, rad))
 		{		
 			//do a quick search by octant
-			U8 octant = node->getOctant(pos.mdV);
+			S32 octant = node->getOctant(pos);
 			BOOL keep_going = TRUE;
 
 			//traverse the tree until we find a node that has no node
 			//at the appropriate octant or is smaller than the object.  
 			//by definition, that node is the smallest node that contains 
 			// the data
-			while (keep_going && node->getSize().mdV[0] >= rad)
+			while (keep_going && node->getSize()[0] >= rad)
 			{	
 				keep_going = FALSE;
 				for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
@@ -264,7 +256,7 @@ class LLOctreeNode : public LLTreeNode<T>
 					if (node->getChild(i)->getOctant() == octant)
 					{
 						node = node->getChild(i);
-						octant = node->getOctant(pos.mdV);
+						octant = node->getOctant(pos);
 						keep_going = TRUE;
 					}
 				}
@@ -282,7 +274,7 @@ class LLOctreeNode : public LLTreeNode<T>
 	{
 		if (data == NULL)
 		{
-			//OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
+			OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE BRANCH !!!" << llendl;
 			return false;
 		}
 		LLOctreeNode<T>* parent = getOctParent();
@@ -292,7 +284,7 @@ class LLOctreeNode : public LLTreeNode<T>
 		{
 			if (getElementCount() < LL_OCTREE_MAX_CAPACITY &&
 				(contains(data->getBinRadius()) ||
-				(data->getBinRadius() > getSize().mdV[0] &&
+				(data->getBinRadius() > getSize()[0] &&
 				parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY))) 
 			{ //it belongs here
 #if LL_OCTREE_PARANOIA_CHECK
@@ -323,16 +315,22 @@ class LLOctreeNode : public LLTreeNode<T>
 				}
 				
 				//it's here, but no kids are in the right place, make a new kid
-				LLVector3d center(getCenter());
-				LLVector3d size(getSize()*0.5);
+				LLVector4a center = getCenter();
+				LLVector4a size = getSize();
+				size.mul(0.5f);
 		        		
 				//push center in direction of data
 				LLOctreeNode<T>::pushCenter(center, size, data);
 
 				// handle case where floating point number gets too small
-				if( llabs(center.mdV[0] - getCenter().mdV[0]) < F_APPROXIMATELY_ZERO &&
-					llabs(center.mdV[1] - getCenter().mdV[1]) < F_APPROXIMATELY_ZERO &&
-					llabs(center.mdV[2] - getCenter().mdV[2]) < F_APPROXIMATELY_ZERO)
+				LLVector4a val;
+				val.setSub(center, getCenter());
+				val.setAbs(val);
+				LLVector4a app_zero;
+				app_zero.mQ = F_APPROXIMATELY_ZERO_4A;
+				S32 lt = val.lessThan4(app_zero).getComparisonMask() & 0x7;
+
+				if( lt == 0x7 )
 				{
 					mData.insert(data);
 					BaseType::insert(data);
@@ -350,7 +348,7 @@ class LLOctreeNode : public LLTreeNode<T>
 				//make sure no existing node matches this position
 				for (U32 i = 0; i < getChildCount(); i++)
 				{
-					if (mChild[i]->getCenter() == center)
+					if (mChild[i]->getCenter().equal3(center))
 					{
 						OCT_ERRS << "Octree detected duplicate child center and gave up." << llendl;
 						return false;
@@ -368,7 +366,7 @@ class LLOctreeNode : public LLTreeNode<T>
 		else 
 		{
 			//it's not in here, give it to the root
-			//OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
+			OCT_ERRS << "Octree insertion failed, starting over from root!" << llendl;
 
 			oct_node* node = this;
 
@@ -475,13 +473,19 @@ class LLOctreeNode : public LLTreeNode<T>
 	void addChild(oct_node* child, BOOL silent = FALSE) 
 	{
 #if LL_OCTREE_PARANOIA_CHECK
+
+		if (child->getSize().equal3(getSize()))
+		{
+			OCT_ERRS << "Child size is same as parent size!" << llendl;
+		}
+
 		for (U32 i = 0; i < getChildCount(); i++)
 		{
-			if(mChild[i]->getSize() != child->getSize()) 
+			if(!mChild[i]->getSize().equal3(child->getSize())) 
 			{
 				OCT_ERRS <<"Invalid octree child size." << llendl;
 			}
-			if (mChild[i]->getCenter() == child->getCenter())
+			if (mChild[i]->getCenter().equal3(child->getCenter()))
 			{
 				OCT_ERRS <<"Duplicate octree child position." << llendl;
 			}
@@ -506,7 +510,7 @@ class LLOctreeNode : public LLTreeNode<T>
 		}
 	}
 
-	void removeChild(U8 index, BOOL destroy = FALSE)
+	void removeChild(S32 index, BOOL destroy = FALSE)
 	{
 		for (U32 i = 0; i < this->getListenerCount(); i++)
 		{
@@ -547,18 +551,26 @@ class LLOctreeNode : public LLTreeNode<T>
 			}
 		}
 
-		//OCT_ERRS << "Octree failed to delete requested child." << llendl;
+		OCT_ERRS << "Octree failed to delete requested child." << llendl;
 	}
 
 protected:	
+	typedef enum
+	{
+		CENTER = 0,
+		SIZE = 1,
+		MAX = 2,
+		MIN = 3
+	} eDName;
+
+	LLVector4a* mD;
+	
+	oct_node* mParent;
+	S32 mOctant;
+
 	child_list mChild;
 	element_list mData;
-	oct_node* mParent;
-	LLVector3d mCenter;
-	LLVector3d mSize;
-	LLVector3d mMax;
-	LLVector3d mMin;
-	U8 mOctant;
+		
 };
 
 //just like a regular node, except it might expand on insert and compress on balance
@@ -569,9 +581,9 @@ class LLOctreeRoot : public LLOctreeNode<T>
 	typedef LLOctreeNode<T>	BaseType;
 	typedef LLOctreeNode<T>		oct_node;
 
-	LLOctreeRoot(	LLVector3d center, 
-					LLVector3d size, 
-					BaseType* parent)
+	LLOctreeRoot(const LLVector4a& center, 
+				 const LLVector4a& size, 
+				 BaseType* parent)
 	:	BaseType(center, size, parent)
 	{
 	}
@@ -612,28 +624,33 @@ class LLOctreeRoot : public LLOctreeNode<T>
 	{
 		if (data == NULL) 
 		{
-			//OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
+			OCT_ERRS << "!!! INVALID ELEMENT ADDED TO OCTREE ROOT !!!" << llendl;
 			return false;
 		}
 		
 		if (data->getBinRadius() > 4096.0)
 		{
-			//OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
+			OCT_ERRS << "!!! ELEMENT EXCEEDS MAXIMUM SIZE IN OCTREE ROOT !!!" << llendl;
 			return false;
 		}
 		
-		const F64 MAX_MAG = 1024.0*1024.0;
+		LLVector4a MAX_MAG;
+		MAX_MAG.splat(1024.f*1024.f);
+
+		const LLVector4a& v = data->getPositionGroup();
+
+		LLVector4a val;
+		val.setSub(v, BaseType::mD[BaseType::CENTER]);
+		val.setAbs(val);
+		S32 lt = val.lessThan4(MAX_MAG).getComparisonMask() & 0x7;
 
-		const LLVector3d& v = data->getPositionGroup();
-		if (!(fabs(v.mdV[0]-this->mCenter.mdV[0]) < MAX_MAG &&
-		      fabs(v.mdV[1]-this->mCenter.mdV[1]) < MAX_MAG &&
-		      fabs(v.mdV[2]-this->mCenter.mdV[2]) < MAX_MAG))
+		if (lt != 0x7)
 		{
-			//OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
+			OCT_ERRS << "!!! ELEMENT EXCEEDS RANGE OF SPATIAL PARTITION !!!" << llendl;
 			return false;
 		}
 
-		if (this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
+		if (this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup()))
 		{
 			//we got it, just act like a branch
 			oct_node* node = getNodeAt(data);
@@ -649,31 +666,34 @@ class LLOctreeRoot : public LLOctreeNode<T>
 		else if (this->getChildCount() == 0)
 		{
 			//first object being added, just wrap it up
-			while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
+			while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
 			{
-				LLVector3d center, size;
+				LLVector4a center, size;
 				center = this->getCenter();
 				size = this->getSize();
 				LLOctreeNode<T>::pushCenter(center, size, data);
 				this->setCenter(center);
-				this->setSize(size*2);
+				size.mul(2.f);
+				this->setSize(size);
 				this->updateMinMax();
 			}
 			LLOctreeNode<T>::insert(data);
 		}
 		else
 		{
-			while (!(this->getSize().mdV[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
+			while (!(this->getSize()[0] > data->getBinRadius() && isInside(data->getPositionGroup())))
 			{
 				//the data is outside the root node, we need to grow
-				LLVector3d center(this->getCenter());
-				LLVector3d size(this->getSize());
+				LLVector4a center(this->getCenter());
+				LLVector4a size(this->getSize());
 
 				//expand this node
-				LLVector3d newcenter(center);
+				LLVector4a newcenter(center);
 				LLOctreeNode<T>::pushCenter(newcenter, size, data);
 				this->setCenter(newcenter);
-				this->setSize(size*2);
+				LLVector4a size2 = size;
+				size2.mul(2.f);
+				this->setSize(size2);
 				this->updateMinMax();
 
 				//copy our children to a new branch
@@ -710,4 +730,15 @@ void LLOctreeTraveler<T>::traverse(const LLOctreeNode<T>* node)
 		traverse(node->getChild(i));
 	}
 }
+
+template <class T>
+void LLOctreeTravelerDepthFirst<T>::traverse(const LLOctreeNode<T>* node)
+{
+	for (U32 i = 0; i < node->getChildCount(); i++)
+	{
+		traverse(node->getChild(i));
+	}
+	node->accept(this);
+}
+
 #endif
diff --git a/indra/llmath/lltreenode.h b/indra/llmath/lltreenode.h
index ee9836241a50c4f18c01b354b3629ed5787467f4..e6d2521b2ac27422b88c3839149c8c2c46e02d26 100644
--- a/indra/llmath/lltreenode.h
+++ b/indra/llmath/lltreenode.h
@@ -34,6 +34,9 @@
 
 #include "stdtypes.h"
 #include "xform.h"
+#include "llpointer.h"
+#include "llrefcount.h"
+
 #include <vector>
 
 template <class T> class LLTreeNode;
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 34348230b6a1ecdedb156b0d5e5f91512504d555..ac3ed5d63ea904ff40066773884828431a89b4ae 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -1,4 +1,5 @@
 /** 
+
  * @file llvolume.cpp
  *
  * $LicenseInfo:firstyear=2002&license=viewergpl$
@@ -30,6 +31,7 @@
  */
 
 #include "linden_common.h"
+#include "llmemory.h"
 #include "llmath.h"
 
 #include <set>
@@ -43,9 +45,14 @@
 #include "v4math.h"
 #include "m4math.h"
 #include "m3math.h"
+#include "llmatrix4a.h"
+#include "lloctree.h"
 #include "lldarray.h"
 #include "llvolume.h"
+#include "llvolumeoctree.h"
 #include "llstl.h"
+#include "llsdserialize.h"
+#include "llvector4a.h"
 
 #define DEBUG_SILHOUETTE_BINORMALS 0
 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
@@ -103,127 +110,264 @@ BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLV
 
 BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size)
 {
-	float fAWdU[3];
-	LLVector3 dir;
-	LLVector3 diff;
+	return LLLineSegmentBoxIntersect(start.mV, end.mV, center.mV, size.mV);
+}
+
+BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size)
+{
+	F32 fAWdU[3];
+	F32 dir[3];
+	F32 diff[3];
 
 	for (U32 i = 0; i < 3; i++)
 	{
-		dir.mV[i] = 0.5f * (end.mV[i] - start.mV[i]);
-		diff.mV[i] = (0.5f * (end.mV[i] + start.mV[i])) - center.mV[i];
-		fAWdU[i] = fabsf(dir.mV[i]);
-		if(fabsf(diff.mV[i])>size.mV[i] + fAWdU[i]) return false;
+		dir[i] = 0.5f * (end[i] - start[i]);
+		diff[i] = (0.5f * (end[i] + start[i])) - center[i];
+		fAWdU[i] = fabsf(dir[i]);
+		if(fabsf(diff[i])>size[i] + fAWdU[i]) return false;
 	}
 
 	float f;
-	f = dir.mV[1] * diff.mV[2] - dir.mV[2] * diff.mV[1];    if(fabsf(f)>size.mV[1]*fAWdU[2] + size.mV[2]*fAWdU[1])  return false;
-	f = dir.mV[2] * diff.mV[0] - dir.mV[0] * diff.mV[2];    if(fabsf(f)>size.mV[0]*fAWdU[2] + size.mV[2]*fAWdU[0])  return false;
-	f = dir.mV[0] * diff.mV[1] - dir.mV[1] * diff.mV[0];    if(fabsf(f)>size.mV[0]*fAWdU[1] + size.mV[1]*fAWdU[0])  return false;
+	f = dir[1] * diff[2] - dir[2] * diff[1];    if(fabsf(f)>size[1]*fAWdU[2] + size[2]*fAWdU[1])  return false;
+	f = dir[2] * diff[0] - dir[0] * diff[2];    if(fabsf(f)>size[0]*fAWdU[2] + size[2]*fAWdU[0])  return false;
+	f = dir[0] * diff[1] - dir[1] * diff[0];    if(fabsf(f)>size[0]*fAWdU[1] + size[1]*fAWdU[0])  return false;
 	
 	return true;
 }
 
 
+
 // intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
 // returns TRUE if intersecting and returns barycentric coordinates in intersection_a, intersection_b,
 // and returns the intersection point along dir in intersection_t.
 
 // Moller-Trumbore algorithm
-BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
-							F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided)
+BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t)
 {
-	F32 u, v, t;
 	
 	/* find vectors for two edges sharing vert0 */
-	LLVector3 edge1 = vert1 - vert0;
+	LLVector4a edge1;
+	edge1.setSub(vert1, vert0);
 	
-	LLVector3 edge2 = vert2 - vert0;;
+	LLVector4a edge2;
+	edge2.setSub(vert2, vert0);
 
 	/* begin calculating determinant - also used to calculate U parameter */
-	LLVector3 pvec = dir % edge2;
-	
-	/* if determinant is near zero, ray lies in plane of triangle */
-	F32 det = edge1 * pvec;
+	LLVector4a pvec;
+	pvec.setCross3(dir, edge2);
 
-	if (!two_sided)
+	/* if determinant is near zero, ray lies in plane of triangle */
+	LLVector4a det;
+	det.setAllDot3(edge1, pvec);
+	
+	if (det.greaterEqual4(LLVector4a::getApproximatelyZero()).getComparisonMask() & 0x7)
 	{
-		if (det < F_APPROXIMATELY_ZERO)
-		{
-			return FALSE;
-		}
-
 		/* calculate distance from vert0 to ray origin */
-		LLVector3 tvec = orig - vert0;
+		LLVector4a tvec;
+		tvec.setSub(orig, vert0);
 
 		/* calculate U parameter and test bounds */
-		u = tvec * pvec;	
+		LLVector4a u;
+		u.setAllDot3(tvec,pvec);
 
-		if (u < 0.f || u > det)
+		if ((u.greaterEqual4(LLVector4a::getZero()).getComparisonMask() & 0x7) &&
+			(u.lessEqual4(det).getComparisonMask() & 0x7))
 		{
-			return FALSE;
+			/* prepare to test V parameter */
+			LLVector4a qvec;
+			qvec.setCross3(tvec, edge1);
+			
+			/* calculate V parameter and test bounds */
+			LLVector4a v;
+			v.setAllDot3(dir, qvec);
+
+			
+			//if (!(v < 0.f || u + v > det))
+
+			LLVector4a sum_uv;
+			sum_uv.setAdd(u, v);
+
+			S32 v_gequal = v.greaterEqual4(LLVector4a::getZero()).getComparisonMask() & 0x7;
+			S32 sum_lequal = sum_uv.lessEqual4(det).getComparisonMask() & 0x7;
+
+			if (v_gequal  && sum_lequal)
+			{
+				/* calculate t, scale parameters, ray intersects triangle */
+				LLVector4a t;
+				t.setAllDot3(edge2,qvec);
+
+				t.div(det);
+				u.div(det);
+				v.div(det);
+				
+				intersection_a = u[0];
+				intersection_b = v[0];
+				intersection_t = t[0];
+				return TRUE;
+			}
 		}
-	
-		/* prepare to test V parameter */
-		LLVector3 qvec = tvec % edge1;
+	}
 		
-		/* calculate V parameter and test bounds */
-		v = dir * qvec;
-		if (v < 0.f || u + v > det)
-		{
-			return FALSE;
-		}
+	return FALSE;
+} 
+
+BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t)
+{
+	F32 u, v, t;
+	
+	/* find vectors for two edges sharing vert0 */
+	LLVector4a edge1;
+	edge1.setSub(vert1, vert0);
+	
+	
+	LLVector4a edge2;
+	edge2.setSub(vert2, vert0);
 
-		/* calculate t, scale parameters, ray intersects triangle */
-		t = edge2 * qvec;
-		F32 inv_det = 1.0 / det;
-		t *= inv_det;
-		u *= inv_det;
-		v *= inv_det;
+	/* begin calculating determinant - also used to calculate U parameter */
+	LLVector4a pvec;
+	pvec.setCross3(dir, edge2);
+
+	/* if determinant is near zero, ray lies in plane of triangle */
+	F32 det = edge1.dot3(pvec);
+
+	
+	if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
+	{
+		return FALSE;
 	}
+
+	F32 inv_det = 1.f / det;
+
+	/* calculate distance from vert0 to ray origin */
+	LLVector4a tvec;
+	tvec.setSub(orig, vert0);
 	
-	else // two sided
-			{
-		if (det > -F_APPROXIMATELY_ZERO && det < F_APPROXIMATELY_ZERO)
-				{
-			return FALSE;
-				}
-		F32 inv_det = 1.0 / det;
+	/* calculate U parameter and test bounds */
+	u = (tvec.dot3(pvec)) * inv_det;
+	if (u < 0.f || u > 1.f)
+	{
+		return FALSE;
+	}
 
-		/* calculate distance from vert0 to ray origin */
-		LLVector3 tvec = orig - vert0;
+	/* prepare to test V parameter */
+	tvec.sub(edge1);
 		
-		/* calculate U parameter and test bounds */
-		u = (tvec * pvec) * inv_det;
-		if (u < 0.f || u > 1.f)
+	/* calculate V parameter and test bounds */
+	v = (dir.dot3(tvec)) * inv_det;
+	
+	if (v < 0.f || u + v > 1.f)
+	{
+		return FALSE;
+	}
+
+	/* calculate t, ray intersects triangle */
+	t = (edge2.dot3(tvec)) * inv_det;
+	
+	intersection_a = u;
+	intersection_b = v;
+	intersection_t = t;
+	
+	
+	return TRUE;
+} 
+
+//helper for non-aligned vectors
+BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided)
+{
+	LLVector4a vert0a, vert1a, vert2a, origa, dira;
+	vert0a.load3(vert0.mV);
+	vert1a.load3(vert1.mV);
+	vert2a.load3(vert2.mV);
+	origa.load3(orig.mV);
+	dira.load3(dir.mV);
+
+	if (two_sided)
+	{
+		return LLTriangleRayIntersectTwoSided(vert0a, vert1a, vert2a, origa, dira, 
+				intersection_a, intersection_b, intersection_t);
+	}
+	else
+	{
+		return LLTriangleRayIntersect(vert0a, vert1a, vert2a, origa, dira, 
+				intersection_a, intersection_b, intersection_t);
+	}
+}
+
+class LLVolumeOctreeRebound : public LLOctreeTravelerDepthFirst<LLVolumeTriangle>
+{
+public:
+	const LLVolumeFace* mFace;
+
+	LLVolumeOctreeRebound(const LLVolumeFace* face)
+	{
+		mFace = face;
+	}
+
+	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+	{
+		LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
+
+		LLVector4a& min = node->mExtents[0];
+		LLVector4a& max = node->mExtents[1];
+
+		if (branch->getElementCount() != 0)
 		{
-			return FALSE;
+			const LLVolumeTriangle* tri = *(branch->getData().begin());
+						
+			min = *(tri->mV[0]);
+			max = *(tri->mV[0]);
+			
+			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = 
+				branch->getData().begin(); iter != branch->getData().end(); ++iter)
+			{
+				//stretch by triangles in node
+				tri = *iter;
+				
+				min.setMin(*tri->mV[0]);
+				min.setMin(*tri->mV[1]);
+				min.setMin(*tri->mV[2]);
+
+				max.setMax(*tri->mV[0]);
+				max.setMax(*tri->mV[1]);
+				max.setMax(*tri->mV[2]);
 			}
 
-		/* prepare to test V parameter */
-		LLVector3 qvec = tvec - edge1;
-		
-		/* calculate V parameter and test bounds */
-		v = (dir * qvec) * inv_det;
-		
-		if (v < 0.f || u + v > 1.f)
+			for (S32 i = 0; i < branch->getChildCount(); ++i)
+			{  //stretch by child extents
+				LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+				min.setMin(child->mExtents[0]);
+				max.setMax(child->mExtents[1]);
+			}
+		}
+		else if (branch->getChildCount() != 0)
 		{
-			return FALSE;
+			LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
+
+			min = child->mExtents[0];
+			max = child->mExtents[1];
+
+			for (S32 i = 1; i < branch->getChildCount(); ++i)
+			{  //stretch by child extents
+				child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+				min.setMin(child->mExtents[0]);
+				max.setMax(child->mExtents[1]);
+			}
+		}
+		else
+		{
+			llerrs << "WTF? Empty leaf" << llendl;
 		}
+		
+		node->mBounds[0].setAdd(min, max);
+		node->mBounds[0].mul(0.5f);
 
-		/* calculate t, ray intersects triangle */
-		t = (edge2 * qvec) * inv_det;
+		node->mBounds[1].setSub(max,min);
+		node->mBounds[1].mul(0.5f);
 	}
-	
-	if (intersection_a != NULL)
-		*intersection_a = u;
-	if (intersection_b != NULL)
-		*intersection_b = v;
-	if (intersection_t != NULL)
-		*intersection_t = t;
-	
-	
-	return TRUE;
-} 
+};
 
 
 //-------------------------------------------------------------------
@@ -1673,7 +1817,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 +1834,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,146 +1986,725 @@ BOOL LLVolume::generate()
 	return FALSE;
 }
 
-
-void LLVolume::createVolumeFaces()
+void LLVolumeFace::VertexData::init()
 {
-	LLMemType m1(LLMemType::MTYPE_VOLUME);
-
-	if (mGenerateSingleFace)
-	{
-		// do nothing
-	}
-	else
-	{
-		S32 num_faces = getNumFaces();
-		BOOL partial_build = TRUE;
-		if (num_faces != mVolumeFaces.size())
-		{
-			partial_build = FALSE;
-			mVolumeFaces.resize(num_faces);
-		}
-		// Initialize volume faces with parameter data
-		for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++)
-		{
-			LLVolumeFace& vf = mVolumeFaces[i];
-			LLProfile::Face& face = mProfilep->mFaces[i];
-			vf.mBeginS = face.mIndex;
-			vf.mNumS = face.mCount;
-			vf.mBeginT = 0;
-			vf.mNumT= getPath().mPath.size();
-			vf.mID = i;
+	mData = (LLVector4a*) ll_aligned_malloc_16(32);
+}
 
-			// Set the type mask bits correctly
-			if (mParams.getProfileParams().getHollow() > 0)
-			{
-				vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK;
-			}
-			if (mProfilep->isOpen())
-			{
-				vf.mTypeMask |= LLVolumeFace::OPEN_MASK;
-			}
-			if (face.mCap)
-			{
-				vf.mTypeMask |= LLVolumeFace::CAP_MASK;
-				if (face.mFaceID == LL_FACE_PATH_BEGIN)
-				{
-					vf.mTypeMask |= LLVolumeFace::TOP_MASK;
-				}
-				else
-				{
-					llassert(face.mFaceID == LL_FACE_PATH_END);
-					vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK;
-				}
-			}
-			else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
-			{
-				vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK;
-			}
-			else
-			{
-				vf.mTypeMask |= LLVolumeFace::SIDE_MASK;
-				if (face.mFlat)
-				{
-					vf.mTypeMask |= LLVolumeFace::FLAT_MASK;
-				}
-				if (face.mFaceID & LL_FACE_INNER_SIDE)
-				{
-					vf.mTypeMask |= LLVolumeFace::INNER_MASK;
-					if (face.mFlat && vf.mNumS > 2)
-					{ //flat inner faces have to copy vert normals
-						vf.mNumS = vf.mNumS*2;
-					}
-				}
-				else
-				{
-					vf.mTypeMask |= LLVolumeFace::OUTER_MASK;
-				}
-			}
-		}
+LLVolumeFace::VertexData::VertexData()
+{
+	init();
+}
+	
+LLVolumeFace::VertexData::VertexData(const VertexData& rhs)
+{
+	init();
+	LLVector4a::memcpyNonAliased16((F32*) mData, (F32*) rhs.mData, 8);
+	mTexCoord = rhs.mTexCoord;
+}
 
-		for (face_list_t::iterator iter = mVolumeFaces.begin();
-			 iter != mVolumeFaces.end(); ++iter)
-		{
-			(*iter).create(this, partial_build);
-		}
-	}
+LLVolumeFace::VertexData::~VertexData()
+{
+	ll_aligned_free_16(mData);
 }
 
+LLVector4a& LLVolumeFace::VertexData::getPosition()
+{
+	return mData[POSITION];
+}
 
-inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b)
+LLVector4a& LLVolumeFace::VertexData::getNormal()
 {
-	// maps RGB values to vector values [0..255] -> [-0.5..0.5]
-	LLVector3 value;
-	value.mV[VX] = r / 255.f - 0.5f;
-	value.mV[VY] = g / 255.f - 0.5f;
-	value.mV[VZ] = b / 255.f - 0.5f;
+	return mData[NORMAL];
+}
 
-	return value;
+const LLVector4a& LLVolumeFace::VertexData::getPosition() const
+{
+	return mData[POSITION];
 }
 
-inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
+const LLVector4a& LLVolumeFace::VertexData::getNormal() const
 {
-	U32 index = (x + y * sculpt_width) * sculpt_components;
-	return index;
+	return mData[NORMAL];
 }
 
 
-inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
+void LLVolumeFace::VertexData::setPosition(const LLVector4a& pos)
 {
-	U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width);
-	U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height);
-
-	return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
+	mData[POSITION] = pos;
 }
 
+void LLVolumeFace::VertexData::setNormal(const LLVector4a& norm)
+{
+	mData[NORMAL] = norm;
+}
 
-inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data)
+bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const
 {
-	LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]);
+	const U8* l = (const U8*) this;
+	const U8* r = (const U8*) &rhs;
 
-	return v;
+	for (U32 i = 0; i < sizeof(VertexData); ++i)
+	{
+		if (l[i] != r[i])
+		{
+			return r[i] < l[i];
+		}
+	}
+	
+	return false;
 }
 
-inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
+bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const
 {
-	U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components);
+	const U8* l = (const U8*) this;
+	const U8* r = (const U8*) &rhs;
 
-	return sculpt_index_to_vector(index, sculpt_data);
+	for (U32 i = 0; i < sizeof(VertexData); ++i)
+	{
+		if (l[i] != r[i])
+		{
+			return false;
+		}
+	}
+	
+	return true;
 }
 
-inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
+bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs, F32 angle_cutoff) const
 {
-	U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
+	bool retval = false;
+	if (rhs.mData[POSITION].equal3(mData[POSITION]) && rhs.mTexCoord == mTexCoord)
+	{
+		if (angle_cutoff > 1.f)
+		{
+			retval = (mData[NORMAL].equal3(rhs.mData[NORMAL]));
+		}
+		else
+		{
+			F32 cur_angle = rhs.mData[NORMAL].dot3(mData[NORMAL]);
+			retval = cur_angle > angle_cutoff;
+		}
+	}
 
-	return sculpt_index_to_vector(index, sculpt_data);
+	return retval;
 }
 
-
-F32 LLVolume::sculptGetSurfaceArea()
+BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name)
 {
-	// test to see if image has enough variation to create non-degenerate geometry
+	std::ifstream is;
+	
+	is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary);
 
-	F32 area = 0;
+	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)
+{
+	//input stream is now pointing at a zlib compressed block of LLSD
+	//decompress block
+	LLSD mdl;
+	if (!unzip_llsd(mdl, is, size))
+	{
+		llwarns << "not a valid mesh asset!" << llendl;
+		return false;
+	}
+	
+	{
+		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];
+
+			//copy out indices
+			face.resizeIndices(idx.size()/2);
+			
+			if (idx.empty() || face.mNumIndices < 3)
+			{ //why is there an empty index list?
+				llerrs <<"WTF?" << llendl;
+				continue;
+			}
+
+			U16* indices = (U16*) &(idx[0]);
+			for (U32 j = 0; j < idx.size()/2; ++j)
+			{
+				face.mIndices[j] = indices[j];
+			}
+
+			//copy out vertices
+			U32 num_verts = pos.size()/(3*2);
+			face.resizeVertices(num_verts);
+
+			if (mdl[i].has("Weights"))
+			{
+				face.allocateWeights(num_verts);
+
+				LLSD::Binary weights = mdl[i]["Weights"];
+
+				U32 idx = 0;
+
+				U32 cur_vertex = 0;
+				while (idx < weights.size() && cur_vertex < num_verts)
+				{
+					const U8 END_INFLUENCES = 0xFF;
+					U8 joint = weights[idx++];
+
+					U32 cur_influence = 0;
+					LLVector4 wght(0,0,0,0);
+
+					while (joint != END_INFLUENCES)
+					{
+						U16 influence = weights[idx++];
+						influence |= ((U16) weights[idx++] << 8);
+
+						F32 w = llmin((F32) influence / 65535.f, 0.99999f);
+						wght.mV[cur_influence++] = (F32) joint + w;
+
+						if (cur_influence >= 4)
+						{
+							joint = END_INFLUENCES;
+						}
+						else
+						{
+							joint = weights[idx++];
+						}
+					}
+
+					face.mWeights[cur_vertex].loadua(wght.mV);
+
+					cur_vertex++;
+				}
+
+				if (cur_vertex != num_verts || idx != weights.size())
+				{
+					llwarns << "Vertex weight count does not match vertex count!" << llendl;
+				}
+					
+			}
+
+			LLVector3 minp;
+			LLVector3 maxp;
+			LLVector2 min_tc; 
+			LLVector2 max_tc; 
+		
+			minp.setValue(mdl[i]["PositionDomain"]["Min"]);
+			maxp.setValue(mdl[i]["PositionDomain"]["Max"]);
+			LLVector4a min_pos, max_pos;
+			min_pos.load3(minp.mV);
+			max_pos.load3(maxp.mV);
+
+			min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
+			max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
+
+			LLVector4a pos_range;
+			pos_range.setSub(max_pos, min_pos);
+			LLVector2 tc_range = max_tc - min_tc;
+
+			LLVector4a& min = face.mExtents[0];
+			LLVector4a& max = face.mExtents[1];
+
+			min.clear();
+			max.clear();
+			
+			LLVector4a* pos_out = face.mPositions;
+			LLVector4a* norm_out = face.mNormals;
+			LLVector2* tc_out = face.mTexCoords;
+
+			for (U32 j = 0; j < num_verts; ++j)
+			{
+				U16* v = (U16*) &(pos[j*3*2]);
+
+				pos_out->set((F32) v[0], (F32) v[1], (F32) v[2]);
+				pos_out->div(65535.f);
+				pos_out->mul(pos_range);
+				pos_out->add(min_pos);
+
+				if (j == 0)
+				{
+					min = *pos_out;
+					max = min;
+				}
+				else
+				{
+					min.setMin(*pos_out);
+					max.setMax(*pos_out);
+				}
+
+				pos_out++;
+
+				U16* n = (U16*) &(norm[j*3*2]);
+
+				norm_out->set((F32) n[0], (F32) n[1], (F32) n[2]);
+				norm_out->div(65535.f);
+				norm_out->mul(2.f);
+				norm_out->sub(1.f);
+				norm_out++;
+
+				U16* t = (U16*) &(tc[j*2*2]);
+
+				tc_out->mV[0] = (F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0];
+				tc_out->mV[1] =	(F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1];
+
+				tc_out++;
+			}
+
+			
+			// modifier flags?
+			bool do_mirror = (mParams.getSculptType() & LL_SCULPT_FLAG_MIRROR);
+			bool do_invert = (mParams.getSculptType() &LL_SCULPT_FLAG_INVERT);
+			
+			
+			// translate to actions:
+			bool do_reflect_x = false;
+			bool do_reverse_triangles = false;
+			bool do_invert_normals = false;
+			
+			if (do_mirror)
+			{
+				do_reflect_x = true;
+				do_reverse_triangles = !do_reverse_triangles;
+			}
+			
+			if (do_invert)
+			{
+				do_invert_normals = true;
+				do_reverse_triangles = !do_reverse_triangles;
+			}
+			
+			// now do the work
+
+			if (do_reflect_x)
+			{
+				LLVector4a* p = (LLVector4a*) face.mPositions;
+				LLVector4a* n = (LLVector4a*) face.mNormals;
+				
+				for (S32 i = 0; i < face.mNumVertices; i++)
+				{
+					p[i].mul(-1.0f);
+					n[i].mul(-1.0f);
+				}
+			}
+
+			if (do_invert_normals)
+			{
+				LLVector4a* n = (LLVector4a*) face.mNormals;
+				
+				for (S32 i = 0; i < face.mNumVertices; i++)
+				{
+					n[i].mul(-1.0f);
+				}
+			}
+
+			if (do_reverse_triangles)
+			{
+				for (U32 j = 0; j < face.mNumIndices; 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)
+{
+	LLVector4a v0;
+	v0.setSub(cv[1].getPosition(), cv[0].getNormal());
+	LLVector4a v1;
+	v1.setSub(cv[2].getNormal(), cv[0].getPosition());
+	
+	cv[0].getNormal().setCross3(v0,v1);
+	cv[0].getNormal().normalize3fast();
+	cv[1].setNormal(cv[0].getNormal());
+	cv[2].setNormal(cv[1].getNormal());
+}
+
+BOOL LLVolume::isTetrahedron()
+{
+	return mIsTetrahedron;
+}
+
+void LLVolume::makeTetrahedron()
+{
+	mVolumeFaces.clear();
+
+	LLVolumeFace face;
+
+	F32 x = 0.25f;
+	LLVector4a p[] = 
+	{ //unit tetrahedron corners
+		LLVector4a(x,x,x),
+		LLVector4a(-x,-x,x),
+		LLVector4a(-x,x,-x),
+		LLVector4a(x,-x,-x)
+	};
+
+	face.mExtents[0].splat(-x);
+	face.mExtents[1].splat(x);
+	
+	LLVolumeFace::VertexData cv[3];
+
+	//set texture coordinates
+	cv[0].mTexCoord = LLVector2(0,0);
+	cv[1].mTexCoord = LLVector2(1,0);
+	cv[2].mTexCoord = LLVector2(0.5f, 0.5f*F_SQRT3);
+
+
+	//side 1
+	cv[0].setPosition(p[1]);
+	cv[1].setPosition(p[0]);
+	cv[2].setPosition(p[2]);
+
+	tetrahedron_set_normal(cv);
+
+	face.resizeVertices(12);
+	face.resizeIndices(12);
+
+	LLVector4a* v = (LLVector4a*) face.mPositions;
+	LLVector4a* n = (LLVector4a*) face.mNormals;
+	LLVector2* tc = (LLVector2*) face.mTexCoords;
+
+	v[0] = cv[0].getPosition();
+	v[1] = cv[1].getPosition();
+	v[2] = cv[2].getPosition();
+	v += 3;
+
+	n[0] = cv[0].getNormal();
+	n[1] = cv[1].getNormal();
+	n[2] = cv[2].getNormal();
+	n += 3;
+
+	tc[0] = cv[0].mTexCoord;
+	tc[1] = cv[1].mTexCoord;
+	tc[2] = cv[2].mTexCoord;
+	tc += 3;
+
+	
+	//side 2
+	cv[0].setPosition(p[3]);
+	cv[1].setPosition(p[0]);
+	cv[2].setPosition(p[1]);
+
+	tetrahedron_set_normal(cv);
+
+	v[0] = cv[0].getPosition();
+	v[1] = cv[1].getPosition();
+	v[2] = cv[2].getPosition();
+	v += 3;
+
+	n[0] = cv[0].getNormal();
+	n[1] = cv[1].getNormal();
+	n[2] = cv[2].getNormal();
+	n += 3;
+
+	tc[0] = cv[0].mTexCoord;
+	tc[1] = cv[1].mTexCoord;
+	tc[2] = cv[2].mTexCoord;
+	tc += 3;
+	
+	//side 3
+	cv[0].setPosition(p[3]);
+	cv[1].setPosition(p[1]);
+	cv[2].setPosition(p[2]);
+
+	tetrahedron_set_normal(cv);
+
+	v[0] = cv[0].getPosition();
+	v[1] = cv[1].getPosition();
+	v[2] = cv[2].getPosition();
+	v += 3;
+
+	n[0] = cv[0].getNormal();
+	n[1] = cv[1].getNormal();
+	n[2] = cv[2].getNormal();
+	n += 3;
+
+	tc[0] = cv[0].mTexCoord;
+	tc[1] = cv[1].mTexCoord;
+	tc[2] = cv[2].mTexCoord;
+	tc += 3;
+	
+	//side 4
+	cv[0].setPosition(p[2]);
+	cv[1].setPosition(p[0]);
+	cv[2].setPosition(p[3]);
+
+	tetrahedron_set_normal(cv);
+
+	v[0] = cv[0].getPosition();
+	v[1] = cv[1].getPosition();
+	v[2] = cv[2].getPosition();
+	v += 3;
+
+	n[0] = cv[0].getNormal();
+	n[1] = cv[1].getNormal();
+	n[2] = cv[2].getNormal();
+	n += 3;
+
+	tc[0] = cv[0].mTexCoord;
+	tc[1] = cv[1].mTexCoord;
+	tc[2] = cv[2].mTexCoord;
+	tc += 3;
+	
+	//set index buffer
+	for (U16 i = 0; i < 12; i++)
+	{
+		face.mIndices[i] = 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
+{
+#if LL_MESH_ENABLED
+	U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
+
+	if (sculpt_type == LL_SCULPT_TYPE_MESH)
+	{
+		return LL_SCULPT_MESH_MAX_FACES;
+	}
+#endif
+
+	return (S32)mProfilep->mFaces.size();
+}
+
+
+void LLVolume::createVolumeFaces()
+{
+	LLMemType m1(LLMemType::MTYPE_VOLUME);
+
+	if (mGenerateSingleFace)
+	{
+		// do nothing
+	}
+	else
+	{
+		S32 num_faces = getNumFaces();
+		BOOL partial_build = TRUE;
+		if (num_faces != mVolumeFaces.size())
+		{
+			partial_build = FALSE;
+			mVolumeFaces.resize(num_faces);
+		}
+		// Initialize volume faces with parameter data
+		for (S32 i = 0; i < (S32)mVolumeFaces.size(); i++)
+		{
+			LLVolumeFace& vf = mVolumeFaces[i];
+			LLProfile::Face& face = mProfilep->mFaces[i];
+			vf.mBeginS = face.mIndex;
+			vf.mNumS = face.mCount;
+			if (vf.mNumS < 0)
+			{
+				llerrs << "Volume face corruption detected." << llendl;
+			}
+
+			vf.mBeginT = 0;
+			vf.mNumT= getPath().mPath.size();
+			vf.mID = i;
+
+			// Set the type mask bits correctly
+			if (mParams.getProfileParams().getHollow() > 0)
+			{
+				vf.mTypeMask |= LLVolumeFace::HOLLOW_MASK;
+			}
+			if (mProfilep->isOpen())
+			{
+				vf.mTypeMask |= LLVolumeFace::OPEN_MASK;
+			}
+			if (face.mCap)
+			{
+				vf.mTypeMask |= LLVolumeFace::CAP_MASK;
+				if (face.mFaceID == LL_FACE_PATH_BEGIN)
+				{
+					vf.mTypeMask |= LLVolumeFace::TOP_MASK;
+				}
+				else
+				{
+					llassert(face.mFaceID == LL_FACE_PATH_END);
+					vf.mTypeMask |= LLVolumeFace::BOTTOM_MASK;
+				}
+			}
+			else if (face.mFaceID & (LL_FACE_PROFILE_BEGIN | LL_FACE_PROFILE_END))
+			{
+				vf.mTypeMask |= LLVolumeFace::FLAT_MASK | LLVolumeFace::END_MASK;
+			}
+			else
+			{
+				vf.mTypeMask |= LLVolumeFace::SIDE_MASK;
+				if (face.mFlat)
+				{
+					vf.mTypeMask |= LLVolumeFace::FLAT_MASK;
+				}
+				if (face.mFaceID & LL_FACE_INNER_SIDE)
+				{
+					vf.mTypeMask |= LLVolumeFace::INNER_MASK;
+					if (face.mFlat && vf.mNumS > 2)
+					{ //flat inner faces have to copy vert normals
+						vf.mNumS = vf.mNumS*2;
+						if (vf.mNumS < 0)
+						{
+							llerrs << "Volume face corruption detected." << llendl;
+						}
+					}
+				}
+				else
+				{
+					vf.mTypeMask |= LLVolumeFace::OUTER_MASK;
+				}
+			}
+		}
+
+		for (face_list_t::iterator iter = mVolumeFaces.begin();
+			 iter != mVolumeFaces.end(); ++iter)
+		{
+			(*iter).create(this, partial_build);
+		}
+	}
+}
+
+
+inline LLVector3 sculpt_rgb_to_vector(U8 r, U8 g, U8 b)
+{
+	// maps RGB values to vector values [0..255] -> [-0.5..0.5]
+	LLVector3 value;
+	value.mV[VX] = r / 255.f - 0.5f;
+	value.mV[VY] = g / 255.f - 0.5f;
+	value.mV[VZ] = b / 255.f - 0.5f;
+
+	return value;
+}
+
+inline U32 sculpt_xy_to_index(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
+{
+	U32 index = (x + y * sculpt_width) * sculpt_components;
+	return index;
+}
+
+
+inline U32 sculpt_st_to_index(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components)
+{
+	U32 x = (U32) ((F32)s/(size_s) * (F32) sculpt_width);
+	U32 y = (U32) ((F32)t/(size_t) * (F32) sculpt_height);
+
+	return sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
+}
+
+
+inline LLVector3 sculpt_index_to_vector(U32 index, const U8* sculpt_data)
+{
+	LLVector3 v = sculpt_rgb_to_vector(sculpt_data[index], sculpt_data[index+1], sculpt_data[index+2]);
+
+	return v;
+}
+
+inline LLVector3 sculpt_st_to_vector(S32 s, S32 t, S32 size_s, S32 size_t, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
+{
+	U32 index = sculpt_st_to_index(s, t, size_s, size_t, sculpt_width, sculpt_height, sculpt_components);
+
+	return sculpt_index_to_vector(index, sculpt_data);
+}
+
+inline LLVector3 sculpt_xy_to_vector(U32 x, U32 y, U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data)
+{
+	U32 index = sculpt_xy_to_index(x, y, sculpt_width, sculpt_height, sculpt_components);
+
+	return sculpt_index_to_vector(index, sculpt_data);
+}
+
+
+F32 LLVolume::sculptGetSurfaceArea()
+{
+	// test to see if image has enough variation to create non-degenerate geometry
+
+	F32 area = 0;
 
 	S32 sizeS = mPathp->mPath.size();
 	S32 sizeT = mProfilep->mProfile.size();
@@ -2309,7 +3035,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams &params) const
 		return mSculptID < params.mSculptID;
 	}
 
-
 	return mSculptType < params.mSculptType;
 
 
@@ -3367,34 +4092,66 @@ 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).mNumIndices/3;
+	}
+
+	return triangle_count;
+}
+
+
 //-----------------------------------------------------------------------------
 // generateSilhouetteVertices()
 //-----------------------------------------------------------------------------
 void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 										  std::vector<LLVector3> &normals,
 										  std::vector<S32> &segments,
-										  const LLVector3& obj_cam_vec,
-										  const LLMatrix4& mat,
-										  const LLMatrix3& norm_mat,
+										  const LLVector3& obj_cam_vec_in,
+										  const LLMatrix4& mat_in,
+										  const LLMatrix3& norm_mat_in,
 										  S32 face_mask)
 {
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
-	
+
+	LLMatrix4a mat;
+	mat.loadu(mat_in);
+
+	LLMatrix4a norm_mat;
+	norm_mat.loadu(norm_mat_in);
+		
+	LLVector4a obj_cam_vec;
+	obj_cam_vec.load3(obj_cam_vec_in.mV);
+
 	vertices.clear();
 	normals.clear();
 	segments.clear();
 
+#if LL_MESH_ENABLED
+	if ((mParams.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+	{
+		return;
+	}
+#endif
+	
 	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.mNumIndices == 0 || face.mEdge.empty())
 		{
 			continue;
 		}
+
 		if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
 	
 		}
@@ -3407,7 +4164,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 #if DEBUG_SILHOUETTE_EDGE_MAP
 
 			//for each triangle
-			U32 count = face.mIndices.size();
+			U32 count = face.mNumIndices;
 			for (U32 j = 0; j < count/3; j++) {
 				//get vertices
 				S32 v1 = face.mIndices[j*3+0];
@@ -3415,9 +4172,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 				S32 v3 = face.mIndices[j*3+2];
 
 				//get current face center
-				LLVector3 cCenter = (face.mVertices[v1].mPosition + 
-									face.mVertices[v2].mPosition + 
-									face.mVertices[v3].mPosition) / 3.0f;
+				LLVector3 cCenter = (face.mVertices[v1].getPosition() + 
+									face.mVertices[v2].getPosition() + 
+									face.mVertices[v3].getPosition()) / 3.0f;
 
 				//for each edge
 				for (S32 k = 0; k < 3; k++) {
@@ -3435,9 +4192,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 					v3 = face.mIndices[nIndex*3+2];
 
 					//get neighbor face center
-					LLVector3 nCenter = (face.mVertices[v1].mPosition + 
-									face.mVertices[v2].mPosition + 
-									face.mVertices[v3].mPosition) / 3.0f;
+					LLVector3 nCenter = (face.mVertices[v1].getPosition() + 
+									face.mVertices[v2].getPosition() + 
+									face.mVertices[v3].getPosition()) / 3.0f;
 
 					//draw line
 					vertices.push_back(cCenter);
@@ -3460,15 +4217,15 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 #elif DEBUG_SILHOUETTE_NORMALS
 
 			//for each vertex
-			for (U32 j = 0; j < face.mVertices.size(); j++) {
-				vertices.push_back(face.mVertices[j].mPosition);
-				vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mNormal*0.1f);
+			for (U32 j = 0; j < face.mNumVertices; j++) {
+				vertices.push_back(face.mVertices[j].getPosition());
+				vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].getNormal()*0.1f);
 				normals.push_back(LLVector3(0,0,1));
 				normals.push_back(LLVector3(0,0,1));
 				segments.push_back(vertices.size());
 #if DEBUG_SILHOUETTE_BINORMALS
-				vertices.push_back(face.mVertices[j].mPosition);
-				vertices.push_back(face.mVertices[j].mPosition + face.mVertices[j].mBinormal*0.1f);
+				vertices.push_back(face.mVertices[j].getPosition());
+				vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f);
 				normals.push_back(LLVector3(0,0,1));
 				normals.push_back(LLVector3(0,0,1));
 				segments.push_back(vertices.size());
@@ -3486,26 +4243,36 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 
 			//for each triangle
 			std::vector<U8> fFacing;
-			vector_append(fFacing, face.mIndices.size()/3);
-			for (U32 j = 0; j < face.mIndices.size()/3; j++) 
+			vector_append(fFacing, face.mNumIndices/3);
+
+			LLVector4a* v = (LLVector4a*) face.mPositions;
+			LLVector4a* n = (LLVector4a*) face.mNormals;
+
+			for (U32 j = 0; j < face.mNumIndices/3; j++) 
 			{
 				//approximate normal
 				S32 v1 = face.mIndices[j*3+0];
 				S32 v2 = face.mIndices[j*3+1];
 				S32 v3 = face.mIndices[j*3+2];
 
-				LLVector3 norm = (face.mVertices[v1].mPosition - face.mVertices[v2].mPosition) % 
-					(face.mVertices[v2].mPosition - face.mVertices[v3].mPosition);
-				
-				if (norm.magVecSquared() < 0.00000001f) 
+				LLVector4a c1,c2;
+				c1.setSub(v[v1], v[v2]);
+				c2.setSub(v[v2], v[v3]);
+
+				LLVector4a norm;
+
+				norm.setCross3(c1, c2);
+
+				if (norm.dot3(norm) < 0.00000001f) 
 				{
 					fFacing[j] = AWAY | TOWARDS;
 				}
 				else 
 				{
 					//get view vector
-					LLVector3 view = (obj_cam_vec-face.mVertices[v1].mPosition);
-					bool away = view * norm > 0.0f; 
+					LLVector4a view;
+					view.setSub(obj_cam_vec, v[v1]);
+					bool away = view.dot3(norm) > 0.0f; 
 					if (away) 
 					{
 						fFacing[j] = AWAY;
@@ -3518,7 +4285,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 			}
 			
 			//for each triangle
-			for (U32 j = 0; j < face.mIndices.size()/3; j++) 
+			for (U32 j = 0; j < face.mNumIndices/3; j++) 
 			{
 				if (fFacing[j] == (AWAY | TOWARDS)) 
 				{ //this is a degenerate triangle
@@ -3551,15 +4318,21 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 						S32 v1 = face.mIndices[j*3+k];
 						S32 v2 = face.mIndices[j*3+((k+1)%3)];
 						
-						vertices.push_back(face.mVertices[v1].mPosition*mat);
-						LLVector3 norm1 = face.mVertices[v1].mNormal * norm_mat;
-						norm1.normVec();
-						normals.push_back(norm1);
+						LLVector4a t;
+						mat.affineTransform(v[v1], t);
+						vertices.push_back(LLVector3(t[0], t[1], t[2]));
+
+						norm_mat.rotate(n[v1], t);
 
-						vertices.push_back(face.mVertices[v2].mPosition*mat);
-						LLVector3 norm2 = face.mVertices[v2].mNormal * norm_mat;
-						norm2.normVec();
-						normals.push_back(norm2);
+						t.normalize3fast();
+						normals.push_back(LLVector3(t[0], t[1], t[2]));
+
+						mat.affineTransform(v[v2], t);
+						vertices.push_back(LLVector3(t[0], t[1], t[2]));
+						
+						norm_mat.rotate(n[v2], t);
+						t.normalize3fast();
+						normals.push_back(LLVector3(t[0], t[1], t[2]));
 
 						segments.push_back(vertices.size());
 					}
@@ -3573,6 +4346,19 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
 								   S32 face,
 								   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+{
+	LLVector4a starta, enda;
+	starta.load3(start.mV);
+	enda.load3(end.mV);
+
+	return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal);
+
+}
+
+
+S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
+								   S32 face,
+								   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
 {
 	S32 hit_face = -1;
 	
@@ -3590,16 +4376,23 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
 		end_face = face;
 	}
 
-	LLVector3 dir = end - start;
+	LLVector4a dir;
+	dir.setSub(end, start);
 
 	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);
+		LLVolumeFace &face = mVolumeFaces[i];
+
+		LLVector4a box_center;
+		box_center.setAdd(face.mExtents[0], face.mExtents[1]);
+		box_center.mul(0.5f);
 
-		LLVector3 box_center = (face.mExtents[0] + face.mExtents[1]) / 2.f;
-		LLVector3 box_size   = face.mExtents[1] - face.mExtents[0];
+		LLVector4a box_size;
+		box_size.setSub(face.mExtents[1], face.mExtents[0]);
 
         if (LLLineSegmentBoxIntersect(start, end, box_center, box_size))
 		{
@@ -3607,56 +4400,19 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
 			{
 				genBinormals(i);
 			}
-			
-			for (U32 tri = 0; tri < face.mIndices.size()/3; tri++) 
-			{
-				S32 index1 = face.mIndices[tri*3+0];
-				S32 index2 = face.mIndices[tri*3+1];
-				S32 index3 = face.mIndices[tri*3+2];
 
-				F32 a, b, t;
+			if (!face.mOctree)
+			{
+				face.createOctree();
+			}
 			
-				if (LLTriangleRayIntersect(face.mVertices[index1].mPosition,
-										   face.mVertices[index2].mPosition,
-										   face.mVertices[index3].mPosition,
-										   start, dir, &a, &b, &t, FALSE))
-				{
-					if ((t >= 0.f) &&      // if hit is after start
-						(t <= 1.f) &&      // and before end
-						(t < closest_t))   // and this hit is closer
-		{
-						closest_t = t;
-						hit_face = i;
+			//LLVector4a* p = (LLVector4a*) face.mPositions;
 
-						if (intersection != NULL)
-						{
-							*intersection = start + dir * closest_t;
-						}
-			
-						if (tex_coord != NULL)
+			LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
+			intersect.traverse(face.mOctree);
+			if (intersect.mHitFace)
 			{
-							*tex_coord = ((1.f - a - b)  * face.mVertices[index1].mTexCoord +
-										  a              * face.mVertices[index2].mTexCoord +
-										  b              * face.mVertices[index3].mTexCoord);
-
-						}
-
-						if (normal != NULL)
-				{
-							*normal    = ((1.f - a - b)  * face.mVertices[index1].mNormal + 
-										  a              * face.mVertices[index2].mNormal +
-										  b              * face.mVertices[index3].mNormal);
-						}
-
-						if (bi_normal != NULL)
-					{
-							*bi_normal = ((1.f - a - b)  * face.mVertices[index1].mBinormal + 
-										  a              * face.mVertices[index2].mBinormal +
-										  b              * face.mVertices[index3].mBinormal);
-						}
-
-					}
-				}
+				hit_face = i;
 			}
 		}		
 	}
@@ -4104,11 +4860,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 +4889,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd)
 {
 	mPathParams.fromLLSD(sd["path"]);
 	mProfileParams.fromLLSD(sd["profile"]);
+	sculptFromLLSD(sd["sculpt"]);
+		
 	return true;
 }
 
@@ -4158,6 +4933,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();
 	 
@@ -4398,9 +5179,153 @@ std::ostream& operator<<(std::ostream &s, const LLVolume *volumep)
 	return s;
 }
 
+LLVolumeFace::LLVolumeFace() : 
+	mID(0),
+	mTypeMask(0),
+	mBeginS(0),
+	mBeginT(0),
+	mNumS(0),
+	mNumT(0),
+	mNumVertices(0),
+	mNumIndices(0),
+	mPositions(NULL),
+	mNormals(NULL),
+	mBinormals(NULL),
+	mTexCoords(NULL),
+	mIndices(NULL),
+	mWeights(NULL),
+	mOctree(NULL)
+{
+	mExtents = (LLVector4a*) ll_aligned_malloc_16(48);
+	mCenter = mExtents+2;
+}
+
+LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
+:	mID(0),
+	mTypeMask(0),
+	mBeginS(0),
+	mBeginT(0),
+	mNumS(0),
+	mNumT(0),
+	mNumVertices(0),
+	mNumIndices(0),
+	mPositions(NULL),
+	mNormals(NULL),
+	mBinormals(NULL),
+	mTexCoords(NULL),
+	mIndices(NULL),
+	mWeights(NULL),
+	mOctree(NULL)
+{ 
+	mExtents = (LLVector4a*) ll_aligned_malloc_16(48);
+	mCenter = mExtents+2;
+	*this = src;
+}
+
+LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
+{
+	if (&src == this)
+	{ //self assignment, do nothing
+		return *this;
+	}
+
+	mID = src.mID;
+	mTypeMask = src.mTypeMask;
+	mBeginS = src.mBeginS;
+	mBeginT = src.mBeginT;
+	mNumS = src.mNumS;
+	mNumT = src.mNumT;
+
+	mNumVertices = 0;
+	mNumIndices = 0;
+
+	freeData();
+	
+	LLVector4a::memcpyNonAliased16((F32*) mExtents, (F32*) src.mExtents, 12);
+
+	resizeVertices(src.mNumVertices);
+	resizeIndices(src.mNumIndices);
+
+	if (mNumVertices)
+	{
+		S32 vert_size = mNumVertices*4;
+		S32 tc_size = (mNumVertices*8+0xF) & ~0xF;
+		tc_size /= 4;
+			
+		LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size);
+		LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) src.mNormals, vert_size);
+		LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) src.mTexCoords, vert_size);
+
+
+		if (src.mBinormals)
+		{
+			allocateBinormals(src.mNumVertices);
+			LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size);
+		}
+		else
+		{
+			ll_aligned_free_16(mBinormals);
+			mBinormals = NULL;
+		}
+
+		if (src.mWeights)
+		{
+			allocateWeights(src.mNumVertices);
+			LLVector4a::memcpyNonAliased16((F32*) mWeights, (F32*) src.mWeights, vert_size);
+		}
+		else
+		{
+			ll_aligned_free_16(mWeights);
+			mWeights = NULL;
+		}
+	}
+
+	if (mNumIndices)
+	{
+		S32 idx_size = (mNumIndices*2+0xF) & ~0xF;
+		idx_size /= 4;
+
+		LLVector4a::memcpyNonAliased16((F32*) mIndices, (F32*) src.mIndices, idx_size);
+	}
+	
+
+	//delete 
+	return *this;
+}
+
+LLVolumeFace::~LLVolumeFace()
+{
+	ll_aligned_free_16(mExtents);
+	mExtents = NULL;
+
+	freeData();
+}
+
+void LLVolumeFace::freeData()
+{
+	ll_aligned_free_16(mPositions);
+	mPositions = NULL;
+	ll_aligned_free_16(mNormals);
+	mNormals = NULL;
+	ll_aligned_free_16(mTexCoords);
+	mTexCoords = NULL;
+	ll_aligned_free_16(mIndices);
+	mIndices = NULL;
+	ll_aligned_free_16(mBinormals);
+	mBinormals = NULL;
+	ll_aligned_free_16(mWeights);
+	mWeights = NULL;
+
+	delete mOctree;
+	mOctree = NULL;
+}
 
 BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 {
+	//tree for this face is no longer valid
+	delete mOctree;
+	mOctree = NULL;
+
 	if (mTypeMask & CAP_MASK)
 	{
 		return createCap(volume, partial_build);
@@ -4416,6 +5341,145 @@ BOOL LLVolumeFace::create(LLVolume* volume, BOOL partial_build)
 	}
 }
 
+void LLVolumeFace::getVertexData(U16 index, LLVolumeFace::VertexData& cv)
+{
+	cv.setPosition(mPositions[index]);
+	cv.setNormal(mNormals[index]);
+	cv.mTexCoord = mTexCoords[index];
+}
+
+bool LLVolumeFace::VertexMapData::operator==(const LLVolumeFace::VertexData& rhs) const
+{
+	return getPosition().equal3(rhs.getPosition()) &&
+		mTexCoord == rhs.mTexCoord &&
+		getNormal().equal3(rhs.getNormal());
+}
+
+bool LLVolumeFace::VertexMapData::ComparePosition::operator()(const LLVector4a& a, const LLVector4a& b) const
+{
+	return a.less3(b);			
+}
+
+void LLVolumeFace::optimize(F32 angle_cutoff)
+{
+	LLVolumeFace new_face;
+
+	VertexMapData::PointMap point_map;
+
+	//remove redundant vertices
+	for (U32 i = 0; i < mNumIndices; ++i)
+	{
+		U16 index = mIndices[i];
+
+		LLVolumeFace::VertexData cv;
+		getVertexData(index, cv);
+		
+		BOOL found = FALSE;
+		VertexMapData::PointMap::iterator point_iter = point_map.find(cv.getPosition());
+		if (point_iter != point_map.end())
+		{ //duplicate point might exist
+			for (U32 j = 0; j < point_iter->second.size(); ++j)
+			{
+				LLVolumeFace::VertexData& tv = (point_iter->second)[j];
+				if (tv.compareNormal(cv, angle_cutoff))
+				{
+					found = TRUE;
+					new_face.pushIndex((point_iter->second)[j].mIndex);
+					break;
+				}
+			}
+		}
+
+		if (!found)
+		{
+			new_face.pushVertex(cv);
+			U16 index = (U16) new_face.mNumVertices-1;
+			new_face.pushIndex(index);
+
+			VertexMapData d;
+			d.setPosition(cv.getPosition());
+			d.mTexCoord = cv.mTexCoord;
+			d.setNormal(cv.getNormal());
+			d.mIndex = index;
+			if (point_iter != point_map.end())
+			{
+				point_iter->second.push_back(d);
+			}
+			else
+			{
+				point_map[d.getPosition()].push_back(d);
+			}
+		}
+	}
+
+	swapData(new_face);
+}
+
+
+void LLVolumeFace::createOctree()
+{
+	LLVector4a center;
+	LLVector4a size;
+	center.splat(0.f);
+	size.splat(1.f);
+
+	mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL);
+	new LLVolumeOctreeListener(mOctree);
+
+	for (U32 i = 0; i < mNumIndices; i+= 3)
+	{
+		LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle();
+				
+		const LLVector4a& v0 = mPositions[mIndices[i]];
+		const LLVector4a& v1 = mPositions[mIndices[i+1]];
+		const LLVector4a& v2 = mPositions[mIndices[i+2]];
+
+		tri->mV[0] = &v0;
+		tri->mV[1] = &v1;
+		tri->mV[2] = &v2;
+
+		tri->mIndex[0] = mIndices[i];
+		tri->mIndex[1] = mIndices[i+1];
+		tri->mIndex[2] = mIndices[i+2];
+
+		LLVector4a min = v0;
+		min.setMin(v1);
+		min.setMin(v2);
+
+		LLVector4a max = v0;
+		max.setMax(v1);
+		max.setMax(v2);
+
+		LLVector4a center;
+		center.setAdd(min, max);
+		center.mul(0.5f);
+
+		*tri->mPositionGroup = center;
+
+		LLVector4a size;
+		size.setSub(max,min);
+		
+		tri->mRadius = size.length3() * 0.5f;
+		
+		mOctree->insert(tri);
+	}
+
+	LLVolumeOctreeRebound rebound(this);
+	rebound.traverse(mOctree);
+}
+
+
+void LLVolumeFace::swapData(LLVolumeFace& rhs)
+{
+	llswap(rhs.mPositions, mPositions);
+	llswap(rhs.mNormals, mNormals);
+	llswap(rhs.mBinormals, mBinormals);
+	llswap(rhs.mTexCoords, mTexCoords);
+	llswap(rhs.mIndices,mIndices);
+	llswap(rhs.mNumVertices, mNumVertices);
+	llswap(rhs.mNumIndices, mNumIndices);
+}
+
 void	LerpPlanarVertex(LLVolumeFace::VertexData& v0,
 				   LLVolumeFace::VertexData& v1,
 				   LLVolumeFace::VertexData& v2,
@@ -4423,10 +5487,21 @@ void	LerpPlanarVertex(LLVolumeFace::VertexData& v0,
 				   F32	coef01,
 				   F32	coef02)
 {
-	vout.mPosition = v0.mPosition + ((v1.mPosition-v0.mPosition)*coef01)+((v2.mPosition-v0.mPosition)*coef02);
+
+	LLVector4a lhs;
+	lhs.setSub(v1.getPosition(), v0.getPosition());
+	lhs.mul(coef01);
+	LLVector4a rhs;
+	rhs.setSub(v2.getPosition(), v0.getPosition());
+	rhs.mul(coef02);
+
+	rhs.add(lhs);
+	rhs.add(v0.getPosition());
+
+	vout.setPosition(rhs);
+		
 	vout.mTexCoord = v0.mTexCoord + ((v1.mTexCoord-v0.mTexCoord)*coef01)+((v2.mTexCoord-v0.mTexCoord)*coef02);
-	vout.mNormal = v0.mNormal;
-	vout.mBinormal = v0.mBinormal;
+	vout.setNormal(v0.getNormal());
 }
 
 BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
@@ -4446,8 +5521,8 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 	num_vertices = (grid_size+1)*(grid_size+1);
 	num_indices = quad_count * 4;
 
-	LLVector3& min = mExtents[0];
-	LLVector3& max = mExtents[1];
+	LLVector4a& min = mExtents[0];
+	LLVector4a& max = mExtents[1];
 
 	S32 offset = 0;
 	if (mTypeMask & TOP_MASK)
@@ -4458,16 +5533,22 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 	VertexData	corners[4];
 	VertexData baseVert;
 	for(int t = 0; t < 4; t++){
-		corners[t].mPosition = mesh[offset + (grid_size*t)].mPos;
+		corners[t].getPosition().load3( mesh[offset + (grid_size*t)].mPos.mV);
 		corners[t].mTexCoord.mV[0] = profile[grid_size*t].mV[0]+0.5f;
 		corners[t].mTexCoord.mV[1] = 0.5f - profile[grid_size*t].mV[1];
 	}
-	baseVert.mNormal = 
-		((corners[1].mPosition-corners[0].mPosition) % 
-		(corners[2].mPosition-corners[1].mPosition));
-	baseVert.mNormal.normVec();
+
+	{
+		LLVector4a lhs;
+		lhs.setSub(corners[1].getPosition(), corners[0].getPosition());
+		LLVector4a rhs;
+		rhs.setSub(corners[2].getPosition(), corners[1].getPosition());
+		baseVert.getNormal().setCross3(lhs, rhs); 
+		baseVert.getNormal().normalize3fast();
+	}
+
 	if(!(mTypeMask & TOP_MASK)){
-		baseVert.mNormal *= -1.0f;
+		baseVert.getNormal().mul(-1.0f);
 	}else{
 		//Swap the UVs on the U(X) axis for top face
 		LLVector2 swap;
@@ -4476,24 +5557,27 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 		corners[3].mTexCoord=swap;
 		swap = corners[1].mTexCoord;
 		corners[1].mTexCoord=corners[2].mTexCoord;
-		corners[2].mTexCoord=swap;
-	}
-	baseVert.mBinormal = calc_binormal_from_triangle( 
-		corners[0].mPosition, corners[0].mTexCoord,
-		corners[1].mPosition, corners[1].mTexCoord,
-		corners[2].mPosition, corners[2].mTexCoord);
-	for(int t = 0; t < 4; t++){
-		corners[t].mBinormal = baseVert.mBinormal;
-		corners[t].mNormal = baseVert.mNormal;
-	}
-	mHasBinormals = TRUE;
-
-	if (partial_build)
-	{
-		mVertices.clear();
+		corners[2].mTexCoord=swap;
 	}
 
-	S32	vtop = mVertices.size();
+	LLVector4a binormal;
+	
+	calc_binormal_from_triangle( binormal,
+		corners[0].getPosition(), corners[0].mTexCoord,
+		corners[1].getPosition(), corners[1].mTexCoord,
+		corners[2].getPosition(), corners[2].mTexCoord);
+	
+	binormal.normalize3fast();
+
+	S32 size = (grid_size+1)*(grid_size+1);
+	resizeVertices(size);
+	allocateBinormals(size);
+
+	LLVector4a* pos = (LLVector4a*) mPositions;
+	LLVector4a* norm = (LLVector4a*) mNormals;
+	LLVector4a* binorm = (LLVector4a*) mBinormals;
+	LLVector2* tc = (LLVector2*) mTexCoords;
+
 	for(int gx = 0;gx<grid_size+1;gx++){
 		for(int gy = 0;gy<grid_size+1;gy++){
 			VertexData newVert;
@@ -4504,24 +5588,33 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 				newVert,
 				(F32)gx/(F32)grid_size,
 				(F32)gy/(F32)grid_size);
-			mVertices.push_back(newVert);
+
+			*pos++ = newVert.getPosition();
+			*norm++ = baseVert.getNormal();
+			*tc++ = newVert.mTexCoord;
+			*binorm++ = binormal;
 
 			if (gx == 0 && gy == 0)
 			{
-				min = max = newVert.mPosition;
+				min = max = newVert.getPosition();
 			}
 			else
 			{
-				update_min_max(min,max,newVert.mPosition);
+				min.setMin(newVert.getPosition());
+				max.setMax(newVert.getPosition());
 			}
 		}
 	}
 	
-	mCenter = (min + max) * 0.5f;
+	mCenter->setAdd(min, max);
+	mCenter->mul(0.5f); 
 
 	if (!partial_build)
 	{
-		mTriStrip.clear();
+		resizeIndices(grid_size*grid_size*6);
+
+		U16* out = mIndices;
+
 		S32 idxs[] = {0,1,(grid_size+1)+1,(grid_size+1)+1,(grid_size+1),0};
 		for(S32 gx = 0;gx<grid_size;gx++)
 		{
@@ -4532,55 +5625,19 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 				{
 					for(S32 i=5;i>=0;i--)
 					{
-						mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
-					}
-					
-					if (gy == 0)
-					{
-						mTriStrip.push_back((gx+1)*(grid_size+1));
-						mTriStrip.push_back((gx+1)*(grid_size+1));
-						mTriStrip.push_back(gx*(grid_size+1));
-					}
-
-					mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
-					mTriStrip.push_back(gy+1+gx*(grid_size+1));
-					
-					
-					if (gy == grid_size-1)
-					{
-						mTriStrip.push_back(gy+1+gx*(grid_size+1));
-					}
+						*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
+					}		
 				}
 				else
 				{
 					for(S32 i=0;i<6;i++)
 					{
-						mIndices.push_back(vtop+(gy*(grid_size+1))+gx+idxs[i]);
-					}
-
-					if (gy == 0)
-					{
-						mTriStrip.push_back(gx*(grid_size+1));
-						mTriStrip.push_back(gx*(grid_size+1));
-						mTriStrip.push_back((gx+1)*(grid_size+1));
-					}
-
-					mTriStrip.push_back(gy+1+gx*(grid_size+1));
-					mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
-					
-					if (gy == grid_size-1)
-					{
-						mTriStrip.push_back(gy+1+(gx+1)*(grid_size+1));
+						*out++ = ((gy*(grid_size+1))+gx+idxs[i]);
 					}
 				}
 			}
 			
 		}
-
-		if (mTriStrip.size()%2 == 1)
-		{
-			mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
-		}
 	}
 		
 	return TRUE;
@@ -4610,17 +5667,31 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 	num_vertices = profile.size();
 	num_indices = (profile.size() - 2)*3;
 
-	mVertices.resize(num_vertices);
+	if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
+	{
+		resizeVertices(num_vertices+1);
+		allocateBinormals(num_vertices+1);	
 
-	if (!partial_build)
+		if (!partial_build)
+		{
+			resizeIndices(num_indices+3);
+		}
+	}
+	else
 	{
-		mIndices.resize(num_indices);
+		resizeVertices(num_vertices);
+		allocateBinormals(num_vertices);
+
+		if (!partial_build)
+		{
+			resizeIndices(num_indices);
+		}
 	}
 
 	S32 max_s = volume->getProfile().getTotal();
 	S32 max_t = volume->getPath().mPath.size();
 
-	mCenter.clearVec();
+	mCenter->clear();
 
 	S32 offset = 0;
 	if (mTypeMask & TOP_MASK)
@@ -4638,82 +5709,90 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 	LLVector2 cuv;
 	LLVector2 min_uv, max_uv;
 
-	LLVector3& min = mExtents[0];
-	LLVector3& max = mExtents[1];
+	LLVector4a& min = mExtents[0];
+	LLVector4a& max = mExtents[1];
+
+	LLVector2* tc = (LLVector2*) mTexCoords;
+	LLVector4a* pos = (LLVector4a*) mPositions;
+	LLVector4a* norm = (LLVector4a*) mNormals;
+	LLVector4a* binorm = (LLVector4a*) mBinormals;
 
 	// Copy the vertices into the array
 	for (S32 i = 0; i < num_vertices; i++)
 	{
 		if (mTypeMask & TOP_MASK)
 		{
-			mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
-			mVertices[i].mTexCoord.mV[1] = profile[i].mV[1]+0.5f;
+			tc[i].mV[0] = profile[i].mV[0]+0.5f;
+			tc[i].mV[1] = profile[i].mV[1]+0.5f;
 		}
 		else
 		{
 			// Mirror for underside.
-			mVertices[i].mTexCoord.mV[0] = profile[i].mV[0]+0.5f;
-			mVertices[i].mTexCoord.mV[1] = 0.5f - profile[i].mV[1];
+			tc[i].mV[0] = profile[i].mV[0]+0.5f;
+			tc[i].mV[1] = 0.5f - profile[i].mV[1];
 		}
 
-		mVertices[i].mPosition = mesh[i + offset].mPos;
+		pos[i].load3(mesh[i + offset].mPos.mV);
 		
 		if (i == 0)
 		{
-			min = max = mVertices[i].mPosition;
-			min_uv = max_uv = mVertices[i].mTexCoord;
+			min = max = pos[i];
+			min_uv = max_uv = tc[i];
 		}
 		else
 		{
-			update_min_max(min,max, mVertices[i].mPosition);
-			update_min_max(min_uv, max_uv, mVertices[i].mTexCoord);
+			update_min_max(min,max,pos[i]);
+			update_min_max(min_uv, max_uv, tc[i]);
 		}
 	}
 
-	mCenter = (min+max)*0.5f;
+	mCenter->setAdd(min, max);
+	mCenter->mul(0.5f); 
+
 	cuv = (min_uv + max_uv)*0.5f;
 
-	LLVector3 binormal = calc_binormal_from_triangle( 
-		mCenter, cuv,
-		mVertices[0].mPosition, mVertices[0].mTexCoord,
-		mVertices[1].mPosition, mVertices[1].mTexCoord);
-	binormal.normVec();
+	LLVector4a binormal;
+	calc_binormal_from_triangle(binormal,
+		*mCenter, cuv,
+		pos[0], tc[0],
+		pos[1], tc[1]);
+	binormal.normalize3fast();
+
+	LLVector4a normal;
+	LLVector4a d0, d1;
+	
 
-	LLVector3 d0;
-	LLVector3 d1;
-	LLVector3 normal;
+	d0.setSub(*mCenter, pos[0]);
+	d1.setSub(*mCenter, pos[1]);
 
-	d0 = mCenter-mVertices[0].mPosition;
-	d1 = mCenter-mVertices[1].mPosition;
+	if (mTypeMask & TOP_MASK)
+	{
+		normal.setCross3(d0, d1);
+	}
+	else
+	{
+		normal.setCross3(d1, d0);
+	}
 
-	normal = (mTypeMask & TOP_MASK) ? (d0%d1) : (d1%d0);
-	normal.normVec();
+	normal.normalize3fast();
 
 	VertexData vd;
-	vd.mPosition = mCenter;
-	vd.mNormal = normal;
-	vd.mBinormal = binormal;
+	vd.setPosition(*mCenter);
 	vd.mTexCoord = cuv;
 	
 	if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
 	{
-		mVertices.push_back(vd);
+		pos[num_vertices] = *mCenter;
+		tc[num_vertices] = cuv;
 		num_vertices++;
-		if (!partial_build)
-		{
-			vector_append(mIndices, 3);
-		}
 	}
 		
-	
 	for (S32 i = 0; i < num_vertices; i++)
 	{
-		mVertices[i].mBinormal = binormal;
-		mVertices[i].mNormal = normal;
+		binorm[i].load4a((F32*) &binormal.mQ);
+		norm[i].load4a((F32*) &normal.mQ);
 	}
 
-	mHasBinormals = TRUE;
-
 	if (partial_build)
 	{
 		return TRUE;
@@ -4821,8 +5900,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 					pt2--;
 				}
 			}
-
-			makeTriStrip();
 		}
 		else
 		{
@@ -4927,8 +6004,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 					pt2--;
 				}
 			}
-
-			makeTriStrip();
 		}
 	}
 	else
@@ -4950,127 +6025,283 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 			mIndices[3*i+v2] = i + 1;
 		}
 
-		//make tri strip
-		if (mTypeMask & OPEN_MASK)
-		{
-			makeTriStrip();
-		}
-		else
-		{
-			S32 j = num_vertices-2;
-			if (mTypeMask & TOP_MASK)
-			{
-				mTriStrip.push_back(0);
-				for (S32 i = 0; i <= j; ++i)
-				{
-					mTriStrip.push_back(i);
-					if (i != j)
-					{
-						mTriStrip.push_back(j);
-					}
-					--j;
-				}
-			}
-			else
-			{
-				mTriStrip.push_back(j);
-				for (S32 i = 0; i <= j; ++i)
-				{
-					if (i != j)
-					{
-						mTriStrip.push_back(j);
-					}
-					mTriStrip.push_back(i);
-					--j;
-				}
-			}
-			
-			mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
 
-			if (mTriStrip.size()%2 == 1)
-			{
-				mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
-			}
-		}
 	}
 		
 	return TRUE;
 }
 
-void LLVolumeFace::makeTriStrip()
-{
-	for (U32 i = 0; i < mIndices.size(); i+=3)
-	{
-		U16 i0 = mIndices[i];
-		U16 i1 = mIndices[i+1];
-		U16 i2 = mIndices[i+2];
-
-		if ((i/3)%2 == 1)
-		{
-			mTriStrip.push_back(i0);
-			mTriStrip.push_back(i0);
-			mTriStrip.push_back(i1);
-			mTriStrip.push_back(i2);
-			mTriStrip.push_back(i2);
-		}
-		else
-		{
-			mTriStrip.push_back(i2);
-			mTriStrip.push_back(i2);
-			mTriStrip.push_back(i1);
-			mTriStrip.push_back(i0);
-			mTriStrip.push_back(i0);
-		}
-	}
-
-	if (mTriStrip.size()%2 == 1)
-	{
-		mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
-	}
-}
-
 void LLVolumeFace::createBinormals()
 {
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
 	
-	if (!mHasBinormals)
+	if (!mBinormals)
 	{
+		allocateBinormals(mNumVertices);
+
 		//generate binormals
-		for (U32 i = 0; i < mIndices.size()/3; i++) 
+		LLVector4a* pos = mPositions;
+		LLVector2* tc = (LLVector2*) mTexCoords;
+		LLVector4a* binorm = (LLVector4a*) mBinormals;
+
+		for (U32 i = 0; i < mNumIndices/3; i++) 
 		{	//for each triangle
-			const VertexData& v0 = mVertices[mIndices[i*3+0]];
-			const VertexData& v1 = mVertices[mIndices[i*3+1]];
-			const VertexData& v2 = mVertices[mIndices[i*3+2]];
+			const U16& i0 = mIndices[i*3+0];
+			const U16& i1 = mIndices[i*3+1];
+			const U16& i2 = mIndices[i*3+2];
 						
 			//calculate binormal
-			LLVector3 binorm = calc_binormal_from_triangle(v0.mPosition, v0.mTexCoord,
-															v1.mPosition, v1.mTexCoord,
-															v2.mPosition, v2.mTexCoord);
+			LLVector4a binormal;
+			calc_binormal_from_triangle(binormal,
+										pos[i0], tc[i0],
+										pos[i1], tc[i1],
+										pos[i2], tc[i2]);
 
-			for (U32 j = 0; j < 3; j++) 
-			{ //add triangle normal to vertices
-				mVertices[mIndices[i*3+j]].mBinormal += binorm; // * (weight_sum - d[j])/weight_sum;
-			}
+
+			//add triangle normal to vertices
+			binorm[i0].add(binormal);
+			binorm[i1].add(binormal);
+			binorm[i2].add(binormal);
 
 			//even out quad contributions
 			if (i % 2 == 0) 
 			{
-				mVertices[mIndices[i*3+2]].mBinormal += binorm;
+				binorm[i2].add(binormal);
 			}
 			else 
 			{
-				mVertices[mIndices[i*3+1]].mBinormal += binorm;
+				binorm[i1].add(binormal);
 			}
 		}
 
 		//normalize binormals
-		for (U32 i = 0; i < mVertices.size(); i++) 
+		for (U32 i = 0; i < mNumVertices; i++) 
+		{
+			binorm[i].normalize3fast();
+			//bump map/planar projection code requires normals to be normalized
+			mNormals[i].normalize3fast();
+		}
+	}
+}
+
+void LLVolumeFace::resizeVertices(S32 num_verts)
+{
+	ll_aligned_free_16(mPositions);
+	ll_aligned_free_16(mNormals);
+	ll_aligned_free_16(mBinormals);
+	ll_aligned_free_16(mTexCoords);
+
+	mBinormals = NULL;
+
+	if (num_verts)
+	{
+		mPositions = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+		mNormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+
+		//pad texture coordinate block end to allow for QWORD reads
+		S32 size = ((num_verts*8) + 0xF) & ~0xF;
+		mTexCoords = (LLVector2*) ll_aligned_malloc_16(size);
+	}
+	else
+	{
+		mPositions = NULL;
+		mNormals = NULL;
+		mTexCoords = NULL;
+	}
+
+	mNumVertices = num_verts;
+}
+
+void LLVolumeFace::pushVertex(const LLVolumeFace::VertexData& cv)
+{
+	pushVertex(cv.getPosition(), cv.getNormal(), cv.mTexCoord);
+}
+
+void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc)
+{
+	S32 new_verts = mNumVertices+1;
+	S32 new_size = new_verts*16;
+	
+	//positions
+	LLVector4a* dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
+	if (mPositions)
+	{
+		LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mPositions, new_size/4);
+		ll_aligned_free_16(mPositions);
+	}
+	mPositions = dst;
+
+	//normals
+	dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
+	if (mNormals)
+	{
+		LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mNormals, new_size/4);
+		ll_aligned_free_16(mNormals);
+	}
+	mNormals = dst;
+
+	//tex coords
+	new_size = ((new_verts*8)+0xF) & ~0xF;
+
+	{
+		LLVector2* dst = (LLVector2*) ll_aligned_malloc_16(new_size);
+		if (mTexCoords)
+		{
+			LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mTexCoords, new_size/4);
+			ll_aligned_free_16(mTexCoords);
+		}
+	}
+
+	//just clear binormals
+	ll_aligned_free_16(mBinormals);
+	mBinormals = NULL;
+
+	mPositions[mNumVertices] = pos;
+	mNormals[mNumVertices] = norm;
+	mTexCoords[mNumVertices] = tc;
+
+	mNumVertices++;	
+}
+
+void LLVolumeFace::allocateBinormals(S32 num_verts)
+{
+	ll_aligned_free_16(mBinormals);
+	mBinormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+}
+
+void LLVolumeFace::allocateWeights(S32 num_verts)
+{
+	ll_aligned_free_16(mWeights);
+	mWeights = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+}
+
+void LLVolumeFace::resizeIndices(S32 num_indices)
+{
+	ll_aligned_free_16(mIndices);
+
+	if (num_indices)
+	{
+		//pad index block end to allow for QWORD reads
+		S32 size = ((num_indices*2) + 0xF) & ~0xF;
+		
+		mIndices = (U16*) ll_aligned_malloc_16(size);	
+	}
+	else
+	{
+		mIndices = NULL;
+	}
+
+	mNumIndices = num_indices;
+}
+
+void LLVolumeFace::pushIndex(const U16& idx)
+{
+	S32 new_count = mNumIndices + 1;
+	S32 new_size = ((new_count*2)+0xF) & ~0xF;
+
+	S32 old_size = (mNumIndices+0xF) & ~0xF;
+	if (new_size != old_size)
+	{
+		U16* dst = (U16*) ll_aligned_malloc_16(new_size);
+		LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mIndices, new_size/4);
+		ll_aligned_free_16(mIndices);
+		mIndices = dst;
+	}
+	
+	mIndices[mNumIndices++] = idx;
+}
+
+void LLVolumeFace::fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx)
+{
+	resizeVertices(v.size());
+	resizeIndices(idx.size());
+
+	for (U32 i = 0; i < v.size(); ++i)
+	{
+		mPositions[i] = v[i].getPosition();
+		mNormals[i] = v[i].getNormal();
+		mTexCoords[i] = v[i].mTexCoord;
+	}
+
+	for (U32 i = 0; i < idx.size(); ++i)
+	{
+		mIndices[i] = idx[i];
+	}
+}
+
+void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMatrix4& norm_mat_in)
+{
+	U16 offset = mNumVertices;
+
+	S32 new_count = face.mNumVertices + mNumVertices;
+
+	if (new_count > 65536)
+	{
+		llerrs << "Cannot append face -- 16-bit overflow will occur." << llendl;
+	}
+	
+	
+	LLVector4a* new_pos = (LLVector4a*) ll_aligned_malloc_16(new_count*16);
+	LLVector4a* new_norm = (LLVector4a*) ll_aligned_malloc_16(new_count*16);
+	LLVector2* new_tc = (LLVector2*) ll_aligned_malloc_16((new_count*8+0xF) & ~0xF);
+
+	LLVector4a::memcpyNonAliased16((F32*) new_pos, (F32*) mPositions, new_count*4);
+	LLVector4a::memcpyNonAliased16((F32*) new_norm, (F32*) mNormals, new_count*4);
+	LLVector4a::memcpyNonAliased16((F32*) new_tc, (F32*) mTexCoords, new_count*2);
+
+	ll_aligned_free_16(mPositions);
+	ll_aligned_free_16(mNormals);
+	ll_aligned_free_16(mTexCoords);
+
+	mPositions = new_pos;
+	mNormals = new_norm;
+	mTexCoords = new_tc;
+
+	mNumVertices = new_count;
+
+	LLVector4a* dst_pos = (LLVector4a*) mPositions+offset;
+	LLVector2* dst_tc = (LLVector2*) mTexCoords+offset;
+	LLVector4a* dst_norm = (LLVector4a*) mNormals+offset;
+
+	LLVector4a* src_pos = (LLVector4a*) face.mPositions;
+	LLVector2* src_tc = (LLVector2*) face.mTexCoords;
+	LLVector4a* src_norm = (LLVector4a*) face.mNormals;
+
+	LLMatrix4a mat, norm_mat;
+	mat.loadu(mat_in);
+	norm_mat.loadu(norm_mat_in);
+
+	for (U32 i = 0; i < face.mNumVertices; ++i)
+	{
+		mat.affineTransform(src_pos[i], dst_pos[i]);
+		norm_mat.rotate(src_norm[i], dst_norm[i]);
+		dst_norm[i].normalize3fast();
+
+		dst_tc[i] = src_tc[i];
+
+		if (offset == 0 && i == 0)
+		{
+			mExtents[0] = mExtents[1] = dst_pos[i];
+		}
+		else
 		{
-			mVertices[i].mBinormal.normVec();
-			mVertices[i].mNormal.normVec();
+			update_min_max(mExtents[0], mExtents[1], dst_pos[i]);
 		}
+	}
+
+
+	new_count = mNumIndices + face.mNumIndices;
+	U16* new_indices = (U16*) ll_aligned_malloc_16((new_count*2+0xF) & ~0xF);
+	LLVector4a::memcpyNonAliased16((F32*) new_indices, (F32*) mIndices, new_count/2);
+	ll_aligned_free_16(mIndices);
+	mIndices = new_indices;
+	mNumIndices = new_count;
+
+	U16* dst_idx = mIndices+offset;
 
-		mHasBinormals = TRUE;
+	for (U32 i = 0; i < face.mNumIndices; ++i)
+	{
+		dst_idx[i] = face.mIndices[i]+offset;
 	}
 }
 
@@ -5100,23 +6331,24 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 	num_vertices = mNumS*mNumT;
 	num_indices = (mNumS-1)*(mNumT-1)*6;
 
-	mVertices.resize(num_vertices);
-
 	if (!partial_build)
 	{
-		mIndices.resize(num_indices);
+		resizeVertices(num_vertices);
+		resizeIndices(num_indices);
+
+#if LL_MESH_ENABLED
+		if ((volume->getParams().getSculptType() & LL_SCULPT_TYPE_MASK) != LL_SCULPT_TYPE_MESH)
+		{
+			mEdge.resize(num_indices);
+		}
+#else
 		mEdge.resize(num_indices);
+#endif
 	}
-	else
-	{
-		mHasBinormals = FALSE;
-	}
-
-
-	LLVector3& face_min = mExtents[0];
-	LLVector3& face_max = mExtents[1];
 
-	mCenter.clearVec();
+	LLVector4a* pos = (LLVector4a*) mPositions;
+	LLVector4a* norm = (LLVector4a*) mNormals;
+	LLVector2* tc = (LLVector2*) mTexCoords;
 
 	S32 begin_stex = llfloor( profile[mBeginS].mV[2] );
 	S32 num_s = ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2) ? mNumS/2 : mNumS;
@@ -5168,30 +6400,21 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 				i = mBeginS + s + max_s*t;
 			}
 
-			mVertices[cur_vertex].mPosition = mesh[i].mPos;
-			mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
+			pos[cur_vertex].load3(mesh[i].mPos.mV);
+			tc[cur_vertex] = LLVector2(ss,tt);
 		
-			mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
-			mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
-			
-			if (cur_vertex == 0)
-			{
-				face_min = face_max = mesh[i].mPos;
-			}
-			else
-			{
-				update_min_max(face_min, face_max, mesh[i].mPos);
-			}
+			norm[cur_vertex].clear();
 
 			cur_vertex++;
 
 			if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0)
 			{
-				mVertices[cur_vertex].mPosition = mesh[i].mPos;
-				mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
+
+				pos[cur_vertex].load3(mesh[i].mPos.mV);
+				tc[cur_vertex] = LLVector2(ss,tt);
 			
-				mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
-				mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
+				norm[cur_vertex].clear();
+				
 				cur_vertex++;
 			}
 		}
@@ -5209,19 +6432,29 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 			i = mBeginS + s + max_s*t;
 			ss = profile[mBeginS + s].mV[2] - begin_stex;
-			mVertices[cur_vertex].mPosition = mesh[i].mPos;
-			mVertices[cur_vertex].mTexCoord = LLVector2(ss,tt);
-		
-			mVertices[cur_vertex].mNormal = LLVector3(0,0,0);
-			mVertices[cur_vertex].mBinormal = LLVector3(0,0,0);
-
-			update_min_max(face_min,face_max,mesh[i].mPos);
-
+			pos[cur_vertex].load3(mesh[i].mPos.mV);
+			tc[cur_vertex] = LLVector2(ss,tt);
+			norm[cur_vertex].clear(); 
+			
 			cur_vertex++;
 		}
 	}
 	
-	mCenter = (face_min + face_max) * 0.5f;
+
+	//get bounding box for this side
+	LLVector4a& face_min = mExtents[0];
+	LLVector4a& face_max = mExtents[1];
+	mCenter->clear();
+
+	face_min = face_max = pos[0];
+
+	for (U32 i = 1; i < mNumVertices; ++i)
+	{
+		update_min_max(face_min, face_max, pos[i]);
+	}
+
+	mCenter->setAdd(face_min, face_max);
+	mCenter->mul(0.5f);
 
 	S32 cur_index = 0;
 	S32 cur_edge = 0;
@@ -5229,14 +6462,9 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 	if (!partial_build)
 	{
-		mTriStrip.clear();
-
 		// Now we generate the indices.
 		for (t = 0; t < (mNumT-1); t++)
 		{
-			//prepend terminating index to strip
-			mTriStrip.push_back(mNumS*t);
-
 			for (s = 0; s < (mNumS-1); s++)
 			{	
 				mIndices[cur_index++] = s   + mNumS*t;			//bottom left
@@ -5246,14 +6474,6 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 				mIndices[cur_index++] = s+1 + mNumS*t;			//bottom right
 				mIndices[cur_index++] = s+1 + mNumS*(t+1);		//top right
 
-				if (s == 0)
-				{
-					mTriStrip.push_back(s+mNumS*t);
-					mTriStrip.push_back(s+mNumS*(t+1));
-				}
-				mTriStrip.push_back(s+1+mNumS*t);
-				mTriStrip.push_back(s+1+mNumS*(t+1));
-				
 				mEdge[cur_edge++] = (mNumS-1)*2*t+s*2+1;						//bottom left/top right neighbor face 
 				if (t < mNumT-2) {												//top right/top left neighbor face 
 					mEdge[cur_edge++] = (mNumS-1)*2*(t+1)+s*2+1;
@@ -5294,59 +6514,55 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 				}
 				mEdge[cur_edge++] = (mNumS-1)*2*t+s*2;							//top right/bottom left neighbor face	
 			}
-			//append terminating vertex to strip
-			mTriStrip.push_back(mNumS-1+mNumS*(t+1));
-		}
-
-		if (mTriStrip.size()%2 == 1)
-		{
-			mTriStrip.push_back(mTriStrip[mTriStrip.size()-1]);
 		}
 	}
 
 	//generate normals 
-	for (U32 i = 0; i < mIndices.size()/3; i++) //for each triangle
-	{
-		const S32 i0 = mIndices[i*3+0];
-		const S32 i1 = mIndices[i*3+1];
-		const S32 i2 = mIndices[i*3+2];
-		const VertexData& v0 = mVertices[i0];
-		const VertexData& v1 = mVertices[i1];
-		const VertexData& v2 = mVertices[i2];
-					
-		//calculate triangle normal
-		LLVector3 norm = (v0.mPosition-v1.mPosition) % (v0.mPosition-v2.mPosition);
+	for (U32 i = 0; i < mNumIndices/3; i++) //for each triangle
+	{
+		const U16* idx = &(mIndices[i*3]);
+		
 
-		for (U32 j = 0; j < 3; j++) 
-		{ //add triangle normal to vertices
-			const S32 idx = mIndices[i*3+j];
-			mVertices[idx].mNormal += norm; // * (weight_sum - d[j])/weight_sum;
-		}
+		LLVector4a* v[] = 
+		{	pos+idx[0], pos+idx[1], pos+idx[2] };
+		
+		LLVector4a* n[] = 
+		{	norm+idx[0], norm+idx[1], norm+idx[2] };
+		
+		//calculate triangle normal
+		LLVector4a a, b, c;
+		
+		a.setSub(*v[0], *v[1]);
+		b.setSub(*v[0], *v[2]);
+		c.setCross3(a,b);
 
+		n[0]->add(c);
+		n[1]->add(c);
+		n[2]->add(c);
+		
 		//even out quad contributions
-		if ((i & 1) == 0) 
-		{
-			mVertices[i2].mNormal += norm;
-		}
-		else 
-		{
-			mVertices[i1].mNormal += norm;
-		}
+		n[i%2+1]->add(c);
 	}
 	
 	// adjust normals based on wrapping and stitching
 	
-	BOOL s_bottom_converges = ((mVertices[0].mPosition - mVertices[mNumS*(mNumT-2)].mPosition).magVecSquared() < 0.000001f);
-	BOOL s_top_converges = ((mVertices[mNumS-1].mPosition - mVertices[mNumS*(mNumT-2)+mNumS-1].mPosition).magVecSquared() < 0.000001f);
+	LLVector4a top;
+	top.setSub(pos[0], pos[mNumS*(mNumT-2)]);
+	BOOL s_bottom_converges = (top.dot3(top) < 0.000001f);
+
+	top.setSub(pos[mNumS-1], pos[mNumS*(mNumT-2)+mNumS-1]);
+	BOOL s_top_converges = (top.dot3(top) < 0.000001f);
+
 	if (sculpt_stitching == LL_SCULPT_TYPE_NONE)  // logic for non-sculpt volumes
 	{
 		if (volume->getPath().isOpen() == FALSE)
 		{ //wrap normals on T
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
-				mVertices[i].mNormal = norm;
-				mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
+				LLVector4a n;
+				n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+				norm[i] = n;
+				norm[mNumS*(mNumT-1)+i] = n;
 			}
 		}
 
@@ -5354,9 +6570,10 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		{ //wrap normals on S
 			for (S32 i = 0; i < mNumT; i++)
 			{
-				LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
-				mVertices[mNumS * i].mNormal = norm;
-				mVertices[mNumS * i+mNumS-1].mNormal = norm;
+				LLVector4a n;
+				n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+				norm[mNumS * i] = n;
+				norm[mNumS * i+mNumS-1] = n;
 			}
 		}
 	
@@ -5367,7 +6584,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 			{ //all lower S have same normal
 				for (S32 i = 0; i < mNumT; i++)
 				{
-					mVertices[mNumS*i].mNormal = LLVector3(1,0,0);
+					norm[mNumS*i].set(1,0,0);
 				}
 			}
 
@@ -5375,7 +6592,7 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 			{ //all upper S have same normal
 				for (S32 i = 0; i < mNumT; i++)
 				{
-					mVertices[mNumS*i+mNumS-1].mNormal = LLVector3(-1,0,0);
+					norm[mNumS*i+mNumS-1].set(-1,0,0);
 				}
 			}
 		}
@@ -5403,30 +6620,33 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		{
 			// average normals for north pole
 		
-			LLVector3 average(0.0, 0.0, 0.0);
+			LLVector4a average;
+			average.clear();
+
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				average += mVertices[i].mNormal;
+				average.add(norm[i]);
 			}
 
 			// set average
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				mVertices[i].mNormal = average;
+				norm[i] = average;
 			}
 
 			// average normals for south pole
 		
-			average = LLVector3(0.0, 0.0, 0.0);
+			average.clear();
+
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				average += mVertices[i + mNumS * (mNumT - 1)].mNormal;
+				average.add(norm[i + mNumS * (mNumT - 1)]);
 			}
 
 			// set average
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				mVertices[i + mNumS * (mNumT - 1)].mNormal = average;
+				norm[i + mNumS * (mNumT - 1)] = average;
 			}
 
 		}
@@ -5436,23 +6656,22 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		{
 			for (S32 i = 0; i < mNumT; i++)
 			{
-				LLVector3 norm = mVertices[mNumS*i].mNormal + mVertices[mNumS*i+mNumS-1].mNormal;
-				mVertices[mNumS * i].mNormal = norm;
-				mVertices[mNumS * i+mNumS-1].mNormal = norm;
+				LLVector4a n;
+				n.setAdd(norm[mNumS*i], norm[mNumS*i+mNumS-1]);
+				norm[mNumS * i] = n;
+				norm[mNumS * i+mNumS-1] = n;
 			}
 		}
 
-
-		
 		if (wrap_t)
 		{
 			for (S32 i = 0; i < mNumS; i++)
 			{
-				LLVector3 norm = mVertices[i].mNormal + mVertices[mNumS*(mNumT-1)+i].mNormal;
-				mVertices[i].mNormal = norm;
-				mVertices[mNumS*(mNumT-1)+i].mNormal = norm;
+				LLVector4a n;
+				n.setAdd(norm[i], norm[mNumS*(mNumT-1)+i]);
+				norm[i] = n;
+				norm[mNumS*(mNumT-1)+i] = n;
 			}
-			
 		}
 
 	}
@@ -5462,41 +6681,51 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 // Finds binormal based on three vertices with texture coordinates.
 // Fills in dummy values if the triangle has degenerate texture coordinates.
-LLVector3 calc_binormal_from_triangle( 
-	const LLVector3& pos0,
+void calc_binormal_from_triangle(LLVector4a& binormal,
+
+	const LLVector4a& pos0,
 	const LLVector2& tex0,
-	const LLVector3& pos1,
+	const LLVector4a& pos1,
 	const LLVector2& tex1,
-	const LLVector3& pos2,
+	const LLVector4a& pos2,
 	const LLVector2& tex2)
 {
-	LLVector3 rx0( pos0.mV[VX], tex0.mV[VX], tex0.mV[VY] );
-	LLVector3 rx1( pos1.mV[VX], tex1.mV[VX], tex1.mV[VY] );
-	LLVector3 rx2( pos2.mV[VX], tex2.mV[VX], tex2.mV[VY] );
+	LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] );
+	LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] );
+	LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] );
 	
-	LLVector3 ry0( pos0.mV[VY], tex0.mV[VX], tex0.mV[VY] );
-	LLVector3 ry1( pos1.mV[VY], tex1.mV[VX], tex1.mV[VY] );
-	LLVector3 ry2( pos2.mV[VY], tex2.mV[VX], tex2.mV[VY] );
+	LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] );
+	LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] );
+	LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] );
 
-	LLVector3 rz0( pos0.mV[VZ], tex0.mV[VX], tex0.mV[VY] );
-	LLVector3 rz1( pos1.mV[VZ], tex1.mV[VX], tex1.mV[VY] );
-	LLVector3 rz2( pos2.mV[VZ], tex2.mV[VX], tex2.mV[VY] );
+	LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] );
+	LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] );
+	LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] );
 	
-	LLVector3 r0 = (rx0 - rx1) % (rx0 - rx2);
-	LLVector3 r1 = (ry0 - ry1) % (ry0 - ry2);
-	LLVector3 r2 = (rz0 - rz1) % (rz0 - rz2);
+	LLVector4a lhs, rhs;
+
+	LLVector4a r0; 
+	lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2);
+	r0.setCross3(lhs, rhs);
+		
+	LLVector4a r1;
+	lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2);
+	r1.setCross3(lhs, rhs);
+
+	LLVector4a r2;
+	lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2);
+	r2.setCross3(lhs, rhs);
 
-	if( r0.mV[VX] && r1.mV[VX] && r2.mV[VX] )
+	if( r0[VX] && r1[VX] && r2[VX] )
 	{
-		LLVector3 binormal(
-				-r0.mV[VZ] / r0.mV[VX],
-				-r1.mV[VZ] / r1.mV[VX],
-				-r2.mV[VZ] / r2.mV[VX]);
+		binormal.set(
+				-r0[VZ] / r0[VX],
+				-r1[VZ] / r1[VX],
+				-r2[VZ] / r2[VX]);
 		// binormal.normVec();
-		return binormal;
 	}
 	else
 	{
-		return LLVector3( 0, 1 , 0 );
+		binormal.set( 0, 1 , 0 );
 	}
 }
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index d9f80f0e30e5d099294b0862aa187d94409e1446..078294407969f9bc05e48b7fdfaf7a2aa963b138 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -40,8 +40,15 @@ class LLPathParams;
 class LLVolumeParams;
 class LLProfile;
 class LLPath;
+
+#define LL_MESH_ENABLED 0
+
+template <class T> class LLOctreeNode;
+
+class LLVector4a;
 class LLVolumeFace;
 class LLVolume;
+class LLVolumeTriangle;
 
 #include "lldarray.h"
 #include "lluuid.h"
@@ -49,6 +56,8 @@ class LLVolume;
 //#include "vmath.h"
 #include "v2math.h"
 #include "v3math.h"
+#include "v3dmath.h"
+#include "v4math.h"
 #include "llquaternion.h"
 #include "llstrider.h"
 #include "v4coloru.h"
@@ -183,12 +192,20 @@ 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_MASK      = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE | LL_SCULPT_TYPE_CYLINDER;
+#if LL_MESH_ENABLED
+const U8 LL_SCULPT_TYPE_MESH      = 5;
+
+const U8 LL_SCULPT_TYPE_MASK      = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
+	LL_SCULPT_TYPE_CYLINDER | LL_SCULPT_TYPE_MESH;
+#else
+const U8 LL_SCULPT_TYPE_MASK      = LL_SCULPT_TYPE_SPHERE | LL_SCULPT_TYPE_TORUS | LL_SCULPT_TYPE_PLANE |
+	LL_SCULPT_TYPE_CYLINDER;
+#endif
 
 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 +592,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 +654,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)
@@ -785,30 +804,84 @@ class LLDynamicPath : public LLPath
 class LLVolumeFace
 {
 public:
-	LLVolumeFace() : 
-		mID(0),
-		mTypeMask(0),
-		mHasBinormals(FALSE),
-		mBeginS(0),
-		mBeginT(0),
-		mNumS(0),
-		mNumT(0)
+	class VertexData
 	{
-	}
+		enum 
+		{
+			POSITION = 0,
+			NORMAL = 1
+		};
+
+	private:
+		void init();
+	public:
+		VertexData();
+		VertexData(const VertexData& rhs);
+		~VertexData();
+		LLVector4a& getPosition();
+		LLVector4a& getNormal();
+		const LLVector4a& getPosition() const;
+		const LLVector4a& getNormal() const;
+		void setPosition(const LLVector4a& pos);
+		void setNormal(const LLVector4a& norm);
+		
+
+		LLVector2 mTexCoord;
+
+		bool operator<(const VertexData& rhs) const;
+		bool operator==(const VertexData& rhs) const;
+		bool compareNormal(const VertexData& rhs, F32 angle_cutoff) const;
+
+	private:
+		LLVector4a* mData;
+	};
+
+	LLVolumeFace();
+	LLVolumeFace(const LLVolumeFace& src);
+	LLVolumeFace& operator=(const LLVolumeFace& rhs);
+
+	~LLVolumeFace();
+private:
+	void freeData();
+public:
 
 	BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
 	void createBinormals();
-	void makeTriStrip();
 	
-	class VertexData
+	void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform);
+
+	void resizeVertices(S32 num_verts);
+	void allocateBinormals(S32 num_verts);
+	void allocateWeights(S32 num_verts);
+	void resizeIndices(S32 num_indices);
+	void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
+
+	void pushVertex(const VertexData& cv);
+	void pushVertex(const LLVector4a& pos, const LLVector4a& norm, const LLVector2& tc);
+	void pushIndex(const U16& idx);
+
+	void swapData(LLVolumeFace& rhs);
+
+	void getVertexData(U16 indx, LLVolumeFace::VertexData& cv);
+
+	class VertexMapData : public LLVolumeFace::VertexData
 	{
 	public:
-		LLVector3 mPosition;
-		LLVector3 mNormal;
-		LLVector3 mBinormal;
-		LLVector2 mTexCoord;
+		U16 mIndex;
+
+		bool operator==(const LLVolumeFace::VertexData& rhs) const;
+
+		struct ComparePosition
+		{
+			bool operator()(const LLVector4a& a, const LLVector4a& b) const;
+		};
+
+		typedef std::map<LLVector4a, std::vector<VertexMapData>, VertexMapData::ComparePosition > PointMap;
 	};
 
+	void optimize(F32 angle_cutoff = 2.f);
+	void createOctree();
+
 	enum
 	{
 		SINGLE_MASK =	0x0001,
@@ -827,22 +900,34 @@ class LLVolumeFace
 public:
 	S32 mID;
 	U32 mTypeMask;
-	LLVector3 mCenter;
-	BOOL mHasBinormals;
-
+	
 	// Only used for INNER/OUTER faces
 	S32 mBeginS;
 	S32 mBeginT;
 	S32 mNumS;
 	S32 mNumT;
 
-	LLVector3 mExtents[2]; //minimum and maximum point of face
+	LLVector4a* mExtents; //minimum and maximum point of face
+	LLVector4a* mCenter;
+
+	S32 mNumVertices;
+	S32 mNumIndices;
+
+	LLVector4a* mPositions;
+	LLVector4a* mNormals;
+	LLVector4a* mBinormals;
+	LLVector2* mTexCoords;
+	U16* mIndices;
 
-	std::vector<VertexData> mVertices;
-	std::vector<U16>	mIndices;
-	std::vector<U16>	mTriStrip;
 	std::vector<S32>	mEdge;
 
+	//list of skin weights for rigged volumes
+	// format is mWeights[vertex_index].mV[influence] = <joint_index>.<weight>
+	// mWeights.size() should be empty or match mVertices.size()  
+	LLVector4a* mWeights;
+
+	LLOctreeNode<LLVolumeTriangle>* mOctree;
+
 private:
 	BOOL createUnCutCubeCap(LLVolume* volume, BOOL partial_build = FALSE);
 	BOOL createCap(LLVolume* volume, BOOL partial_build = FALSE);
@@ -853,8 +938,7 @@ class LLVolume : public LLRefCount
 {
 	friend class LLVolumeLODGroup;
 
-private:
-	LLVolume(const LLVolume&);  // Don't implement
+protected:
 	~LLVolume(); // use unref
 
 public:
@@ -876,7 +960,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 +982,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, 
@@ -922,6 +1009,13 @@ class LLVolume : public LLRefCount
 							 LLVector3* normal = NULL,               // return the surface normal at the intersection point
 							 LLVector3* bi_normal = NULL             // return the surface bi-normal at the intersection point
 		);
+
+	S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
+								   S32 face = 1,
+								   LLVector3* intersection = NULL,
+								   LLVector2* tex_coord = NULL,
+								   LLVector3* normal = NULL,
+								   LLVector3* bi_normal = NULL);
 	
 	// The following cleans up vertices and triangles,
 	// getting rid of degenerate triangles and duplicate vertices,
@@ -948,6 +1042,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 +1054,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;
@@ -976,17 +1080,26 @@ class LLVolume : public LLRefCount
 
 std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
 
-LLVector3 calc_binormal_from_triangle(
-		const LLVector3& pos0,
+void calc_binormal_from_triangle(
+		LLVector4a& binormal,
+		const LLVector4a& pos0,
 		const LLVector2& tex0,
-		const LLVector3& pos1,
+		const LLVector4a& pos1,
 		const LLVector2& tex1,
-		const LLVector3& pos2,
+		const LLVector4a& pos2,
 		const LLVector2& tex2);
 
+BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size);
 BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
+BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size);
+
 BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
-							F32* intersection_a, F32* intersection_b, F32* intersection_t, BOOL two_sided);
+							F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided);
+
+BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t);
+BOOL LLTriangleRayIntersectTwoSided(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
+							F32& intersection_a, F32& intersection_b, F32& intersection_t);
 	
 	
 
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 65f3714313574e7cba74292e3065ee964da1bea3..ae26c85ce4ceaf64ff160dfafe986817b46db2a5 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..75c860a91eb7ad426896ef9af9521b99d2563e9f 100644
--- a/indra/llmath/v3math.h
+++ b/indra/llmath/v3math.h
@@ -40,6 +40,7 @@
 class LLVector2;
 class LLVector4;
 class LLMatrix3;
+class LLMatrix4;
 class LLVector3d;
 class LLQuaternion;
 
@@ -115,6 +116,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
@@ -529,6 +531,21 @@ inline void update_min_max(LLVector3& min, LLVector3& max, const LLVector3& pos)
 	}
 }
 
+inline void update_min_max(LLVector3& min, LLVector3& max, const F32* pos)
+{
+	for (U32 i = 0; i < 3; i++)
+	{
+		if (min.mV[i] > pos[i])
+		{
+			min.mV[i] = pos[i];
+		}
+		if (max.mV[i] < pos[i])
+		{
+			max.mV[i] = pos[i];
+		}
+	}
+}
+
 inline F32 angle_between(const LLVector3& a, const LLVector3& b)
 {
 	LLVector3 an = a;
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 970b6747f79e0325046abd9e4fb094d53e2a6581..468dfaf397c83605c2b7de86417f65a659d77308 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -546,7 +546,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 36874a5d48fcfd4f7da5c793ba4abc9a002896c3..16af7ea4fad21d925525f2007f6a55a40f5a4b3f 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"
 
 //////////////////////////////////////////////////////////////////////////////
 /*
@@ -240,7 +241,12 @@ class LLCurl::Easy
 	
 	void resetState();
 
+	static CURL* allocEasyHandle();
+	static void releaseEasyHandle(CURL* handle);
+
 private:	
+	friend class LLCurl;
+
 	CURL*				mCurlEasyHandle;
 	struct curl_slist*	mHeaders;
 	
@@ -255,8 +261,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)
@@ -267,25 +327,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());
@@ -363,6 +425,7 @@ U32 LLCurl::Easy::report(CURLcode code)
 	{
 		responseCode = 499;
 		responseReason = strerror(code) + " : " + mErrorBuffer;
+		setopt(CURLOPT_FRESH_CONNECT, TRUE);
 	}
 		
 	if(responseCode >= 300 && responseCode < 400) //redirect
@@ -456,7 +519,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);
@@ -473,6 +536,9 @@ void LLCurl::Easy::prepRequest(const std::string& url,
 	setCA();
 
 	setopt(CURLOPT_SSL_VERIFYPEER, true);
+	
+	//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);
@@ -533,6 +599,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;
@@ -700,6 +767,7 @@ LLCurlRequest::LLCurlRequest() :
 	mActiveRequestCount(0)
 {
 	mThreadID = LLThread::currentID();
+	mProcessing = FALSE;
 }
 
 LLCurlRequest::~LLCurlRequest()
@@ -734,6 +802,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;
 }
@@ -791,12 +864,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(); )
 	{
@@ -810,6 +912,7 @@ S32 LLCurlRequest::process()
 			delete multi;
 		}
 	}
+	mProcessing = FALSE;
 	return res;
 }
 
@@ -1041,6 +1144,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++)
@@ -1058,6 +1163,21 @@ void LLCurl::cleanupClass()
 	CRYPTO_set_locking_callback(NULL);
 	for_each(sSSLMutex.begin(), sSSLMutex.end(), DeletePointer());
 #endif
-	curl_global_cleanup();
+
+	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;
+	}
 }
 
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index b6a637ae5b4966f6d9c6cf53592b64fc1409da1e..882d0367051ef4788aa5a12487ce458f702060a1 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -202,6 +202,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();
 
@@ -215,6 +217,7 @@ class LLCurlRequest
 	curlmulti_set_t mMultiSet;
 	LLCurl::Multi* mActiveMulti;
 	S32 mActiveRequestCount;
+	BOOL mProcessing;
 	U32 mThreadID; // debug
 };
 
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/llplugin/slplugin/slplugin.cpp b/indra/llplugin/slplugin/slplugin.cpp
index 7d6dde1a58e3dfb03e9947b133f8ce61887c063b..b989e321f1c2c164e23c17cd2487c27b03de3679 100644
--- a/indra/llplugin/slplugin/slplugin.cpp
+++ b/indra/llplugin/slplugin/slplugin.cpp
@@ -273,7 +273,7 @@ int main(int argc, char **argv)
 			}
 			
 			// Check for a change in this process's frontmost window.
-			if(FrontWindow() != front_window)
+			if(ActiveNonFloatingWindow() != front_window)
 			{
 				ProcessSerialNumber self = { 0, kCurrentProcess };
 				ProcessSerialNumber parent = { 0, kNoProcess };
@@ -299,7 +299,7 @@ int main(int argc, char **argv)
 					}
 				}
 								
-				if((FrontWindow() != NULL) && (front_window == NULL))
+				if((ActiveNonFloatingWindow() != NULL) && (front_window == NULL))
 				{
 					// Opening the first window
 					
@@ -311,7 +311,7 @@ int main(int argc, char **argv)
 
 					if(layer_group)
 					{
-						SetWindowGroup(FrontWindow(), layer_group);
+						SetWindowGroup(ActiveNonFloatingWindow(), layer_group);
 					}
 					
 					if(parent_is_front_process)
@@ -320,9 +320,9 @@ int main(int argc, char **argv)
 						(void) SetFrontProcess( &self );
 					}
 
-					ActivateWindow(FrontWindow(), true);					
+					ActivateWindow(ActiveNonFloatingWindow(), true);					
 				}
-				else if((FrontWindow() == NULL) && (front_window != NULL))
+				else if((ActiveNonFloatingWindow() == NULL) && (front_window != NULL))
 				{
 					// Closing the last window
 					
@@ -342,7 +342,7 @@ int main(int argc, char **argv)
 					window_hack_state = 2;
 				}
 
-				front_window = FrontWindow();
+				front_window = ActiveNonFloatingWindow();
 
 			}
 		}
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..7ff68fe34b2ac711072f27d124633f46c6c8262b 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");
@@ -1014,24 +1039,9 @@ void flush_glerror()
 	glGetError();
 }
 
-void assert_glerror()
+void do_assert_glerror()
 {
-	if (!gGLActive)
-	{
-		//llwarns << "GL used while not active!" << llendl;
-
-		if (gDebugSession)
-		{
-			//ll_fail("GL used while not active");
-		}
-	}
-
-	if (gNoRender || !gDebugGL) 
-	{
-		return;
-	}
-	
-	if (!gGLManager.mInited)
+	if (LL_UNLIKELY(!gGLManager.mInited))
 	{
 		LL_ERRS("RenderInit") << "GL not initialized" << LL_ENDL;
 	}
@@ -1039,10 +1049,9 @@ void assert_glerror()
 	GLenum error;
 	error = glGetError();
 	BOOL quit = FALSE;
-	while (error)
+	while (LL_UNLIKELY(error))
 	{
 		quit = TRUE;
-#ifndef LL_LINUX // *FIX: !  This should be an error for linux as well.
 		GLubyte const * gl_error_msg = gluErrorString(error);
 		if (NULL != gl_error_msg)
 		{
@@ -1066,7 +1075,6 @@ void assert_glerror()
 			}
 		}
 		error = glGetError();
-#endif
 	}
 
 	if (quit)
@@ -1082,6 +1090,25 @@ void assert_glerror()
 	}
 }
 
+void assert_glerror()
+{
+	if (!gGLActive)
+	{
+		//llwarns << "GL used while not active!" << llendl;
+
+		if (gDebugSession)
+		{
+			//ll_fail("GL used while not active");
+		}
+	}
+
+	if (!gNoRender && gDebugGL) 
+	{
+		do_assert_glerror();
+	}
+}
+	
+
 void clear_glerror()
 {
 	//  Create or update texture to be used with this data 
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/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index ca92cb6580f70db30ca0e3053cbc9ee75369be21..9256e3959cdfa96912b7a9a62f5ce552c70d5f0b 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -61,7 +61,7 @@ BOOL shouldChange(const LLVector4& v1, const LLVector4& v2)
 
 LLShaderFeatures::LLShaderFeatures()
 : calculatesLighting(false), isShiny(false), isFullbright(false), hasWaterFog(false),
-hasTransport(false), hasSkinning(false), hasAtmospherics(false), isSpecular(false),
+hasTransport(false), hasSkinning(false), hasObjectSkinning(false), hasAtmospherics(false), isSpecular(false),
 hasGamma(false), hasLighting(false), calculatesAtmospherics(false)
 {
 }
@@ -124,7 +124,7 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
 	{
 		GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second);
 		LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
-		if (mShaderLevel > 0)
+		if (shaderhandle > 0)
 		{
 			attachObject(shaderhandle);
 		}
@@ -717,6 +717,18 @@ GLint LLGLSLShader::getUniformLocation(const string& uniform)
 	return -1;
 }
 
+GLint LLGLSLShader::getAttribLocation(U32 attrib)
+{
+	if (attrib < mAttribute.size())
+	{
+		return mAttribute[attrib];
+	}
+	else
+	{
+		return -1;
+	}
+}
+
 void LLGLSLShader::uniform1i(const string& uniform, GLint v)
 {
 	GLint location = getUniformLocation(uniform);
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index 166d4af04cab5be2363c668e0ff36515ab122ce8..dc493ba1629470ac21a56d14f0c857bc5dd2b8fe 100644
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -48,6 +48,7 @@ class LLShaderFeatures
 	bool hasWaterFog; // implies no gamma
 	bool hasTransport; // implies no lighting (it's possible to have neither though)
 	bool hasSkinning;	
+	bool hasObjectSkinning;
 	bool hasAtmospherics;
 	bool hasGamma;
 
@@ -109,7 +110,7 @@ class LLGLSLShader
 	void vertexAttrib4fv(U32 index, GLfloat* v);
 	
 	GLint getUniformLocation(const std::string& uniform);
-	
+	GLint getAttribLocation(U32 attrib);
 	GLint mapUniformTextureChannel(GLint location, GLenum type);
 	
 
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index ff47c57c7022eea684fe4d960a4013a1cfcf2c06..2579bad0b6904a6bd2374f34f625ce2a0e1ea1b5 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -1645,7 +1645,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)
 	{
@@ -1653,26 +1653,91 @@ void LLImageGL::analyzeAlpha(const void* data_in, S32 w, S32 h)
 	}
 
 	U32 length = w * h;
-	const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset ;
+	U32 alphatotal = 0;
 	
-	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)
+			{
+				const U32 s1 = current[0];
+				alphatotal += s1;
+				const U32 s2 = current[w * mAlphaStride];
+				alphatotal += s2;
+				current += mAlphaStride;
+				const U32 s3 = current[0];
+				alphatotal += s3;
+				const U32 s4 = current[w * mAlphaStride];
+				alphatotal += s4;
+				current += mAlphaStride;
+
+				++sample[s1/16];
+				++sample[s2/16];
+				++sample[s3/16];
+				++sample[s4/16];
+
+				const U32 asum = (s1+s2+s3+s4);
+				alphatotal += asum;
+				sample[asum/(16*4)] += 4;
+			}
+			
+			rowstart += 2 * w * mAlphaStride;
+		}
+		length *= 2; // we sampled everything twice, essentially
+	}
+	else
 	{
-		++sample[*current/16];
-		current += mAlphaStride ;
+		const GLubyte* current = ((const GLubyte*) data_in) + mAlphaOffset;
+		for (U32 i = 0; i < length; i++)
+		{
+			const U32 s1 = *current;
+			alphatotal += s1;
+			++sample[s1/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;
+	// also, if all of the alpha samples are clumped on one half
+	// of the range (but not at an absolute extreme), then consider
+	// this to be an intentional effect and don't treat as a mask.
+
+	U32 midrangetotal = 0;
 	for (U32 i = 4; i < 11; i++)
 	{
-		total += sample[i];
+		midrangetotal += sample[i];
+	}
+	U32 lowerhalftotal = 0;
+	for (U32 i = 0; i < 8; i++)
+	{
+		lowerhalftotal += sample[i];
+	}
+	U32 upperhalftotal = 0;
+	for (U32 i = 8; i < 16; i++)
+	{
+		upperhalftotal += sample[i];
 	}
 
-	if (total > length/16)
+	if (midrangetotal > length/16 || // lots of midrange, or
+	    (lowerhalftotal == length && alphatotal != 0) || // all close to transparent but not all totally transparent, or
+	    (upperhalftotal == length && alphatotal != 255*length)) // all close to opaque but not all totally opaque
 	{
-		mIsMask = FALSE;
+		mIsMask = FALSE; // not suitable for masking
 	}
 	else
 	{
@@ -1748,7 +1813,7 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
 		{
 			LL_WARNS_ONCE("render") << "Ugh, non-finite u/v in mask pick" << LL_ENDL;
 			u = v = 0.f;
-			llassert(false);
+			//llassert(false);
 		}
 
 		if (LL_UNLIKELY(u < 0.f || u > 1.f ||
@@ -1756,7 +1821,7 @@ BOOL LLImageGL::getMask(const LLVector2 &tc)
 		{
 			LL_WARNS_ONCE("render") << "Ugh, u/v out of range in image mask pick" << LL_ENDL;
 			u = v = 0.f;
-			llassert(false);
+			//llassert(false);
 		}
 
 		S32 x = llfloor(u * mPickMaskWidth);
diff --git a/indra/llrender/llimagegl.h b/indra/llrender/llimagegl.h
index 41239d24c8967312b5bb00ddf5291bf54430cf21..03939888a503d104fd070149f2666da1d0b78f20 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..70601663e65cb085beddc40e7f01001ff0c64026 100644
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -39,6 +39,7 @@
 #include "llimagegl.h"
 #include "llrendertarget.h"
 #include "lltexture.h"
+#include "llvector4a.h"
 
 LLRender gGL;
 
@@ -53,6 +54,7 @@ U32 LLRender::sUICalls = 0;
 U32 LLRender::sUIVerts = 0;
 
 static const U32 LL_NUM_TEXTURE_LAYERS = 16; 
+static const U32 LL_MAX_UI_STACK_DEPTH = 32;
 
 static GLenum sGLTextureType[] =
 {
@@ -165,6 +167,7 @@ void LLTexUnit::enable(eTextureType type)
 	if ( (mCurrTexType != type || gGL.mDirty) && (type != TT_NONE) )
 	{
 		activate();
+
 		if (mCurrTexType != TT_NONE && !gGL.mDirty)
 		{
 			disable(); // Force a disable of a previous texture type if it's enabled.
@@ -756,14 +759,27 @@ LLRender::LLRender()
     mCount(0),
     mMode(LLRender::TRIANGLES),
     mCurrTextureUnitIndex(0),
-    mMaxAnisotropy(0.f) 
+    mMaxAnisotropy(0.f),
+	mUIStackDepth(0)
 {
 	mBuffer = new LLVertexBuffer(immediate_mask, 0);
 	mBuffer->allocateBuffer(4096, 0, TRUE);
-	mBuffer->getVertexStrider(mVerticesp);
-	mBuffer->getTexCoord0Strider(mTexcoordsp);
-	mBuffer->getColorStrider(mColorsp);
-	
+
+	LLStrider<LLVector3> vert;
+	LLStrider<LLVector2> tc;
+	LLStrider<LLColor4U> color;
+
+	mBuffer->getVertexStrider(vert);
+	mBuffer->getTexCoord0Strider(tc);
+	mBuffer->getColorStrider(color);
+
+	mVerticesp = (LLVector4a*) vert.get();
+	mTexcoordsp = tc.get();
+	mColorsp = color.get();
+
+	mUIOffset = (LLVector4a*) ll_aligned_malloc_16(LL_MAX_UI_STACK_DEPTH*sizeof(LLVector4a));
+	mUIScale = (LLVector4a*) ll_aligned_malloc_16(LL_MAX_UI_STACK_DEPTH*sizeof(LLVector4a));
+		
 	mTexUnits.reserve(LL_NUM_TEXTURE_LAYERS);
 	for (U32 i = 0; i < LL_NUM_TEXTURE_LAYERS; i++)
 	{
@@ -778,8 +794,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()
@@ -796,6 +815,11 @@ void LLRender::shutdown()
 	mTexUnits.clear();
 	delete mDummyTexUnit;
 	mDummyTexUnit = NULL;
+
+	ll_aligned_free_16(mUIOffset);
+	mUIOffset = NULL;
+	ll_aligned_free_16(mUIScale);
+	mUIScale = NULL;
 }
 
 void LLRender::refreshState(void)
@@ -844,84 +868,83 @@ void LLRender::popMatrix()
 
 void LLRender::translateUI(F32 x, F32 y, F32 z)
 {
-	if (mUIOffset.empty())
+	if (mUIStackDepth == 0)
 	{
 		llerrs << "Need to push a UI translation frame before offsetting" << llendl;
 	}
 
-	mUIOffset.front().mV[0] += x;
-	mUIOffset.front().mV[1] += y;
-	mUIOffset.front().mV[2] += z;
+	LLVector4a trans(x,y,z);
+	mUIOffset[mUIStackDepth-1].add(trans);
 }
 
 void LLRender::scaleUI(F32 x, F32 y, F32 z)
 {
-	if (mUIScale.empty())
+	if (mUIStackDepth == 0)
 	{
 		llerrs << "Need to push a UI transformation frame before scaling." << llendl;
 	}
 
-	mUIScale.front().scaleVec(LLVector3(x,y,z));
+	LLVector4a scale(x,y,z);
+	mUIScale[mUIStackDepth-1].mul(scale);
 }
 
 void LLRender::pushUIMatrix()
 {
-	if (mUIOffset.empty())
+	if (mUIStackDepth == 0)
 	{
-		mUIOffset.push_front(LLVector3(0,0,0));
+		mUIOffset[0].clear();
+		mUIScale[0].splat(1.f);
 	}
-	else
+	else if (mUIStackDepth < LL_MAX_UI_STACK_DEPTH)
 	{
-		mUIOffset.push_front(mUIOffset.front());
-	}
-	
-	if (mUIScale.empty())
-	{
-		mUIScale.push_front(LLVector3(1,1,1));
+		mUIOffset[mUIStackDepth] = mUIOffset[mUIStackDepth-1];
+		mUIScale[mUIStackDepth] = mUIScale[mUIStackDepth-1];
 	}
 	else
 	{
-		mUIScale.push_front(mUIScale.front());
+		llerrs << "Blown UI matrix stack." << llendl;
 	}
+	
+	++mUIStackDepth;
+	
 }
 
 void LLRender::popUIMatrix()
 {
-	if (mUIOffset.empty())
+	if (mUIStackDepth == 0)
 	{
 		llerrs << "UI offset stack blown." << llendl;
 	}
-	mUIOffset.pop_front();
-	mUIScale.pop_front();
+	--mUIStackDepth;
 }
 
 LLVector3 LLRender::getUITranslation()
 {
-	if (mUIOffset.empty())
+	if (mUIStackDepth == 0)
 	{
 		llerrs << "UI offset stack empty." << llendl;
 	}
-	return mUIOffset.front();
+	return LLVector3(mUIOffset[mUIStackDepth-1].getF32());
 }
 
 LLVector3 LLRender::getUIScale()
 {
-	if (mUIScale.empty())
+	if (mUIStackDepth == 0)
 	{
 		llerrs << "UI scale stack empty." << llendl;
 	}
-	return mUIScale.front();
+	return LLVector3(mUIScale[mUIStackDepth-1].getF32());
 }
 
 
 void LLRender::loadUIIdentity()
 {
-	if (mUIOffset.empty())
+	if (mUIStackDepth == 0)
 	{
 		llerrs << "Need to push UI translation frame before clearing offset." << llendl;
 	}
-	mUIOffset.front().setVec(0,0,0);
-	mUIScale.front().setVec(1,1,1);
+	mUIOffset[mUIStackDepth-1].clear();
+	mUIScale[mUIStackDepth-1].splat(1.f);
 }
 
 void LLRender::setColorMask(bool writeColor, bool writeAlpha)
@@ -995,15 +1018,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())
@@ -1121,7 +1173,7 @@ void LLRender::flush()
 		}
 #endif
 				
-		if (!mUIOffset.empty())
+		if (mUIStackDepth > 0)
 		{
 			sUICalls++;
 			sUIVerts += mCount;
@@ -1173,24 +1225,22 @@ void LLRender::vertex3f(const GLfloat& x, const GLfloat& y, const GLfloat& z)
 		return;
 	}
 
-	if (mUIOffset.empty())
-	{
-		mVerticesp[mCount] = LLVector3(x,y,z);
-	}
-	else
+	LLVector3& v = reinterpret_cast<LLVector3&>(mVerticesp[mCount]);
+	v.set(x,y,z);
+	if (mUIStackDepth != 0)
 	{
-		LLVector3 vert = (LLVector3(x,y,z)+mUIOffset.front()).scaledVec(mUIScale.front());
-		mVerticesp[mCount] = vert;
+		v += reinterpret_cast<LLVector3&>(mUIOffset[mUIStackDepth-1]);
+		v.scaleVec(reinterpret_cast<LLVector3&>(mUIScale[mUIStackDepth-1]));
 	}
 
 	mCount++;
 	if (mCount < 4096)
 	{
-		mVerticesp[mCount] = mVerticesp[mCount-1];
 		mColorsp[mCount] = mColorsp[mCount-1];
 		mTexcoordsp[mCount] = mTexcoordsp[mCount-1];
 	}
 }
+
 void LLRender::vertex2i(const GLint& x, const GLint& y)
 {
 	vertex3f((GLfloat) x, (GLfloat) y, 0);	
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index a90fbd4a5c43969db1ee0a24c2a46d40f6f2e9b2..11cd95646f4fd77ec03946ac93a8bb29d161169f 100644
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -45,6 +45,7 @@
 #include "v4coloru.h"
 #include "llstrider.h"
 #include "llpointer.h"
+#include "llmemory.h"
 #include "llglheaders.h"
 
 class LLVertexBuffer;
@@ -52,6 +53,7 @@ class LLCubeMap;
 class LLImageGL;
 class LLRenderTarget;
 class LLTexture ;
+class LLVector4a;
 
 class LLTexUnit
 {
@@ -323,7 +325,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);
 
@@ -356,20 +362,23 @@ class LLRender
 	F32				mCurrAlphaFuncVal;
 
 	LLPointer<LLVertexBuffer>	mBuffer;
-	LLStrider<LLVector3>		mVerticesp;
-	LLStrider<LLVector2>		mTexcoordsp;
-	LLStrider<LLColor4U>		mColorsp;
+	LLVector4a*					mVerticesp;
+	LLVector2*					mTexcoordsp;
+	LLColor4U*					mColorsp;
+
 	std::vector<LLTexUnit*>		mTexUnits;
 	LLTexUnit*			mDummyTexUnit;
 
-	eBlendFactor mCurrBlendSFactor;
-	eBlendFactor mCurrBlendDFactor;
-
+	eBlendFactor mCurrBlendColorSFactor;
+	eBlendFactor mCurrBlendColorDFactor;
+	eBlendFactor mCurrBlendAlphaSFactor;
+	eBlendFactor mCurrBlendAlphaDFactor;
 	F32				mMaxAnisotropy;
 
-	std::list<LLVector3> mUIOffset;
-	std::list<LLVector3> mUIScale;
+	LLVector4a* mUIOffset;
+	LLVector4a* mUIScale;
 
+	U32 mUIStackDepth;
 };
 
 extern F64 gGLModelView[16];
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index 1286e91e49c6355b18073404de16b714cdab4448..0f54ebeb690a0ddf01b23a0d85d8755bc0be68c4 100644
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -152,6 +152,14 @@ BOOL LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader)
 			return FALSE;
 		}
 	}
+
+	if (features->hasObjectSkinning)
+	{
+		if (!shader->attachObject("avatar/objectSkinV.glsl"))
+		{
+			return FALSE;
+		}
+	}
 	
 	///////////////////////////////////////
 	// Attach Fragment Shader Features Next
@@ -313,11 +321,14 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
 
 GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type)
 {
-	GLenum error;
-	error = glGetError();
-	if (error != GL_NO_ERROR)
+	GLenum error = GL_NO_ERROR;
+	if (gDebugGL)
 	{
-		LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
+		error = glGetError();
+		if (error != GL_NO_ERROR)
+		{
+			LL_WARNS("ShaderLoading") << "GL ERROR entering loadShaderFile(): " << error << LL_ENDL;
+		}
 	}
 	
 	LL_DEBUGS("ShaderLoading") << "Loading shader file: " << filename << " class " << shader_level << LL_ENDL;
@@ -372,31 +383,39 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 
 	//create shader object
 	GLhandleARB ret = glCreateShaderObjectARB(type);
-	error = glGetError();
-	if (error != GL_NO_ERROR)
+	if (gDebugGL)
 	{
-		LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
+		error = glGetError();
+		if (error != GL_NO_ERROR)
+		{
+			LL_WARNS("ShaderLoading") << "GL ERROR in glCreateShaderObjectARB: " << error << LL_ENDL;
+		}
 	}
-	else
+	
+	//load source
+	glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
+
+	if (gDebugGL)
 	{
-		//load source
-		glShaderSourceARB(ret, count, (const GLcharARB**) text, NULL);
 		error = glGetError();
 		if (error != GL_NO_ERROR)
 		{
 			LL_WARNS("ShaderLoading") << "GL ERROR in glShaderSourceARB: " << error << LL_ENDL;
 		}
-		else
+	}
+
+	//compile source
+	glCompileShaderARB(ret);
+
+	if (gDebugGL)
+	{
+		error = glGetError();
+		if (error != GL_NO_ERROR)
 		{
-			//compile source
-			glCompileShaderARB(ret);
-			error = glGetError();
-			if (error != GL_NO_ERROR)
-			{
-				LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
-			}
+			LL_WARNS("ShaderLoading") << "GL ERROR in glCompileShaderARB: " << error << LL_ENDL;
 		}
 	}
+		
 	//free memory
 	for (GLuint i = 0; i < count; i++)
 	{
@@ -407,13 +426,16 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 		//check for errors
 		GLint success = GL_TRUE;
 		glGetObjectParameterivARB(ret, GL_OBJECT_COMPILE_STATUS_ARB, &success);
-		error = glGetError();
-		if (error != GL_NO_ERROR || success == GL_FALSE) 
+		if (gDebugGL || success == GL_FALSE)
 		{
-			//an error occured, print log
-			LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
-			dumpObjectLog(ret);
-			ret = 0;
+			error = glGetError();
+			if (error != GL_NO_ERROR || success == GL_FALSE) 
+			{
+				//an error occured, print log
+				LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
+				dumpObjectLog(ret);
+				ret = 0;
+			}
 		}
 	}
 	else
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index bf5eda21ebd6c9adc487520b742d499040470d38..514ca25aa095c73fa1ed23b048f612f27900dd30 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -31,6 +31,7 @@
  */
 
 #include "linden_common.h"
+#include "llmemory.h"
 
 #include <boost/static_assert.hpp>
 
@@ -39,6 +40,7 @@
 #include "llglheaders.h"
 #include "llmemtype.h"
 #include "llrender.h"
+#include "llvector4a.h"
 
 //============================================================================
 
@@ -61,9 +63,32 @@ BOOL LLVertexBuffer::sVBOActive = FALSE;
 BOOL LLVertexBuffer::sIBOActive = FALSE;
 U32 LLVertexBuffer::sAllocatedBytes = 0;
 BOOL LLVertexBuffer::sMapped = FALSE;
+BOOL LLVertexBuffer::sUseStreamDraw = TRUE;
+S32	LLVertexBuffer::sWeight4Loc = -1;
 
 std::vector<U32> LLVertexBuffer::sDeleteList;
 
+#define LL_ALIGNED_VB 1
+
+#if LL_ALIGNED_VB
+
+S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
+{
+	sizeof(LLVector4), // TYPE_VERTEX,
+	sizeof(LLVector4), // TYPE_NORMAL,
+	sizeof(LLVector2), // TYPE_TEXCOORD0,
+	sizeof(LLVector2), // TYPE_TEXCOORD1,
+	sizeof(LLVector2), // TYPE_TEXCOORD2,
+	sizeof(LLVector2), // TYPE_TEXCOORD3,
+	sizeof(LLColor4U), // TYPE_COLOR,
+	sizeof(LLVector4), // TYPE_BINORMAL,
+	sizeof(F32),	   // TYPE_WEIGHT,
+	sizeof(LLVector4), // TYPE_WEIGHT4,
+	sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
+};
+
+#else
+
 S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
 {
 	sizeof(LLVector3), // TYPE_VERTEX,
@@ -75,9 +100,12 @@ S32 LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_MAX] =
 	sizeof(LLColor4U), // TYPE_COLOR,
 	sizeof(LLVector3), // TYPE_BINORMAL,
 	sizeof(F32),	   // TYPE_WEIGHT,
+	sizeof(LLVector4), // TYPE_WEIGHT4,
 	sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
 };
 
+#endif
+
 U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = 
 {
 	GL_TRIANGLES,
@@ -209,14 +237,33 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		}
 	
+		if (sLastMask & MAP_WEIGHT4)
+		{
+			if (sWeight4Loc < 0)
+			{
+				llerrs << "Weighting disabled but vertex buffer still bound!" << llendl;
+			}
+
+			if (!(data_mask & MAP_WEIGHT4))
+			{ //disable 4-component skin weight			
+				glDisableVertexAttribArrayARB(sWeight4Loc);
+			}
+		}
+		else if (data_mask & MAP_WEIGHT4)
+		{
+			if (sWeight4Loc >= 0)
+			{ //enable 4-component skin weight
+				glEnableVertexAttribArrayARB(sWeight4Loc);
+			}
+		}
+				
+
 		sLastMask = data_mask;
 	}
 }
 
-void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
+void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
 {
-	llassert(mRequestedNumVerts >= 0);
-
 	if (start >= (U32) mRequestedNumVerts ||
 	    end >= (U32) mRequestedNumVerts)
 	{
@@ -231,6 +278,25 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 		llerrs << "Bad index buffer draw range: [" << indices_offset << ", " << indices_offset+count << "]" << llendl;
 	}
 
+	if (gDebugGL && !useVBOs())
+	{
+		U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+		for (U32 i = 0; i < count; ++i)
+		{
+			if (idx[i] < start || idx[i] > end)
+			{
+				llerrs << "Index out of range: " << idx[i] << " not in [" << start << ", " << end << "]" << llendl;
+			}
+		}
+	}
+}
+
+void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const
+{
+	validateRange(start, end, count, indices_offset);
+
+	llassert(mRequestedNumVerts >= 0);
+
 	if (mGLIndices != sGLRenderIndices)
 	{
 		llerrs << "Wrong index buffer bound." << llendl;
@@ -247,9 +313,11 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 		return;
 	}
 
+	U16* idx = ((U16*) getIndicesPointer())+indices_offset;
+
 	stop_glerror();
 	glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
-		((U16*) getIndicesPointer()) + indices_offset);
+		idx);
 	stop_glerror();
 }
 
@@ -381,16 +449,52 @@ LLVertexBuffer::LLVertexBuffer(U32 typemask, S32 usage) :
 	{
 		mUsage = 0 ; 
 	}
+
+	if (mUsage == GL_STREAM_DRAW_ARB && !sUseStreamDraw)
+	{
+		mUsage = 0;
+	}
 	
 	S32 stride = calcStride(typemask, mOffsets);
 
 	mTypeMask = typemask;
 	mStride = stride;
+	mAlignedOffset = 0;
+	mAlignedIndexOffset = 0;
+
 	sCount++;
 }
 
+#if LL_ALIGNED_VB
 //static
-S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets)
+S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets, S32 num_vertices)
+{
+	S32 offset = 0;
+	for (S32 i=0; i<TYPE_MAX; i++)
+	{
+		U32 mask = 1<<i;
+		if (typemask & mask)
+		{
+			if (offsets)
+			{
+				offsets[i] = offset;
+				offset += LLVertexBuffer::sTypeOffsets[i]*num_vertices;
+				offset = (offset + 0xF) & ~0xF;
+			}
+		}
+	}
+
+	return offset+16;
+}
+
+S32 LLVertexBuffer::getSize() const
+{
+	return mStride;
+}
+
+#else
+//static
+S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets, S32 num_vertices)
 {
 	S32 stride = 0;
 	for (S32 i=0; i<TYPE_MAX; i++)
@@ -409,6 +513,12 @@ S32 LLVertexBuffer::calcStride(const U32& typemask, S32* offsets)
 	return stride;
 }
 
+S32 LLVertexBuffer::getSize() const
+{ 
+	return mNumVerts*mStride; 
+}
+
+#endif
 // protected, use unref()
 //virtual
 LLVertexBuffer::~LLVertexBuffer()
@@ -518,7 +628,7 @@ void LLVertexBuffer::createGLBuffer()
 	{
 		static int gl_buffer_idx = 0;
 		mGLBuffer = ++gl_buffer_idx;
-		mMappedData = new U8[size];
+		mMappedData = (U8*) ll_aligned_malloc_16(size);
 		memset(mMappedData, 0, size);
 	}
 }
@@ -540,16 +650,20 @@ void LLVertexBuffer::createGLIndices()
 
 	mEmpty = TRUE;
 
+	//pad by 16 bytes for aligned copies
+	size += 16;
+
 	if (useVBOs())
 	{
+		//pad by another 16 bytes for VBO pointer adjustment
+		size += 16;
 		mMappedIndexData = NULL;
 		genIndices();
 		mResized = TRUE;
 	}
 	else
 	{
-		mMappedIndexData = new U8[size];
-		memset(mMappedIndexData, 0, size);
+		mMappedIndexData = (U8*) ll_aligned_malloc_16(size);
 		static int gl_buffer_idx = 0;
 		mGLIndices = ++gl_buffer_idx;
 	}
@@ -570,7 +684,7 @@ void LLVertexBuffer::destroyGLBuffer()
 		}
 		else
 		{
-			delete [] mMappedData;
+			ll_aligned_free_16(mMappedData);
 			mMappedData = NULL;
 			mEmpty = TRUE;
 		}
@@ -579,7 +693,7 @@ void LLVertexBuffer::destroyGLBuffer()
 	}
 	
 	mGLBuffer = 0;
-	unbind();
+	//unbind();
 }
 
 void LLVertexBuffer::destroyGLIndices()
@@ -597,7 +711,7 @@ void LLVertexBuffer::destroyGLIndices()
 		}
 		else
 		{
-			delete [] mMappedIndexData;
+			ll_aligned_free_16(mMappedIndexData);
 			mMappedIndexData = NULL;
 			mEmpty = TRUE;
 		}
@@ -606,7 +720,7 @@ void LLVertexBuffer::destroyGLIndices()
 	}
 
 	mGLIndices = 0;
-	unbind();
+	//unbind();
 }
 
 void LLVertexBuffer::updateNumVerts(S32 nverts)
@@ -622,7 +736,7 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
 	}
 
 	mRequestedNumVerts = nverts;
-	
+
 	if (!mDynamicSize)
 	{
 		mNumVerts = nverts;
@@ -637,6 +751,9 @@ void LLVertexBuffer::updateNumVerts(S32 nverts)
 		}
 		mNumVerts = nverts;
 	}
+#if LL_ALIGNED_VB
+	mStride = calcStride(mTypeMask, mOffsets, mNumVerts);
+#endif
 
 }
 
@@ -668,6 +785,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);
 	
@@ -706,9 +829,6 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 	{
 		sAllocatedBytes -= getSize() + getIndicesSize();
 		
-		S32 oldsize = getSize();
-		S32 old_index_size = getIndicesSize();
-
 		updateNumVerts(newnverts);		
 		updateNumIndices(newnindices);
 		
@@ -725,26 +845,10 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 			}
 			else
 			{
-				//delete old buffer, keep GL buffer for now
 				if (!useVBOs())
 				{
-					U8* old = mMappedData;
-					mMappedData = new U8[newsize];
-					if (old)
-					{	
-						memcpy(mMappedData, old, llmin(newsize, oldsize));
-						if (newsize > oldsize)
-						{
-							memset(mMappedData+oldsize, 0, newsize-oldsize);
-						}
-
-						delete [] old;
-					}
-					else
-					{
-						memset(mMappedData, 0, newsize);
-						mEmpty = TRUE;
-					}
+					ll_aligned_free_16(mMappedData);
+					mMappedData = (U8*) ll_aligned_malloc_16(newsize);
 				}
 				mResized = TRUE;
 			}
@@ -764,24 +868,8 @@ void LLVertexBuffer::resizeBuffer(S32 newnverts, S32 newnindices)
 			{
 				if (!useVBOs())
 				{
-					//delete old buffer, keep GL buffer for now
-					U8* old = mMappedIndexData;
-					mMappedIndexData = new U8[new_index_size];
-					
-					if (old)
-					{	
-						memcpy(mMappedIndexData, old, llmin(new_index_size, old_index_size));
-						if (new_index_size > old_index_size)
-						{
-							memset(mMappedIndexData+old_index_size, 0, new_index_size - old_index_size);
-						}
-						delete [] old;
-					}
-					else
-					{
-						memset(mMappedIndexData, 0, new_index_size);
-						mEmpty = TRUE;
-					}
+					ll_aligned_free_16(mMappedIndexData);
+					mMappedIndexData = (U8*) ll_aligned_malloc_16(new_index_size);
 				}
 				mResized = TRUE;
 			}
@@ -813,7 +901,7 @@ BOOL LLVertexBuffer::useVBOs() const
 		return FALSE;
 	}
 #endif
-	return sEnableVBOs;
+	return TRUE;
 }
 
 //----------------------------------------------------------------------------
@@ -838,12 +926,19 @@ U8* LLVertexBuffer::mapBuffer(S32 access)
 			setBuffer(0);
 			mLocked = TRUE;
 			stop_glerror();	
-			mMappedData = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+
+			U8* src = (U8*) glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+			mMappedData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+			mAlignedOffset = mMappedData - src;
+			
 			stop_glerror();
 		}
 		{
 			LLMemType mt_v(LLMemType::MTYPE_VERTEX_MAP_BUFFER_INDICES);
-			mMappedIndexData = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+			U8* src = (U8*) glMapBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB);
+			mMappedIndexData = LL_NEXT_ALIGNED_ADDRESS<U8>(src);
+			mAlignedIndexOffset = mMappedIndexData - src;
+
 			stop_glerror();
 		}
 
@@ -927,6 +1022,45 @@ void LLVertexBuffer::unmapBuffer()
 
 //----------------------------------------------------------------------------
 
+#if LL_ALIGNED_VB
+
+template <class T,S32 type> struct VertexBufferStrider
+{
+	typedef LLStrider<T> strider_t;
+	static bool get(LLVertexBuffer& vbo, 
+					strider_t& strider, 
+					S32 index)
+	{
+		if (vbo.mapBuffer() == NULL)
+		{
+			llwarns << "mapBuffer failed!" << llendl;
+			return FALSE;
+		}
+
+		if (type == LLVertexBuffer::TYPE_INDEX)
+		{
+			S32 stride = sizeof(T);
+			strider = (T*)(vbo.getMappedIndices() + index*stride);
+			strider.setStride(0);
+			return TRUE;
+		}
+		else if (vbo.hasDataType(type))
+		{
+			S32 stride = LLVertexBuffer::sTypeOffsets[type];
+			strider = (T*)(vbo.getMappedData() + vbo.getOffset(type)+index*stride);
+			strider.setStride(stride);
+			return TRUE;
+		}
+		else
+		{
+			llerrs << "VertexBufferStrider could not find valid vertex data." << llendl;
+		}
+		return FALSE;
+	}
+};
+
+#else
+
 template <class T,S32 type> struct VertexBufferStrider
 {
 	typedef LLStrider<T> strider_t;
@@ -962,6 +1096,7 @@ template <class T,S32 type> struct VertexBufferStrider
 	}
 };
 
+#endif
 
 bool LLVertexBuffer::getVertexStrider(LLStrider<LLVector3>& strider, S32 index)
 {
@@ -1003,6 +1138,12 @@ bool LLVertexBuffer::getWeightStrider(LLStrider<F32>& strider, S32 index)
 {
 	return VertexBufferStrider<F32,TYPE_WEIGHT>::get(*this, strider, index);
 }
+
+bool LLVertexBuffer::getWeight4Strider(LLStrider<LLVector4>& strider, S32 index)
+{
+	return VertexBufferStrider<LLVector4,TYPE_WEIGHT4>::get(*this, strider, index);
+}
+
 bool LLVertexBuffer::getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index)
 {
 	return VertexBufferStrider<LLVector4,TYPE_CLOTHWEIGHT>::get(*this, strider, index);
@@ -1177,7 +1318,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 	{		
 		if (mGLBuffer)
 		{
-			if (sEnableVBOs && sVBOActive)
+			if (sVBOActive)
 			{
 				glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
 				sBindCount++;
@@ -1189,7 +1330,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 				setup = TRUE; // ... or a client memory pointer changed
 			}
 		}
-		if (sEnableVBOs && mGLIndices && sIBOActive)
+		if (mGLIndices && sIBOActive)
 		{
 			/*if (sMapped)
 			{
@@ -1218,6 +1359,81 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 	}
 }
 
+#if LL_ALIGNED_VB
+
+// virtual (default)
+void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
+{
+	LLMemType mt2(LLMemType::MTYPE_VERTEX_SETUP_VERTEX_BUFFER);
+	stop_glerror();
+	U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
+
+	if ((data_mask & mTypeMask) != data_mask)
+	{
+		llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
+	}
+
+	if (data_mask & MAP_NORMAL)
+	{
+		glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+	}
+	if (data_mask & MAP_TEXCOORD3)
+	{
+		glClientActiveTextureARB(GL_TEXTURE3_ARB);
+		glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD3], (void*)(base + mOffsets[TYPE_TEXCOORD3]));
+		glClientActiveTextureARB(GL_TEXTURE0_ARB);
+	}
+	if (data_mask & MAP_TEXCOORD2)
+	{
+		glClientActiveTextureARB(GL_TEXTURE2_ARB);
+		glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD2], (void*)(base + mOffsets[TYPE_TEXCOORD2]));
+		glClientActiveTextureARB(GL_TEXTURE0_ARB);
+	}
+	if (data_mask & MAP_TEXCOORD1)
+	{
+		glClientActiveTextureARB(GL_TEXTURE1_ARB);
+		glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+		glClientActiveTextureARB(GL_TEXTURE0_ARB);
+	}
+	if (data_mask & MAP_BINORMAL)
+	{
+		glClientActiveTextureARB(GL_TEXTURE2_ARB);
+		glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+		glClientActiveTextureARB(GL_TEXTURE0_ARB);
+	}
+	if (data_mask & MAP_TEXCOORD0)
+	{
+		glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+	}
+	if (data_mask & MAP_COLOR)
+	{
+		glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeOffsets[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+	}
+	
+	if (data_mask & MAP_WEIGHT)
+	{
+		glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
+	}
+
+	if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
+	{
+		glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
+	}
+
+	if (data_mask & MAP_CLOTHWEIGHT)
+	{
+		glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE,  LLVertexBuffer::sTypeOffsets[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
+	}
+	if (data_mask & MAP_VERTEX)
+	{
+		glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_VERTEX], (void*)(base + 0));
+	}
+
+	llglassertok();
+}
+
+#else
+
 // virtual (default)
 void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 {
@@ -1272,6 +1488,12 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 	{
 		glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, stride, (void*)(base + mOffsets[TYPE_WEIGHT]));
 	}
+
+	if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
+	{
+		glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, stride, (void*)(base+mOffsets[TYPE_WEIGHT4]));
+	}
+
 	if (data_mask & MAP_CLOTHWEIGHT)
 	{
 		glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE,  stride, (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
@@ -1284,6 +1506,8 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask) const
 	llglassertok();
 }
 
+#endif
+
 void LLVertexBuffer::markDirty(U32 vert_index, U32 vert_count, U32 indices_index, U32 indices_count)
 {
 	// TODO: use GL_APPLE_flush_buffer_range here
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index b785a22976993b42923f0b970badb75bc00c89d4..715309b64a279f1bd79d6d45aa7150de40ec6f9a 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -79,10 +79,25 @@ class LLVBOPool : public LLGLNamePool
 class LLVertexBuffer : public LLRefCount
 {
 public:
+	LLVertexBuffer(const LLVertexBuffer& rhs)
+	{
+		*this = rhs;
+	}
+
+	const LLVertexBuffer& operator=(const LLVertexBuffer& rhs)
+	{
+		llerrs << "Illegal operation!" << llendl;
+		return *this;
+	}
+
 	static LLVBOPool sStreamVBOPool;
 	static LLVBOPool sDynamicVBOPool;
 	static LLVBOPool sStreamIBOPool;
 	static LLVBOPool sDynamicIBOPool;
+	
+	static S32	sWeight4Loc;
+
+	static BOOL	sUseStreamDraw;
 
 	static void initClass(bool use_vbo);
 	static void cleanupClass();
@@ -94,7 +109,7 @@ class LLVertexBuffer : public LLRefCount
 	//if offsets is not NULL, its contents will be filled
 	//with the offset of each vertex component in the buffer, 
 	// indexed by the following enum
-	static S32 calcStride(const U32& typemask, S32* offsets = NULL); 										
+	static S32 calcStride(const U32& typemask, S32* offsets = NULL, S32 num_vertices = 0); 										
 
 	enum {
 		TYPE_VERTEX,
@@ -107,6 +122,7 @@ class LLVertexBuffer : public LLRefCount
 		// These use VertexAttribPointer and should possibly be made generic
 		TYPE_BINORMAL,
 		TYPE_WEIGHT,
+		TYPE_WEIGHT4,
 		TYPE_CLOTHWEIGHT,
 		TYPE_MAX,
 		TYPE_INDEX,
@@ -122,6 +138,7 @@ class LLVertexBuffer : public LLRefCount
 		// These use VertexAttribPointer and should possibly be made generic
 		MAP_BINORMAL = (1<<TYPE_BINORMAL),
 		MAP_WEIGHT = (1<<TYPE_WEIGHT),
+		MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
 		MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
 	};
 	
@@ -171,6 +188,7 @@ class LLVertexBuffer : public LLRefCount
 	bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0);
 	bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0);
 	bool getWeightStrider(LLStrider<F32>& strider, S32 index=0);
+	bool getWeight4Strider(LLStrider<LLVector4>& strider, S32 index=0);
 	bool getClothWeightStrider(LLStrider<LLVector4>& strider, S32 index=0);
 	
 	BOOL isEmpty() const					{ return mEmpty; }
@@ -180,12 +198,12 @@ class LLVertexBuffer : public LLRefCount
 	S32 getRequestedVerts() const			{ return mRequestedNumVerts; }
 	S32 getRequestedIndices() const			{ return mRequestedNumIndices; }
 
-	U8* getIndicesPointer() const			{ return useVBOs() ? NULL : mMappedIndexData; }
+	U8* getIndicesPointer() const			{ return useVBOs() ? (U8*) mAlignedIndexOffset : mMappedIndexData; }
 	U8* getVerticesPointer() const			{ return useVBOs() ? NULL : mMappedData; }
 	S32 getStride() const					{ return mStride; }
-	S32 getTypeMask() const					{ return mTypeMask; }
+	U32 getTypeMask() const					{ return mTypeMask; }
 	BOOL hasDataType(S32 type) const		{ return ((1 << type) & getTypeMask()) ? TRUE : FALSE; }
-	S32 getSize() const						{ return mNumVerts*mStride; }
+	S32 getSize() const;
 	S32 getIndicesSize() const				{ return mNumIndices * sizeof(U16); }
 	U8* getMappedData() const				{ return mMappedData; }
 	U8* getMappedIndices() const			{ return mMappedIndexData; }
@@ -200,12 +218,19 @@ class LLVertexBuffer : public LLRefCount
 	void drawArrays(U32 mode, U32 offset, U32 count) const;
 	void drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indices_offset) const;
 
+	//for debugging, validate data in given range is valid
+	void validateRange(U32 start, U32 end, U32 count, U32 offset) const;
+
+	
+
 protected:	
 	S32		mNumVerts;		// Number of vertices allocated
 	S32		mNumIndices;	// Number of indices allocated
 	S32		mRequestedNumVerts;  // Number of vertices requested
 	S32		mRequestedNumIndices;  // Number of indices requested
 
+	ptrdiff_t mAlignedOffset;
+	ptrdiff_t mAlignedIndexOffset;
 	S32		mStride;
 	U32		mTypeMask;
 	S32		mUsage;			// GL usage
@@ -220,7 +245,7 @@ class LLVertexBuffer : public LLRefCount
 	S32		mOffsets[TYPE_MAX];
 	BOOL	mResized;		// if TRUE, client buffer has been resized and GL buffer has not
 	BOOL	mDynamicSize;	// if TRUE, buffer has been resized at least once (and should be padded)
-
+	
 	class DirtyRegion
 	{
 	public:
diff --git a/indra/llui/lllineeditor.cpp b/indra/llui/lllineeditor.cpp
index c93ca1af88cd63a73084ebb36df83f51737a9ac7..c0cc294c02a2f675624e97fd60b7baa7141be609 100644
--- a/indra/llui/lllineeditor.cpp
+++ b/indra/llui/lllineeditor.cpp
@@ -377,7 +377,11 @@ void LLLineEditor::setText(const LLStringExplicit &new_text)
 	setCursor(llmin((S32)mText.length(), getCursor()));
 
 	// Set current history line to end of history.
-	if(mLineHistory.end() != mLineHistory.begin())
+	if (mLineHistory.empty())
+	{
+		mCurrentHistoryLine = mLineHistory.end();
+	}
+	else
 	{
 		mCurrentHistoryLine = mLineHistory.end() - 1;
 	}
diff --git a/indra/llui/llview.cpp b/indra/llui/llview.cpp
index bd56da912165cd861819d2f25ae4331b7298a5d0..6d476ee39018e7c7cea98a73c0634b533d179c8f 100644
--- a/indra/llui/llview.cpp
+++ b/indra/llui/llview.cpp
@@ -121,7 +121,8 @@ LLView::Params::Params()
 }
 
 LLView::LLView(const LLView::Params& p)
-:	mName(p.name),
+:	mVisible(p.visible),
+	mName(p.name),
 	mParentView(NULL),
 	mReshapeFlags(FOLLOWS_NONE),
 	mFromXUI(p.from_xui),
@@ -130,7 +131,6 @@ LLView::LLView(const LLView::Params& p)
 	mNextInsertionOrdinal(0),
 	mHoverCursor(getCursorFromString(p.hover_cursor)),
 	mEnabled(p.enabled),
-	mVisible(p.visible),
 	mMouseOpaque(p.mouse_opaque),
 	mSoundFlags(p.sound_flags),
 	mUseBoundingRect(p.use_bounding_rect),
@@ -1307,7 +1307,13 @@ void LLView::drawChildren()
 {
 	if (!mChildList.empty())
 	{
-		LLRect rootRect = getRootView()->getRect();
+		static const LLRect* rootRect = NULL;
+		
+		if (!mParentView)
+		{
+			rootRect = &mRect;
+		}
+
 		LLRect screenRect;
 
 		++sDepth;
@@ -1321,7 +1327,7 @@ void LLView::drawChildren()
 			{
 				// Only draw views that are within the root view
 				localRectToScreen(viewp->getRect(),&screenRect);
-				if ( rootRect.overlaps(screenRect)  && LLUI::sDirtyRect.overlaps(screenRect))
+				if ( rootRect->overlaps(screenRect)  && LLUI::sDirtyRect.overlaps(screenRect))
 				{
 					LLUI::pushMatrix();
 					{
diff --git a/indra/llui/llview.h b/indra/llui/llview.h
index 3779fedf34ed270f9e3fe50edd92f53c8a36be51..51b234cf5d10a74b356197a67f0a2384fba91251 100644
--- a/indra/llui/llview.h
+++ b/indra/llui/llview.h
@@ -292,7 +292,7 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	void 	setAllChildrenEnabled(BOOL b);
 
 	virtual void	setVisible(BOOL visible);
-	BOOL			getVisible() const			{ return mVisible; }
+	const BOOL&		getVisible() const			{ return mVisible; }
 	virtual void	setEnabled(BOOL enabled);
 	BOOL			getEnabled() const			{ return mEnabled; }
 	/// 'available' in this context means 'visible and enabled': in other
@@ -552,11 +552,13 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	LLView*		mParentView;
 	child_list_t mChildList;
 
-	std::string	mName;
 	// location in pixels, relative to surrounding structure, bottom,left=0,0
+	BOOL		mVisible;
 	LLRect		mRect;
 	LLRect		mBoundingRect;
+	
 	std::string mLayout;
+	std::string	mName;
 	
 	U32			mReshapeFlags;
 
@@ -578,8 +580,6 @@ class LLView : public LLMouseHandler, public LLMortician, public LLFocusableElem
 	LLRootHandle<LLView> mHandle;
 	BOOL		mLastVisible;
 
-	BOOL		mVisible;
-
 	S32			mNextInsertionOrdinal;
 
 	static LLWindow* sWindow;	// All root views must know about their window.
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..2b01288fd7b699317489cee8cf86a3e99a28b6ac 100644
--- a/indra/llvfs/llvfs.cpp
+++ b/indra/llvfs/llvfs.cpp
@@ -2041,6 +2041,11 @@ std::string get_extension(LLAssetType::EType type)
 	case LLAssetType::AT_ANIMATION:
 		extension = ".lla";
 		break;
+#if LL_MESH_ENABLED
+	case LLAssetType::AT_MESH:
+		extension = ".slm";
+		break;
+#endif
 	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 53c636953452a794f110e6bcdb2adc6982b70a6c..e774d128836839dca20095d1f53a0c3c3d734230 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -39,11 +39,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}
@@ -62,6 +64,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
@@ -177,6 +181,7 @@ set(viewer_SOURCE_FILES
     llfloaterhelpbrowser.cpp
     llfloaterhud.cpp
     llfloaterimagepreview.cpp
+    llfloaterimportcollada.cpp
     llfloaterinspect.cpp
     llfloaterinventory.cpp
     llfloaterjoystick.cpp
@@ -187,6 +192,7 @@ set(viewer_SOURCE_FILES
     llfloatermediabrowser.cpp
     llfloatermediasettings.cpp
     llfloatermemleak.cpp
+    llfloatermodelpreview.cpp
     llfloaternamedesc.cpp
     llfloaternotificationsconsole.cpp
     llfloateropenobject.cpp
@@ -285,6 +291,8 @@ set(viewer_SOURCE_FILES
     llmediadataclient.cpp
     llmemoryview.cpp
     llmenucommands.cpp
+    llmeshrepository.cpp
+    llmeshreduction.cpp
     llmetricperformancetester.cpp
     llmimetypes.cpp
     llmorphview.cpp
@@ -701,6 +709,7 @@ set(viewer_HEADER_FILES
     llfloaterhelpbrowser.h
     llfloaterhud.h
     llfloaterimagepreview.h
+    llfloaterimportcollada.h
     llfloaterinspect.h
     llfloaterinventory.h
     llfloaterjoystick.h
@@ -711,6 +720,7 @@ set(viewer_HEADER_FILES
     llfloatermediabrowser.h
     llfloatermediasettings.h
     llfloatermemleak.h
+    llfloatermodelpreview.h
     llfloaternamedesc.h
     llfloaternotificationsconsole.h
     llfloateropenobject.h
@@ -809,6 +819,8 @@ set(viewer_HEADER_FILES
     llmediadataclient.h
     llmemoryview.h
     llmenucommands.h
+    llmeshrepository.h
+    llmeshreduction.h
     llmetricperformancetester.h
     llmimetypes.h
     llmorphview.h
@@ -1232,6 +1244,7 @@ if (WINDOWS)
         ${DINPUT_LIBRARY}
         ${DXGUID_LIBRARY}
         kernel32
+        libboost_system
         odbc32
         odbccp32
         ole32
@@ -1655,6 +1668,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..587b2f2a896f896a494006b6ffbbbffe7728c7bf 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="FALSE"/>
+  <!--SSAO Disabled-->
+  <RenderDeferredSSAO value="FALSE"/>
+  <!--Sun Shadows-->
+  <RenderShadowDetail value="0"/>
+
 </settings>
diff --git a/indra/newview/app_settings/keywords.ini b/indra/newview/app_settings/keywords.ini
index 263b73ba23f47000e791769cc1b69515c3872160..9f8d89abc610acc27b66a32ff901b1e0556209fb 100644
--- a/indra/newview/app_settings/keywords.ini
+++ b/indra/newview/app_settings/keywords.ini
@@ -353,6 +353,11 @@ PRIM_BUMP_SHINY		Followed by an integer face, one of PRIM_SHINY_NONE, PRIM_SHINY
 PRIM_FULLBRIGHT		Followed by an integer face, and TRUE or FALSE
 PRIM_TEXGEN			Followed by an integer face, and one of PRIM_TEXGEN_DEFAULT or PRIM_TEXGEN_PLANAR
 PRIM_GLOW			Followed by an integer face, and a float from 0.0 to 1.0 specifying glow amount
+PRIM_PHYSICS_SHAPE_TYPE Followed by one of PRIM_PHYSICS_SHAPE_PRIM (use prim as-is for physics), PRIM_PHYSICS_SHAPE_NONE (do not use prim for physics), PRIM_PHYSICS_SHAPE_CONVEX (use convex hull of prim for physics)
+
+PRIM_PHYSICS_SHAPE_PRIM     Sets the physics shape type to PRIM (i.e., use the prim as-is in the physics engine)
+PRIM_PHYSICS_SHAPE_NONE     Sets the physics shape type to NONE (i.e., the shape will not exist the physics engine)
+PRIM_PHYSICS_SHAPE_CONVEX   Sets the physics shape type to CONVEX (i.e., use the convex hull of the prim in the physics engine)
 
 PRIM_TYPE_BOX		Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear
 PRIM_TYPE_CYLINDER	Followed by integer hole shape, vector cut, float hollow, vector twist,:vector top size, and vector top shear
diff --git a/indra/newview/app_settings/low_graphics.xml b/indra/newview/app_settings/low_graphics.xml
index d02a13a67131183e48ab8fd9f282bc5340de94d7..a5bbdfc1d0b9611351a9c86701b01aad0638ccf7 100644
--- a/indra/newview/app_settings/low_graphics.xml
+++ b/indra/newview/app_settings/low_graphics.xml
@@ -14,8 +14,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-->
@@ -33,9 +31,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 4506ee6e0cdbc820df767ac2e3e40f6d37e4837e..50adf562459b7f74dc668ee369e7ba78567b8756 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -1787,7 +1787,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>
@@ -1795,6 +1795,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>
@@ -4899,7 +4910,18 @@
       <key>Value</key>
       <real>0</real>
     </map>
-    <key>MigrateCacheDirectory</key>
+  <key>MeshEnabled</key>
+  <map>
+    <key>Comment</key>
+    <string>Expose UI for mesh functionality (may require restart to take effect).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <real>0</real>
+  </map>
+  <key>MigrateCacheDirectory</key>
     <map>
       <key>Comment</key>
       <string>Check for old version of disk cache to migrate to current location</string>
@@ -6226,7 +6248,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>
@@ -6340,7 +6374,7 @@
     <key>Type</key>
     <string>U32</string>
     <key>Value</key>
-    <integer>60</integer>
+    <integer>200</integer>
   </map>
   <key>RenderSSAOFactor</key>
   <map>
@@ -6423,7 +6457,18 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
-    <key>RenderDebugPipeline</key>
+  <key>RenderDebugNormalScale</key>
+  <map>
+    <key>Comment</key>
+    <string>Scale of normals in debug display.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.03</real>
+  </map>
+  <key>RenderDebugPipeline</key>
     <map>
       <key>Comment</key>
       <string>Enable strict pipeline debugging.</string>
@@ -6456,6 +6501,7 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
+ 
   <key>RenderAnimateRes</key>
   <map>
     <key>Comment</key>
@@ -6467,7 +6513,31 @@
     <key>Value</key>
     <integer>0</integer>
   </map>
-  
+
+  <key>RenderBakeSunlight</key>
+  <map>
+    <key>Comment</key>
+    <string>Bake sunlight into vertex buffers for static objects.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+
+  <key>RenderNoAlpha</key>
+  <map>
+    <key>Comment</key>
+    <string>Disable rendering of alpha objects (render all alpha objects as alpha masks).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
+
   <key>RenderAnimateTrees</key>
   <map>
     <key>Comment</key>
@@ -6624,6 +6694,18 @@
     <real>16.0</real>
    </map>
 
+  <key>RenderMinimumLODTriangleCount</key>
+  <map>
+    <key>Comment</key>
+    <string>Triangle count threshold at which automatic LOD generation stops</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>16</real>
+  </map>
+
   <key>RenderEdgeDepthCutoff</key>
   <map>
     <key>Comment</key>
@@ -6715,6 +6797,52 @@
     <real>0.01</real>
   </map>
 
+  <key>RenderShadowBiasError</key>
+  <map>
+    <key>Comment</key>
+    <string>Error scale for shadow bias (based on altitude).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0</real>
+  </map>
+  <key>RenderShadowOffsetError</key>
+  <map>
+    <key>Comment</key>
+    <string>Error scale for shadow offset (based on altitude).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0</real>
+  </map>
+  
+  <key>RenderSpotShadowBias</key>
+  <map>
+    <key>Comment</key>
+    <string>Bias value for shadows (prevent shadow acne).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>-0.001</real>
+  </map>
+  <key>RenderSpotShadowOffset</key>
+  <map>
+    <key>Comment</key>
+    <string>Offset value for shadows (prevent shadow acne).</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>0.04</real>
+  </map>
+
   <key>RenderShadowResolutionScale</key>
   <map>
     <key>Comment</key>
@@ -6727,8 +6855,6 @@
     <real>1.0</real>
   </map>
 
-
-
   <key>RenderDeferredTreeShadowBias</key>
   <map>
     <key>Comment</key>
@@ -6850,7 +6976,7 @@
     <key>Type</key>
     <string>F32</string>
     <key>Value</key>
-    <real>1</real>
+    <real>8</real>
   </map>
 
   <key>RenderDeferred</key>
@@ -6864,19 +6990,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>
@@ -6889,10 +7003,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>
@@ -6901,10 +7015,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>
@@ -6913,10 +7027,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>
@@ -7175,10 +7289,10 @@
       <key>Value</key>
       <real>256.0</real>
     </map>
-    <key>RenderFastAlpha</key>
+    <key>RenderAutoMaskAlphaNonDeferred</key>
     <map>
       <key>Comment</key>
-      <string>Use lossy alpha rendering optimization (opaque/nonexistent small alpha faces).</string>
+      <string>Use alpha masks where appropriate, in the non-deferred (non-'Lighting and Shadows') graphics mode</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -7186,6 +7300,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+    <key>RenderAutoMaskAlphaDeferred</key>
+    <map>
+      <key>Comment</key>
+      <string>Use alpha masks where appropriate, in the deferred ('Lighting and Shadows') graphics mode</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>Boolean</string>
+      <key>Value</key>
+      <integer>1</integer>
+    </map>
     <key>RenderFastUI</key>
     <map>
       <key>Comment</key>
@@ -7447,17 +7572,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>
@@ -7557,7 +7671,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>
@@ -7720,9 +7846,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>
@@ -7788,6 +7925,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>
@@ -7832,17 +7980,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>
@@ -7876,7 +8013,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>
@@ -10492,7 +10652,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..7d18ae503664afbe8ee705d5bdf8381be558db63 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -22,9 +22,6 @@ varying vec3 vary_ambient;
 varying vec3 vary_directional;
 varying vec3 vary_fragcoord;
 varying vec3 vary_position;
-varying vec3 vary_light;
-
-uniform float alpha_soften;
 
 uniform mat4 inv_proj;
 
@@ -57,16 +54,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);
 	//gl_FragColor = vec4(1,0,1,1)*shadow;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index 1a7d58b07badf728127947f7a185e8dab07635ca..43200f1b07551d20e28a89b00eda8e1480a66ac6 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);
@@ -36,28 +36,27 @@ void main()
 	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
 	
-	vary_position = pos.xyz + norm.xyz * (-pos.z/64.0*shadow_offset+shadow_bias);
+	vary_position = pos.xyz;
 		
 	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..da1dafda3667d139bed9226bf65d0d8f92fd44f6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaV.glsl
@@ -10,14 +10,14 @@ 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);
 vec3 scaleDownLight(vec3 light);
 vec3 scaleUpLight(vec3 light);
 
-varying vec4 vary_position;
+varying vec3 vary_position;
 varying vec3 vary_ambient;
 varying vec3 vary_directional;
 varying vec3 vary_normal;
@@ -41,29 +41,28 @@ void main()
 	norm = normalize(norm);
 		
 	gl_Position = gl_ProjectionMatrix * pos;
-	vary_position = pos;
+	vary_position = pos.xyz;
 	vary_normal = norm;	
 	
 	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/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
index 75df3889418feb0d1efc8e1cbb174bb809d13fbe..afbe08a5794c1b813929223920881d45c41c98f4 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
@@ -20,6 +20,7 @@ void main()
 	
 	gl_FragData[0] = vec4(diff.rgb, 0.0);
 	gl_FragData[1] = vec4(0,0,0,0);
-	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
+	vec3 nvn = normalize(vary_normal);
+	gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
index 00083eb6b396e8ec84f627dbf3bf80d20dbc243a..085ffddeece06d39ab2d8f8a44ad79fac655aa08 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
@@ -10,7 +10,7 @@ uniform sampler2D diffuseMap;
 
 void main() 
 {
-	gl_FragColor = vec4(1,1,1,gl_Color.a * texture2D(diffuseMap, gl_TexCoord[0].xy).a);
-	//gl_FragColor = vec4(1,1,1,1);
+	//gl_FragColor = vec4(1,1,1,gl_Color.a * texture2D(diffuseMap, gl_TexCoord[0].xy).a);
+	gl_FragColor = vec4(1,1,1,1);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
index bd5e9dd75803c6b8ded976bd0d1f11cc41694ed4..d1c5d7cb195b4b19876c6ae4f100a3105ca1c440 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;
@@ -39,7 +37,8 @@ vec4 getPosition(vec2 pos_screen)
 
 void main() 
 {
-	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	vec3 pos = getPosition(vary_fragcoord.xy).xyz;
 	vec4 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rgba;
 	
@@ -50,7 +49,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 +60,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/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
index 1c29dae5f7c55cec11d92de337f81400374bd94b..2197744a3726f88b816e767f4d05f651ede99808 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -14,14 +14,16 @@ varying vec3 vary_mat2;
 
 void main() 
 {
-	vec3 col = texture2D(diffuseMap, gl_TexCoord[0].xy).rgb;
+	vec3 col = gl_Color.rgb * texture2D(diffuseMap, gl_TexCoord[0].xy).rgb;
 	vec3 norm = texture2D(bumpMap, gl_TexCoord[0].xy).rgb * 2.0 - 1.0;
 
 	vec3 tnorm = vec3(dot(norm,vary_mat0),
-					  dot(norm,vary_mat1),
-					  dot(norm,vary_mat2));
+			  dot(norm,vary_mat1),
+			  dot(norm,vary_mat2));
 						
-	gl_FragData[0] = vec4(gl_Color.rgb*col, 0.0);
-	gl_FragData[1] = vec4(col*gl_Color.a, gl_Color.a);
-	gl_FragData[2] = vec4(normalize(tnorm)*0.5+0.5, 0.0);
+	gl_FragData[0] = vec4(col, 0.0);
+	gl_FragData[1] = gl_Color.aaaa; // spec
+	//gl_FragData[1] = vec4(vec3(gl_Color.a), gl_Color.a+(1.0-gl_Color.a)*gl_Color.a); // spec - from former class3 - maybe better, but not so well tested
+	vec3 nvn = normalize(tnorm);
+	gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
index 5895ebda84c2aac53b9dc5573bbc432f073dc3bd..3803119cda39713670917e172d205962d1921686 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
@@ -11,8 +11,10 @@ varying vec3 vary_normal;
 
 void main() 
 {
-	vec3 col = texture2D(diffuseMap, gl_TexCoord[0].xy).rgb;
-	gl_FragData[0] = vec4(gl_Color.rgb*col, 0.0);
-	gl_FragData[1] = vec4(col*(gl_Color.a*1.5), gl_Color.a);
-	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
+	vec3 col = gl_Color.rgb * texture2D(diffuseMap, gl_TexCoord[0].xy).rgb;
+	gl_FragData[0] = vec4(col, 0.0);
+	gl_FragData[1] = gl_Color.aaaa; // spec
+	//gl_FragData[1] = vec4(vec3(gl_Color.a), gl_Color.a+(1.0-gl_Color.a)*gl_Color.a); // spec - from former class3 - maybe better, but not so well tested
+	vec3 nvn = normalize(vary_normal);
+	gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0);
 }
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/giF.glsl b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
index b351eec6e54536d7e822822f381a6cf5d16b04ac..d4b153c4af9f7d00b853c68cbb40cc09ce831e7d 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/giF.glsl
@@ -159,7 +159,8 @@ void main()
 {
 	vec2 pos_screen = vary_fragcoord.xy;
 	vec4 pos = getPosition(pos_screen);
-	vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, pos_screen).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	
 	gl_FragData[0].xyz = giAmbient(pos, norm);
 }
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/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
index 797b9e9f3bf88fe17740443abe5f6ceeeb6ce9d1..b494b521cab77e3f2ebaac631d609c9a6a1ddadd 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -53,7 +53,9 @@ void main()
 		discard;
 	}
 	
-	vec3 norm = normalize(texture2DRect(normalMap, frag.xy).xyz*2.0-1.0);
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
+	norm = normalize(norm);
 	vec4 spec = texture2DRect(specularRect, frag.xy);
 	vec3 diff = texture2DRect(diffuseRect, frag.xy).rgb;
 	float noise = texture2D(noiseMap, frag.xy/128.0).b;
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/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
index 78256e20cc6af290298168401d8b20a334ecba39..3aecbc5f23cae2e022567dc0964097d783f126df 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -55,7 +55,8 @@ void main()
 		discard;
 	}
 	
-	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	float da = dot(norm, lv);
 	if (da < 0.0)
 	{
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl
index 9612aee40597752615947db97084b37fcdc686ea..bd554c2d84ca26a6ea658399ccc16d4d214b564b 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postgiF.glsl
@@ -38,10 +38,10 @@ vec4 getPosition(vec2 pos_screen)
 
 void main() 
 {
-	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	vec3 pos = getPosition(vary_fragcoord.xy).xyz;
 	
-	
 	vec3 ccol = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
 	vec2 dlt = kern_scale * delta/(1.0+norm.xy*norm.xy);
 	dlt /= max(-pos.z*dist_factor, 1.0);
@@ -51,9 +51,10 @@ void main()
 	for (int i = 0; i < kern_length; i++)
 	{
 		vec2 tc = vary_fragcoord.xy + kern[i].y*dlt;
-	    vec3 sampNorm = texture2DRect(normalMap, tc.xy).xyz*2.0-1.0;
+		vec3 sampNorm = texture2DRect(normalMap, tc.xy).xyz;
+		sampNorm = vec3((sampNorm.xy-0.5)*2.0,sampNorm.z); // unpack norm
 	    
-	    float d = dot(norm.xyz, sampNorm);
+		float d = dot(norm.xyz, sampNorm);
 		
 		if (d > 0.8)
 		{
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index b4b0d0ce9de837d2644ff9aebb7c0a4dcd737719..bef91e735dc7751267bfa1fa302477c8dc2c2c4f 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,8 +257,10 @@ vec3 scaleSoftClip(vec3 light)
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
-	vec3 pos = getPosition(tc).xyz;
-	vec3 norm = texture2DRect(normalMap, tc).xyz*2.0-1.0;
+	float depth = texture2DRect(depthMap, tc.xy).a;
+	vec3 pos = getPosition_d(tc, depth).xyz;
+	vec3 norm = texture2DRect(normalMap, tc).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	//vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
 	
 	float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
@@ -250,23 +268,76 @@ 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 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+		float sa = dot(refnormpersp, vary_light.xyz);
+		vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
+
+		/*
+		// screen-space cheap fakey reflection map
+		//
+		vec3 refnorm = normalize(reflect(vec3(0,0,-1), norm.xyz));
+		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
+		float checkoffset = (3.0 + (7.0*(1.0-spec.a)))*(checkerboard-0.5);
+		ref2d += vec2(checkoffset, checkoffset);
+		ref2d += tc.xy; // use as offset from destination
+		// Get attributes from the 2D guess point.
+		// We average two samples of diffuse (not of anything else) per
+		// pixel to try to reduce aliasing some more.
+		vec3 refcol = 0.5 * (texture2DRect(diffuseRect, ref2d + vec2(0.0, -checkoffset)).rgb +
+				     texture2DRect(diffuseRect, ref2d + vec2(-checkoffset, 0.0)).rgb);
+		float refdepth = texture2DRect(depthMap, ref2d).a;
+		vec3 refpos = getPosition_d(ref2d, refdepth).xyz;
+		vec3 refn = texture2DRect(normalMap, ref2d).rgb;
+		refn = normalize(vec3((refn.xy-0.5)*2.0,refn.z)); // unpack norm
+		// 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.
+		// reflect light direction to increase the illusion that
+		// these are reflections.
+		vec3 reflight = reflect(lightnorm.xyz, norm.xyz);
+		float reflit = max(dot(refn, reflight.xyz), 0.0);
+		// apply sun color to guess-point, dampen according to inappropriateness of guess
+		float refmod = min(refapprop, reflit);
+		vec3 refprod = vary_SunlitColor * refcol.rgb * refmod;
+		vec3 ssshiny = (refprod * spec.a);
+		ssshiny *= 0.3; // dampen it even more
+		*/
+		vec3 ssshiny = vec3(0,0,0);
+
+		// 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..1b95b253c3509c39387f3ebc0fd60baf9c890450 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
@@ -68,7 +68,8 @@ void main()
 		discard;
 	}
 	
-	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	
 	norm = normalize(norm);
 	float l_dist = -dot(lv, proj_n);
@@ -161,17 +162,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..cdbed4b7917a529f9dcf73dffd107de53508a917
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
@@ -0,0 +1,124 @@
+/** 
+ * @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;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
+		
+	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/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
index 3cccfb72020b5eb143cf17cd781d05ae27843883..fa0a60c98d913b572c9b65c2f6db6bb3dc797cbb 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
@@ -29,6 +29,7 @@ void main()
 	
 	gl_FragData[0] = vec4(outColor.rgb, 0.0);
 	gl_FragData[1] = vec4(outColor.rgb*0.2, 0.2);
-	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
+	vec3 nvn = normalize(vary_normal);
+	gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
index 258acee08c1decb03f379ed31f3188bad9dbeda8..5b33ea5bfe259d5e1afec2cf1b84118971bf502f 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
@@ -14,5 +14,6 @@ void main()
 	vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy);
 	gl_FragData[0] = vec4(gl_Color.rgb*col.rgb, col.a <= 0.5 ? 0.0 : 0.005);
 	gl_FragData[1] = vec4(0,0,0,0);
-	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
+	vec3 nvn = normalize(vary_normal);
+	gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.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..361ae8dc843ec61724d27fa34eca92123ae29377 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.xy*0.5+0.5, screenspacewavef.z, screenspacewavef.z*0.5); // normalxyz, 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/class1/objects/shinyV.glsl b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
index c2e1ddf734fb30b384e92a7e184dfdeeee4251d8..101458c438d53bf1dada4564e9e07b83d25e5f97 100644
--- a/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/shinyV.glsl
@@ -12,7 +12,7 @@ uniform vec4 origin;
 void main()
 {
 	//transform vertex
-	gl_Position = ftransform(); //gl_ModelViewProjectionMatrix * gl_Vertex;
+	gl_Position = ftransform();
 	
 	vec4 pos = (gl_ModelViewMatrix * gl_Vertex);
 	vec3 norm = normalize(gl_NormalMatrix * gl_Normal);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
index ad16de6d8160a7e34589fc82bec521af550f70c1..fa6b4e2afb174dba374009eea5f50d4475721060 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,18 +113,9 @@ 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;
+	//gl_FragColor = vec4(1,shadow,1,1);
 	
 }
 
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..de423ee22ac60f0ef097380b3d344bb360b94759 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);
@@ -21,6 +21,7 @@ varying vec3 vary_position;
 varying vec3 vary_ambient;
 varying vec3 vary_directional;
 varying vec3 vary_normal;
+varying vec3 vary_fragcoord;
 
 uniform float near_clip;
 uniform float shadow_offset;
@@ -53,23 +54,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)));
 	
@@ -78,7 +78,7 @@ void main()
 	gl_FrontColor = col;
 
 	gl_FogFragCoord = pos.z;
-
+	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
 }
 
 
diff --git a/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl
index 0fad5b4b50be87187b9e320cd1aee3aa28e61db2..d1c5d7cb195b4b19876c6ae4f100a3105ca1c440 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/blurLightF.glsl
@@ -37,7 +37,8 @@ vec4 getPosition(vec2 pos_screen)
 
 void main() 
 {
-	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	vec3 pos = getPosition(vary_fragcoord.xy).xyz;
 	vec4 ccol = texture2DRect(lightMap, vary_fragcoord.xy).rgba;
 	
diff --git a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
index 02beddd43b35dba58858633821dd536b08ac1185..e32e9f4b32678051020c31f853c1e7422d10ec16 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/edgeF.glsl
@@ -31,7 +31,8 @@ float getDepth(vec2 pos_screen)
 
 void main() 
 {
-	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	float depth = getDepth(vary_fragcoord.xy);
 	
 	vec2 tc = vary_fragcoord.xy;
@@ -46,8 +47,12 @@ void main()
 	de = step(depth_cutoff, de);
 	
 	vec2 ne;
-	ne.x = dot(texture2DRect(normalMap, tc+vec2(-sc,-sc)).rgb*2.0-1.0, norm);
-	ne.y = dot(texture2DRect(normalMap, tc+vec2(sc,sc)).rgb*2.0-1.0, norm);
+	vec3 nexnorm = texture2DRect(normalMap, tc+vec2(-sc,-sc)).rgb;
+	nexnorm = vec3((nexnorm.xy-0.5)*2.0,nexnorm.z); // unpack norm
+	ne.x = dot(nexnorm, norm);
+	vec3 neynorm = texture2DRect(normalMap, tc+vec2(sc,sc)).rgb;
+	neynorm = vec3((neynorm.xy-0.5)*2.0,neynorm.z); // unpack norm
+	ne.y = dot(neynorm, norm);
 	
 	ne = 1.0-ne;
 	
diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
index 651959413cd06cad296bf3dfd2a4e3a89babe51e..22ffb58c635e2c7d37d4649d10b9271cb5998d6c 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;
@@ -83,7 +129,8 @@ void main()
 		shadow = min(sh[proj_shadow_idx]+shadow_fade, 1.0);
 	}
 	
-	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	
 	norm = normalize(norm);
 	float l_dist = -dot(lv, proj_n);
@@ -126,7 +173,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 +184,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 +214,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..fd6ae2b96083ee8bc412f877f2b9779646771bb8 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,8 +256,10 @@ vec3 scaleSoftClip(vec3 light)
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
-	vec3 pos = getPosition(tc).xyz;
-	vec3 norm = texture2DRect(normalMap, tc).xyz*2.0-1.0;
+	float depth = texture2DRect(depthMap, tc.xy).a;
+	vec3 pos = getPosition_d(tc, depth).xyz;
+	vec3 norm = texture2DRect(normalMap, tc).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	//vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
 	
 	float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
@@ -271,24 +278,67 @@ 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 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+		float sa = dot(refnormpersp, vary_light.xyz);
+		vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*texture2D(lightFunc, vec2(sa, spec.a)).a;
+
+		/*
+		// screen-space cheap fakey reflection map
+		//
+		vec3 refnorm = normalize(reflect(vec3(0,0,-1), norm.xyz));
+		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
+		float checkoffset = (3.0 + (7.0*(1.0-spec.a)))*(checkerboard-0.5);
+		ref2d += vec2(checkoffset, checkoffset);
+		ref2d += tc.xy; // use as offset from destination
+		// Get attributes from the 2D guess point.
+		// We average two samples of diffuse (not of anything else) per
+		// pixel to try to reduce aliasing some more.
+		vec3 refcol = 0.5 * (texture2DRect(diffuseRect, ref2d + vec2(0.0, -checkoffset)).rgb +
+				     texture2DRect(diffuseRect, ref2d + vec2(-checkoffset, 0.0)).rgb);
+		float refdepth = texture2DRect(depthMap, ref2d).a;
+		vec3 refpos = getPosition_d(ref2d, refdepth).xyz;
+		float refshad = texture2DRect(lightMap, ref2d).r;
+		vec3 refn = texture2DRect(normalMap, ref2d).rgb;
+		refn = vec3((refn.xy-0.5)*2.0,refn.z); // unpack norm
+		refn = normalize(refn);
+		// 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
+		// reflect light direction to increase the illusion that
+		// these are reflections.
+		vec3 reflight = reflect(lightnorm.xyz, norm.xyz);
+		float reflit = min(max(dot(refn, reflight.xyz), 0.0), refshad);
+		// apply sun color to guess-point, dampen according to inappropriateness of guess
+		float refmod = min(refapprop, reflit);
+		vec3 refprod = vary_SunlitColor * refcol.rgb * refmod;
+		vec3 ssshiny = (refprod * spec.a);
+		ssshiny *= 0.3; // dampen it even more
+		*/
+		vec3 ssshiny = vec3(0,0,0);
+
+		// 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..8a90199b7caf1e6b450d911d71420fa13f9ca16c 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
@@ -82,7 +82,8 @@ void main()
 		discard;
 	}
 	
-	vec3 norm = texture2DRect(normalMap, frag.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	
 	norm = normalize(norm);
 	float l_dist = -dot(lv, proj_n);
@@ -179,21 +180,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..7423347346bd8a3f56ce0fdb4003fa16d2f14630 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;
@@ -39,6 +41,9 @@ uniform vec2 proj_shadow_res;
 uniform float shadow_bias;
 uniform float shadow_offset;
 
+uniform float spot_shadow_bias;
+uniform float spot_shadow_offset;
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).a;
@@ -52,56 +57,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;
@@ -123,7 +78,7 @@ float pcfShadow(sampler2DRectShadow shadowMap, vec4 stc, float scl)
 float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl)
 {
 	stc.xyz /= stc.w;
-	stc.z += shadow_bias*scl;
+	stc.z += spot_shadow_bias*scl;
 	
 	float cs = shadow2D(shadowMap, stc.xyz).x;
 	float shadow = cs;
@@ -134,8 +89,7 @@ float pcfShadow(sampler2DShadow shadowMap, vec4 stc, float scl)
 	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;
@@ -149,7 +103,10 @@ void main()
 	
 	vec4 pos = getPosition(pos_screen);
 	
-    vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
+	vec4 nmap4 = texture2DRect(normalMap, pos_screen);
+	nmap4 = vec4((nmap4.xy-0.5)*2.0,nmap4.z,nmap4.w); // unpack norm
+	float displace = nmap4.w;
+	vec3 norm = nmap4.xyz;
 	
 	/*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 +115,12 @@ 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);
+	vec3 shadow_pos = pos.xyz + displace*norm;
+	vec3 offset = vary_light.xyz * (1.0-dp_directional_light);
+	
+	vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0);
 	
 	if (spos.z > -shadow_clip.w)
 	{	
@@ -220,15 +180,17 @@ void main()
 	}
 	
 	gl_FragColor[0] = shadow;
-	gl_FragColor[1] = calcAmbientOcclusion(pos, norm);
+	gl_FragColor[1] = 1.0;
+	
+	spos = vec4(shadow_pos+norm*spot_shadow_offset, 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); 
 	
 	//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); 
 
 	//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..4e33a1af450b84a12097dd54695c69da4bfa6128
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
@@ -0,0 +1,257 @@
+/** 
+ * @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;
+
+uniform float spot_shadow_bias;
+uniform float spot_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 += spot_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);
+	nmap4 = vec4((nmap4.xy-0.5)*2.0,nmap4.z,nmap4.w); // unpack norm
+	float displace = nmap4.w;
+	vec3 norm = nmap4.xyz;
+	
+	/*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));
+
+	vec3 shadow_pos = pos.xyz + displace*norm;
+	vec3 offset = vary_light.xyz * (1.0-dp_directional_light);
+	
+	vec4 spos = vec4(shadow_pos+offset*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);
+	
+	spos.xyz = shadow_pos+offset*spot_shadow_offset;
+	
+	//spotlight shadow 1
+	vec4 lpos = shadow_matrix[4]*spos;
+	gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.8); 
+	
+	//spotlight shadow 2
+	lpos = shadow_matrix[5]*spos;
+	gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.8); 
+
+	//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/giDownsampleF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl
index 7325825d6d4e21c7b07cfefd0fbc840000dd84f7..66606233cdf8171763456ca2db7adee7aae37a41 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/giDownsampleF.glsl
@@ -44,7 +44,8 @@ float getDepth(vec2 pos_screen)
 
 void main() 
 {
-	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, vary_fragcoord.xy).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	float depth = getDepth(vary_fragcoord.xy);
 		
 	vec3 ccol = texture2DRect(giLightMap, vary_fragcoord.xy).rgb;
@@ -56,9 +57,10 @@ void main()
 	for (int i = 0; i < kern_length; i++)
 	{
 		vec2 tc = vary_fragcoord.xy + kern[i].y*dlt;
-	    vec3 sampNorm = texture2DRect(normalMap, tc.xy).xyz*2.0-1.0;
-	    
-	   float d = dot(norm.xyz, sampNorm);
+		vec3 sampNorm = texture2DRect(normalMap, tc.xy).xyz;
+		sampNorm = vec3((sampNorm.xy-0.5)*2.0,sampNorm.z); // unpack norm
+		
+		float d = dot(norm.xyz, sampNorm);
 		
 		if (d > 0.5)
 		{
diff --git a/indra/newview/app_settings/shaders/class3/deferred/giF.glsl b/indra/newview/app_settings/shaders/class3/deferred/giF.glsl
index 939710cb56303208c8123a2499385573cfb06d0e..1b8354dbd10b503b675a8b71668114882eda8001 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/giF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/giF.glsl
@@ -178,7 +178,8 @@ void main()
 	
 	float rad = gi_range*0.5;
 	
-	vec3 norm = texture2DRect(normalMap, pos_screen).xyz*2.0-1.0;
+	vec3 norm = texture2DRect(normalMap, pos_screen).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	float dist = max(length(pos.xyz)-rad, 0.0);
 	
 	float da = clamp(1.0-dist/rad, 0.0, 1.0);
diff --git a/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class3/deferred/softenLightF.glsl
index 96a083b52216947b72f53b67522fb86554de6b46..c88edd0a60b11c0d5219b643f88d898a30e13039 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,8 +257,10 @@ vec3 scaleSoftClip(vec3 light)
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
-	vec3 pos = getPosition(tc).xyz;
-	vec3 norm = texture2DRect(normalMap, tc).xyz*2.0-1.0;
+	float depth = texture2DRect(depthMap, tc.xy).a;
+	vec3 pos = getPosition_d(tc, depth).xyz;
+	vec3 norm = texture2DRect(normalMap, tc).xyz;
+	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
 	//vec3 nz = texture2D(noiseMap, vary_fragcoord.xy/128.0).xyz;
 	
 	float da = max(dot(norm.xyz, vary_light.xyz), 0.0);
@@ -274,11 +281,63 @@ 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 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+		float sa = dot(refnormpersp, vary_light.xyz);
+		vec3 dumbshiny = vary_SunlitColor*scol*texture2D(lightFunc, vec2(sa, spec.a)).a;
+
+		/*
+		// screen-space cheap fakey reflection map
+		//
+		vec3 refnorm = normalize(reflect(vec3(0,0,-1), norm.xyz));
+		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
+		float checkoffset = (3.0 + (7.0*(1.0-spec.a)))*(checkerboard-0.5);
+
+		ref2d += vec2(checkoffset, checkoffset);
+		ref2d += tc.xy; // use as offset from destination
+		// Get attributes from the 2D guess point.
+		// We average two samples of diffuse (not of anything else) per
+		// pixel to try to reduce aliasing some more.
+		vec3 refcol = 0.5 * (texture2DRect(diffuseRect, ref2d + vec2(0.0, -checkoffset)).rgb +
+				     texture2DRect(diffuseRect, ref2d + vec2(-checkoffset, 0.0)).rgb);
+		float refdepth = texture2DRect(depthMap, ref2d).a;
+		vec3 refpos = getPosition_d(ref2d, refdepth).xyz;
+		float refshad = texture2DRect(lightMap, ref2d).r;
+		vec3 refn = texture2DRect(normalMap, ref2d).rgb;
+		refn = vec3((refn.xy-0.5)*2.0,refn.z); // unpack norm
+		refn = normalize(refn);
+		// 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.
+		// reflect light direction to increase the illusion that
+		// these are reflections.
+		vec3 reflight = reflect(lightnorm.xyz, norm.xyz);
+		float reflit = min(max(dot(refn, reflight.xyz), 0.0), refshad);
+		// apply sun color to guess-point, dampen according to inappropriateness of guess
+		float refmod = min(refapprop, reflit);
+		vec3 refprod = vary_SunlitColor * refcol.rgb * refmod;
+		vec3 ssshiny = (refprod * spec.a);
+		ssshiny *= 0.3; // dampen it even more
+		*/
+		vec3 ssshiny = vec3(0,0,0);
+
+		// add the two types of shiny together
+		col += (ssshiny + dumbshiny) * spec.rgb;
 	}
 	
 	col = atmosLighting(col);
diff --git a/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl
index 258acee08c1decb03f379ed31f3188bad9dbeda8..5b33ea5bfe259d5e1afec2cf1b84118971bf502f 100644
--- a/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl
+++ b/indra/newview/app_settings/shaders/class3/deferred/treeF.glsl
@@ -14,5 +14,6 @@ void main()
 	vec4 col = texture2D(diffuseMap, gl_TexCoord[0].xy);
 	gl_FragData[0] = vec4(gl_Color.rgb*col.rgb, col.a <= 0.5 ? 0.0 : 0.005);
 	gl_FragData[1] = vec4(0,0,0,0);
-	gl_FragData[2] = vec4(normalize(vary_normal)*0.5+0.5, 0.0);
+	vec3 nvn = normalize(vary_normal);
+	gl_FragData[2] = vec4(nvn.xy * 0.5 + 0.5, nvn.z, 0.0);
 }
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 de4d787d658819ffbcf95a9af1ffe0288bef71af..dffb56e7dcbbc1bb03bf6f9cd154779ab9adf83e 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
 RenderAvatarMaxVisible      1   35
@@ -36,18 +36,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
@@ -57,7 +55,11 @@ Disregard128DefaultDrawDistance	1	1
 Disregard96DefaultDrawDistance	1	1
 RenderTextureMemoryMultiple		1	1.0
 RenderShaderLightingMaxLevel	1	3
+RenderDeferred				1	1
 SkyUseClassicClouds			1	1
+RenderDeferredSSAO			1	1
+RenderShadowDetail			1	2
+RenderUseFBO				1	1
 
 //
 // Low Graphics Settings
@@ -71,7 +73,6 @@ RenderAvatarVP				1	0
 RenderFarClip				1	64
 RenderFlexTimeFactor		1	0
 RenderGlowResolutionPow		1	8
-RenderLightingDetail		1	0
 RenderMaxPartCount			1	0
 RenderObjectBump			1	0
 RenderReflectionDetail		1	0
@@ -80,11 +81,14 @@ RenderTerrainLODFactor		1	1
 RenderTreeLODFactor			1	0
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	0
-RenderWaterReflections		1	0
 VertexShaderEnable			1	0
 WindLightUseAtmosShaders	1	0
 WLSkyDetail					1	48
+RenderDeferred				1	0
 SkyUseClassicClouds			1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
 
 //
 // Mid Graphics Settings
@@ -97,7 +101,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
@@ -106,10 +109,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)
@@ -122,7 +128,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
@@ -131,10 +136,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	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
 
 //
 // Ultra graphics (REALLY PURTY!)
@@ -147,19 +155,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)
@@ -197,9 +207,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
@@ -207,9 +220,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
 //
@@ -217,14 +234,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
@@ -248,11 +268,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 adda7cec4dd435392605cfd83d9fb635e013f4c3..8b3b30a552bdb1359b48f9a167a2b3c9832ef293 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
 RenderAvatarMaxVisible      1   35
@@ -36,18 +36,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,7 +54,11 @@ WLSkyDetail					1	128
 Disregard128DefaultDrawDistance	1	1
 Disregard96DefaultDrawDistance	1	1
 RenderTextureMemoryMultiple		1	1.0
+RenderShaderLightingMaxLevel		1	3
 SkyUseClassicClouds			1	1
+RenderDeferred				1	1
+RenderDeferredSSAO			1	1
+RenderShadowDetail			1	2
 
 //
 // Low Graphics Settings
@@ -70,7 +72,6 @@ RenderAvatarVP				1	0
 RenderFarClip				1	64
 RenderFlexTimeFactor		1	0
 RenderGlowResolutionPow		1	8
-RenderLightingDetail		1	0
 RenderMaxPartCount			1	0
 RenderObjectBump			1	0
 RenderReflectionDetail		1	0
@@ -79,11 +80,14 @@ RenderTerrainLODFactor		1	1
 RenderTreeLODFactor			1	0
 RenderUseImpostors			1	1
 RenderVolumeLODFactor		1	0
-RenderWaterReflections		1	0
 VertexShaderEnable			1	0
 WindLightUseAtmosShaders	1	0
 WLSkyDetail					1	48
+RenderDeferred				1	0
 SkyUseClassicClouds			1	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
 
 //
 // Mid Graphics Settings
@@ -96,7 +100,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
@@ -105,10 +108,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)
@@ -121,7 +127,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
@@ -130,10 +135,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	0
+RenderDeferredSSAO			1	0
+RenderShadowDetail			1	0
+
 
 //
 // Ultra graphics (REALLY PURTY!)
@@ -146,19 +154,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)
@@ -196,9 +206,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
@@ -206,9 +219,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
 //
@@ -216,14 +233,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
@@ -247,13 +267,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
@@ -465,17 +483,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 82886d7e2cb115579f6431709ffecc0dcbf48be9..055127d38699d91b04c9c3e891a13a17c30635ab 100644
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -370,6 +370,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/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 977f1c9fa8dcbc081761b9a013466f5f5c5391d3..e7fbf0120e4c3a6dba2123cb17b3fe5ebf2c2b78 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -556,7 +556,9 @@ BOOL LLAgentCamera::calcCameraMinDistance(F32 &obj_min_distance)
 {
 	BOOL soft_limit = FALSE; // is the bounding box to be treated literally (volumes) or as an approximation (avatars)
 
-	if (!mFocusObject || mFocusObject->isDead())
+	if (!mFocusObject || mFocusObject->isDead() || 
+		mFocusObject->isMesh() ||
+		gSavedSettings.getBOOL("DisableCameraConstraints"))
 	{
 		obj_min_distance = 0.f;
 		return TRUE;
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index f4004d5664c7d83da641d203d4a3d4d52d8e3610..64b66cb9900fd3dce63fbe3f45ee8beb1b0eea5c 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,8 @@
 #include "llteleporthistory.h"
 #include "lllocationhistory.h"
 #include "llfasttimerview.h"
+#include "llvector4a.h"
+#include "llviewermenufile.h"
 #include "llvoicechannel.h"
 #include "llvoavatarself.h"
 #include "llsidetray.h"
@@ -581,6 +584,9 @@ bool LLAppViewer::init()
 	//
 	LLFastTimer::reset();
 
+	// initialize SSE options
+	LLVector4a::initClass();
+
 	// Need to do this initialization before we do anything else, since anything
 	// that touches files should really go through the lldir API
 	gDirUtilp->initAppDirs("SecondLife");
@@ -921,6 +927,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()
 {
@@ -1030,10 +1039,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();
@@ -1292,6 +1311,11 @@ bool LLAppViewer::cleanup()
 
 	llinfos << "Cleaning Up" << llendflush;
 
+#if LL_MESH_ENABLED
+	// shut down mesh streamer
+	gMeshRepo.shutdown();
+#endif
+
 	// Must clean up texture references before viewer window is destroyed.
 	LLHUDManager::getInstance()->updateEffects();
 	LLHUDObject::updateAll();
@@ -1566,6 +1590,8 @@ bool LLAppViewer::cleanup()
 	sTextureFetch->shutDownTextureCacheThread() ;
 	sTextureFetch->shutDownImageDecodeThread() ;
 
+	LLFilePickerThread::cleanupClass();
+
 	delete sTextureCache;
     sTextureCache = NULL;
 	delete sTextureFetch;
@@ -1713,6 +1739,13 @@ bool LLAppViewer::initThreads()
 		mFastTimerLogThread->start();
 	}
 
+#if LL_MESH_ENABLED
+	// Mesh streaming and caching
+	gMeshRepo.init();
+#endif
+
+	LLFilePickerThread::initClass();
+
 	// *FIX: no error handling here!
 	return true;
 }
@@ -2394,6 +2427,7 @@ bool LLAppViewer::initWindow()
 		gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
 	
 		gPipeline.init();
+		
 		stop_glerror();
 		gViewerWindow->initGLDefaults();
 
@@ -3445,6 +3479,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()
@@ -3465,6 +3503,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
@@ -3515,7 +3555,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));
     
@@ -3530,9 +3570,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;
@@ -3543,6 +3586,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);
@@ -3708,7 +3752,7 @@ void LLAppViewer::idle()
 	//
 
 	{
-		LLFastTimer t(FTM_NETWORK);
+		LLFastTimer t(FTM_VLMANAGER);
 		gVLManager.unpackData();
 	}
 	
@@ -3954,6 +3998,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()
 {
@@ -4004,7 +4053,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)
@@ -4041,24 +4093,39 @@ void LLAppViewer::idleNetwork()
 	LLViewerStats::getInstance()->mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects);
 
 	// Retransmit unacknowledged packets.
-	gXferManager->retransmitUnackedPackets();
-	gAssetStorage->checkForTimeouts();
-	gViewerThrottle.updateDynamicThrottle();
+	{
+		LLFastTimer ftm(FTM_RETRANSMIT);
+		gXferManager->retransmitUnackedPackets();
+	}
+
+	{
+		LLFastTimer ftm(FTM_TIMEOUT_CHECK);
+		gAssetStorage->checkForTimeouts();
+	}
+
+
+	{
+		LLFastTimer ftm(FTM_DYNAMIC_THROTTLE);
+		gViewerThrottle.updateDynamicThrottle();
+	}
 
 	// 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;
 	}
 }
 
diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index 27dcb9f1c7f9bb32a113b65d3d28f5c145679a4e..afb76735ecb2b42e8ab748d7dc13b4213b542c3b 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -42,6 +42,7 @@
 #include "llinventorydefines.h"
 #include "llinventoryobserver.h"
 #include "llinventorypanel.h"
+#include "llfloaterimportcollada.h"
 #include "llpermissionsflags.h"
 #include "llpreviewnotecard.h"
 #include "llpreviewscript.h"
@@ -66,6 +67,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.
@@ -73,6 +75,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,
+			LLInventoryItemFlags::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)
@@ -90,9 +192,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),
@@ -140,6 +243,7 @@ void LLAssetUploadResponder::result(const LLSD& content)
 	lldebugs << "LLAssetUploadResponder::result from capabilities" << llendl;
 
 	std::string state = content["state"];
+
 	if (state == "upload")
 	{
 		uploadUpload(content);
@@ -201,22 +305,37 @@ 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)
+#if LL_MESH_ENABLED
+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)
+	: 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);
 }
 
-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)
+
+//virtual 
+void LLNewAgentInventoryResponder::uploadFailure(const LLSD& content)
 {
+	LLAssetUploadResponder::uploadFailure(content);
+
+	LLImportColladaAssetCache::getInstance()->assetUploaded(mVFileID, content["new_asset"], FALSE);
 }
 
 //virtual 
@@ -230,101 +349,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;
+	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);
 
-		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,
-										LLInventoryItemFlags::II_FLAGS_NONE,
-										creation_date_now);
-		gInventory.updateItem(item);
-		gInventory.notifyObservers();
-		
-		if (mCallback)
-		{
-			// call the callback with the new Asset UUID
-			mCallback(item->getAssetUUID());
-		}
-
-		// 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.
@@ -341,18 +390,44 @@ 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);
 }
+#endif
 
 LLSendTexLayerResponder::LLSendTexLayerResponder(const LLSD& post_data,
 												 const LLUUID& vfile_id,
@@ -405,17 +480,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)
 {
 }
 
@@ -598,3 +675,475 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content)
 		break;
 	}
 }
+
+
+#if LL_MESH_ENABLED
+/////////////////////////////////////////////////////
+// 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)));
+	}
+}
+#endif
+
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
index 2358aeb39d0d70c69fb0a791e44e330490df5ea6..9abaccfde094bc995973d17d761c269bc39d0656 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,21 +61,62 @@ class LLAssetUploadResponder : public LLHTTPClient::Responder
 	std::string mFileName;
 };
 
+#if LL_MESH_ENABLED
+// 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);
+};
 
-	boost::function<void(const LLUUID& uuid)> mCallback;
+// 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();
+
+	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;
 };
+#endif
 
 struct LLBakedUploadData;
 class LLSendTexLayerResponder : public LLAssetUploadResponder
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 38eda5bd2e014d049210e5192003e731044b189e..ca408a309e33d377925f29df8c41033f2d289acb 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -41,6 +41,7 @@
 #include "llcriticaldamp.h"
 #include "llface.h"
 #include "lllightconstants.h"
+#include "llmatrix4a.h"
 #include "llsky.h"
 #include "llsurfacepatch.h"
 #include "llviewercamera.h"
@@ -91,8 +92,12 @@ void LLDrawable::incrementVisible()
 	sCurVisible++;
 	sCurPixelAngle = (F32) gViewerWindow->getWindowHeightRaw()/LLViewerCamera::getInstance()->getView();
 }
+
 void LLDrawable::init()
 {
+	mExtents = (LLVector4a*) ll_aligned_malloc_32(sizeof(LLVector4a)*3);
+	mPositionGroup = mExtents + 2;
+
 	// mXform
 	mParent = NULL;
 	mRenderType = 0;
@@ -121,6 +126,11 @@ void LLDrawable::initClass()
 
 void LLDrawable::destroy()
 {
+	if (gDebugGL)
+	{
+		gPipeline.checkReferences(this);
+	}
+
 	if (isDead())
 	{
 		sNumZombieDrawables--;
@@ -139,6 +149,9 @@ void LLDrawable::destroy()
 	{
 		llinfos << "- Zombie drawables: " << sNumZombieDrawables << llendl;
 	}*/	
+
+	ll_aligned_free_32(mExtents);
+	mExtents = mPositionGroup = NULL;
 }
 
 void LLDrawable::markDead()
@@ -189,20 +202,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()
@@ -523,7 +546,7 @@ F32 LLDrawable::updateXform(BOOL undamped)
 		{
 			// snap to final position
 			dist_squared = 0.0f;
-			if (!isRoot())
+			if (getVOVolume() && !isRoot())
 			{ //child prim snapping to some position, needs a rebuild
 				gPipeline.markRebuild(this, LLDrawable::REBUILD_POSITION, TRUE);
 			}
@@ -704,12 +727,14 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 					LLFace* facep = getFace(i);
 					if (force_update || facep->getPoolType() == LLDrawPool::POOL_ALPHA)
 					{
-						LLVector3 box = (facep->mExtents[1] - facep->mExtents[0]) * 0.25f;
+						LLVector4a box;
+						box.setSub(facep->mExtents[1], facep->mExtents[0]);
+						box.mul(0.25f);
 						LLVector3 v = (facep->mCenterLocal-camera.getOrigin());
 						const LLVector3& at = camera.getAtAxis();
 						for (U32 j = 0; j < 3; j++)
 						{
-							v.mV[j] -= box.mV[j] * at.mV[j];
+							v.mV[j] -= box[j] * at.mV[j];
 						}
 						facep->mDistance = v * camera.getAtAxis();
 					}
@@ -718,7 +743,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 		}
 		else
 		{
-			pos = LLVector3(getPositionGroup());
+			pos = LLVector3(getPositionGroup().getF32());
 		}
 
 		pos -= camera.getOrigin();	
@@ -767,7 +792,7 @@ BOOL LLDrawable::updateGeometry(BOOL priority)
 	return res;
 }
 
-void LLDrawable::shiftPos(const LLVector3 &shift_vector)
+void LLDrawable::shiftPos(const LLVector4a &shift_vector)
 {
 	if (isDead())
 	{
@@ -799,9 +824,9 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector)
 		for (S32 i = 0; i < getNumFaces(); i++)
 		{
 			LLFace *facep = getFace(i);
-			facep->mCenterAgent += shift_vector;
-			facep->mExtents[0] += shift_vector;
-			facep->mExtents[1] += shift_vector;
+			facep->mCenterAgent += LLVector3(shift_vector.getF32());
+			facep->mExtents[0].add(shift_vector);
+			facep->mExtents[1].add(shift_vector);
 			
 			if (!volume && facep->hasGeometry())
 			{
@@ -810,9 +835,9 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector)
 			}
 		}
 		
-		mExtents[0] += shift_vector;
-		mExtents[1] += shift_vector;
-		mPositionGroup += LLVector3d(shift_vector);
+		mExtents[0].add(shift_vector);
+		mExtents[1].add(shift_vector);
+		mPositionGroup->add(shift_vector);
 	}
 	else if (mSpatialBridge)
 	{
@@ -820,9 +845,9 @@ void LLDrawable::shiftPos(const LLVector3 &shift_vector)
 	}
 	else if (isAvatar())
 	{
-		mExtents[0] += shift_vector;
-		mExtents[1] += shift_vector;
-		mPositionGroup += LLVector3d(shift_vector);
+		mExtents[0].add(shift_vector);
+		mExtents[1].add(shift_vector);
+		mPositionGroup->add(shift_vector);
 	}
 	
 	mVObjp->onShift(shift_vector);
@@ -834,21 +859,26 @@ const LLVector3& LLDrawable::getBounds(LLVector3& min, LLVector3& max) const
 	return mXform.getPositionW();
 }
 
-const LLVector3* LLDrawable::getSpatialExtents() const
+const LLVector4a* LLDrawable::getSpatialExtents() const
 {
 	return mExtents;
 }
 
-void LLDrawable::setSpatialExtents(LLVector3 min, LLVector3 max)
+void LLDrawable::setSpatialExtents(const LLVector3& min, const LLVector3& max)
+{ 
+	mExtents[0].load3(min.mV); 
+	mExtents[1].load3(max.mV);
+}
+
+void LLDrawable::setSpatialExtents(const LLVector4a& min, const LLVector4a& max)
 { 
-	LLVector3 size = max - min;
 	mExtents[0] = min; 
-	mExtents[1] = max; 
+	mExtents[1] = max;
 }
 
-void LLDrawable::setPositionGroup(const LLVector3d& pos)
+void LLDrawable::setPositionGroup(const LLVector4a& pos)
 {
-	mPositionGroup.setVec(pos);
+	*mPositionGroup = pos;
 }
 
 void LLDrawable::updateSpatialExtents()
@@ -862,7 +892,7 @@ void LLDrawable::updateSpatialExtents()
 	
 	if (mSpatialBridge.notNull())
 	{
-		mPositionGroup.setVec(0,0,0);
+		mPositionGroup->splat(0.f);
 	}
 }
 
@@ -1073,59 +1103,72 @@ void LLSpatialBridge::updateSpatialExtents()
 		root->rebound();
 	}
 	
-	LLXformMatrix* mat = mDrawable->getXform();
-	
-	LLVector3 offset = root->mBounds[0];
-	LLVector3 size = root->mBounds[1];
+	LLVector4a offset;
+	LLVector4a size = root->mBounds[1];
 		
-	LLVector3 center = LLVector3(0,0,0) * mat->getWorldMatrix();
-	LLQuaternion rotation = LLQuaternion(mat->getWorldMatrix());
+	//VECTORIZE THIS
+	LLMatrix4a mat;
+	mat.loadu(mDrawable->getXform()->getWorldMatrix());
+
+	LLVector4a t;
+	t.splat(0.f);
+
+	LLVector4a center;
+	mat.affineTransform(t, center);
 	
-	offset *= rotation;
-	center += offset;
+	mat.rotate(root->mBounds[0], offset);
+	center.add(offset);
 	
-	LLVector3 v[4];
+	LLVector4a v[4];
+
 	//get 4 corners of bounding box
-	v[0] = (size * rotation);
-	v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation);
-	v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation);
-	v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation);
+	mat.rotate(size,v[0]);
+
+	LLVector4a scale;
+	
+	scale.set(-1.f, -1.f, 1.f);
+	scale.mul(size);
+	mat.rotate(scale, v[1]);
+	
+	scale.set(1.f, -1.f, -1.f);
+	scale.mul(size);
+	mat.rotate(scale, v[2]);
+	
+	scale.set(-1.f, 1.f, -1.f);
+	scale.mul(size);
+	mat.rotate(scale, v[3]);
 
-	LLVector3& newMin = mExtents[0];
-	LLVector3& newMax = mExtents[1];
+	
+	LLVector4a& newMin = mExtents[0];
+	LLVector4a& newMax = mExtents[1];
 	
 	newMin = newMax = center;
 	
 	for (U32 i = 0; i < 4; i++)
 	{
-		for (U32 j = 0; j < 3; j++)
-		{
-			F32 delta = fabsf(v[i].mV[j]);
-			F32 min = center.mV[j] - delta;
-			F32 max = center.mV[j] + delta;
-			
-			if (min < newMin.mV[j])
-			{
-				newMin.mV[j] = min;
-			}
-			
-			if (max > newMax.mV[j])
-			{
-				newMax.mV[j] = max;
-			}
-		}
-	}
+		LLVector4a delta;
+		delta.setAbs(v[i]);
+		LLVector4a min;
+		min.setSub(center, delta);
+		LLVector4a max;
+		max.setAdd(center, delta);
 
-	LLVector3 diagonal = newMax - newMin;
-	mRadius = diagonal.magVec() * 0.5f;
+		newMin.setMin(min);
+		newMax.setMax(max);
+	}
+	
+	LLVector4a diagonal;
+	diagonal.setSub(newMax, newMin);
+	mRadius = diagonal.length3() * 0.5f;
 	
-	mPositionGroup.setVec((newMin + newMax) * 0.5f);
+	mPositionGroup->setAdd(newMin,newMax);
+	mPositionGroup->mul(0.5f);
 	updateBinRadius();
 }
 
 void LLSpatialBridge::updateBinRadius()
 {
-	mBinRadius = llmin((F32) mOctree->getSize().mdV[0]*0.5f, 256.f);
+	mBinRadius = llmin( mOctree->getSize()[0]*0.5f, 256.f);
 }
 
 LLCamera LLSpatialBridge::transformCamera(LLCamera& camera)
@@ -1266,8 +1309,12 @@ void LLSpatialBridge::setVisible(LLCamera& camera_in, std::vector<LLDrawable*>*
 	LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 	group->rebound();
 	
-	LLVector3 center = (mExtents[0] + mExtents[1]) * 0.5f;
-	LLVector3 size = (mExtents[1]-mExtents[0]) * 0.5f;
+	LLVector4a center;
+	center.setAdd(mExtents[0], mExtents[1]);
+	center.mul(0.5f);
+	LLVector4a size;
+	size.setSub(mExtents[1], mExtents[0]);
+	size.mul(0.5f);
 
 	if ((LLPipeline::sShadowRender && camera_in.AABBInFrustum(center, size)) ||
 		LLPipeline::sImpostorRender ||
@@ -1379,11 +1426,11 @@ BOOL LLSpatialBridge::updateMove()
 	return TRUE;
 }
 
-void LLSpatialBridge::shiftPos(const LLVector3& vec)
+void LLSpatialBridge::shiftPos(const LLVector4a& vec)
 {
-	mExtents[0] += vec;
-	mExtents[1] += vec;
-	mPositionGroup += LLVector3d(vec);
+	mExtents[0].add(vec);
+	mExtents[1].add(vec);
+	mPositionGroup->add(vec);
 }
 
 void LLSpatialBridge::cleanupReferences()
@@ -1501,7 +1548,7 @@ F32 LLHUDBridge::calcPixelArea(LLSpatialGroup* group, LLCamera& camera)
 }
 
 
-void LLHUDBridge::shiftPos(const LLVector3& vec)
+void LLHUDBridge::shiftPos(const LLVector4a& vec)
 {
 	//don't shift hud bridges on region crossing
 }
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 651dabff9eaa3805f9ff3deeed41b2c0fab79f7a..811ff1801b849741e923262753197ac84b3acb33 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -41,6 +41,7 @@
 #include "v4math.h"
 #include "m4math.h"
 #include "v4coloru.h"
+#include "llvector4a.h"
 #include "llquaternion.h"
 #include "xform.h"
 #include "llmemtype.h"
@@ -66,6 +67,17 @@ const U32 SILHOUETTE_HIGHLIGHT = 0;
 class LLDrawable : public LLRefCount
 {
 public:
+	LLDrawable(const LLDrawable& rhs)
+	{
+		*this = rhs;
+	}
+
+	const LLDrawable& operator=(const LLDrawable& rhs)
+	{
+		llerrs << "Illegal operation!" << llendl;
+		return *this;
+	}
+
 	static void initClass();
 
 	LLDrawable()				{ init(); }
@@ -94,14 +106,14 @@ class LLDrawable : public LLRefCount
 	const LLVector3&	  getPosition() const			{ return mXform.getPosition(); }
 	const LLVector3&      getWorldPosition() const		{ return mXform.getPositionW(); }
 	const LLVector3		  getPositionAgent() const;
-	const LLVector3d&	  getPositionGroup() const		{ return mPositionGroup; }
+	const LLVector4a&	  getPositionGroup() const		{ return *mPositionGroup; }
 	const LLVector3&	  getScale() const				{ return mCurrentScale; }
 	void				  setScale(const LLVector3& scale) { mCurrentScale = scale; }
 	const LLQuaternion&   getWorldRotation() const		{ return mXform.getWorldRotation(); }
 	const LLQuaternion&   getRotation() const			{ return mXform.getRotation(); }
 	F32			          getIntensity() const			{ return llmin(mXform.getScale().mV[0], 4.f); }
 	S32					  getLOD() const				{ return mVObjp ? mVObjp->getLOD() : 1; }
-	F64					  getBinRadius() const			{ return mBinRadius; }
+	F32					  getBinRadius() const			{ return mBinRadius; }
 	void  getMinMax(LLVector3& min,LLVector3& max) const { mXform.getMinMax(min,max); }
 	LLXformMatrix*		getXform() { return &mXform; }
 
@@ -155,7 +167,7 @@ class LLDrawable : public LLRefCount
 		
 	void updateSpecialHoverCursor(BOOL enabled);
 
-	virtual void shiftPos(const LLVector3 &shift_vector);
+	virtual void shiftPos(const LLVector4a &shift_vector);
 
 	S32 getGeneration() const					{ return mGeneration; }
 
@@ -173,11 +185,12 @@ class LLDrawable : public LLRefCount
 	const LLVector3& getBounds(LLVector3& min, LLVector3& max) const;
 	virtual void updateSpatialExtents();
 	virtual void updateBinRadius();
-	const LLVector3* getSpatialExtents() const;
-	void setSpatialExtents(LLVector3 min, LLVector3 max);
-	void setPositionGroup(const LLVector3d& pos);
-	void setPositionGroup(const LLVector3& pos) { setPositionGroup(LLVector3d(pos)); }
+	const LLVector4a* getSpatialExtents() const;
+	void setSpatialExtents(const LLVector3& min, const LLVector3& max);
+	void setSpatialExtents(const LLVector4a& min, const LLVector4a& max);
 
+	void setPositionGroup(const LLVector4a& pos);
+	
 	void setRenderType(S32 type) 				{ mRenderType = type; }
 	BOOL isRenderType(S32 type) 				{ return mRenderType == type; }
 	S32  getRenderType()						{ return mRenderType; }
@@ -288,6 +301,9 @@ class LLDrawable : public LLRefCount
 private:
 	typedef std::vector<LLFace*> face_list_t;
 	
+	LLVector4a*		mExtents;
+	LLVector4a*		mPositionGroup;
+		
 	U32				mState;
 	S32				mRenderType;
 	LLPointer<LLViewerObject> mVObjp;
@@ -297,9 +313,7 @@ class LLDrawable : public LLRefCount
 	
 	mutable U32		mVisible;
 	F32				mRadius;
-	LLVector3		mExtents[2];
-	LLVector3d		mPositionGroup;
-	F64				mBinRadius;
+	F32				mBinRadius;
 	S32				mGeneration;
 	
 	LLVector3		mCurrentScale;
@@ -313,8 +327,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 e3e66fa00db00dcf6ad23180dc154c3ce757fc36..a99b80d6185b2f817254502c2e66a61a3c15718c 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -248,11 +248,6 @@ void LLFacePool::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures
 {
 }
 
-BOOL LLFacePool::moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data)
-{
-	return TRUE;
-}
-
 // static
 S32 LLFacePool::drawLoop(face_array_t& face_list)
 {
@@ -474,6 +469,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/lldrawpool.h b/indra/newview/lldrawpool.h
index 67870c10e93112486dfac9a3d54db09611599ab7..ec870f59c6db51ec09be99a847788468a891beda 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -133,6 +133,7 @@ class LLRenderPass : public LLDrawPool
 		PASS_FULLBRIGHT_SHINY,
 		PASS_SHINY,
 		PASS_BUMP,
+		PASS_POST_BUMP,
 		PASS_GLOW,
 		PASS_ALPHA,
 		PASS_ALPHA_MASK,
@@ -187,8 +188,6 @@ class LLFacePool : public LLDrawPool
 	virtual void resetDrawOrders();
 	void resetAll();
 
-	BOOL moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data = FALSE);
-
 	void destroy();
 
 	void buildEdges();
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 875c9ac6a9d597ca84c3e78891bbe43df646a6ea..def463cb416c9b2eae777f151c342d55df123c2f 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;
 
-	if (LLPipeline::sFastAlpha && !deferred_render)
+	gGL.setColorMask(true, true);
+
+	if (LLPipeline::sAutoMaskAlphaNonDeferred && !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 2d0859650a86f39e9812133a5fb9201534ff73b1..63ca17d62d9f150bbe15458b723e8846f82b4739 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -39,13 +39,17 @@
 #include "m3math.h"
 
 #include "lldrawable.h"
+#include "lldrawpoolbump.h"
 #include "llface.h"
+#include "llmeshrepository.h"
 #include "llsky.h"
 #include "llviewercamera.h"
 #include "llviewerregion.h"
 #include "noise.h"
 #include "pipeline.h"
 #include "llviewershadermgr.h"
+#include "llvovolume.h"
+#include "llvolume.h"
 #include "llappviewer.h"
 #include "llrendersphere.h"
 #include "llviewerpartsim.h"
@@ -53,10 +57,15 @@
 static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
 static U32 sBufferUsage = GL_STREAM_DRAW_ARB;
 static U32 sShaderLevel = 0;
-static LLGLSLShader* sVertexProgram = NULL;
 
+
+LLGLSLShader* LLDrawPoolAvatar::sVertexProgram = NULL;
 BOOL	LLDrawPoolAvatar::sSkipOpaque = FALSE;
 BOOL	LLDrawPoolAvatar::sSkipTransparent = FALSE;
+S32 LLDrawPoolAvatar::sDiffuseChannel = 0;
+
+
+static bool is_deferred_render = false;
 
 extern BOOL gUseGLPick;
 
@@ -92,7 +101,22 @@ BOOL gAvatarEmbossBumpMap = FALSE;
 static BOOL sRenderingSkinned = FALSE;
 S32 normal_channel = -1;
 S32 specular_channel = -1;
-S32 diffuse_channel = -1;
+S32 cube_channel = -1;
+
+#if LL_MESH_ENABLED
+static const U32 rigged_data_mask[] = {
+	LLDrawPoolAvatar::RIGGED_SIMPLE_MASK,
+	LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK,
+	LLDrawPoolAvatar::RIGGED_SHINY_MASK,
+	LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY_MASK,
+	LLDrawPoolAvatar::RIGGED_GLOW_MASK,
+	LLDrawPoolAvatar::RIGGED_ALPHA_MASK,
+	LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA_MASK,
+	LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP_MASK,						 
+	LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE_MASK,
+};
+#endif
+
 
 static LLFastTimer::DeclareTimer FTM_SHADOW_AVATAR("Avatar Shadow");
 
@@ -123,7 +147,7 @@ void LLDrawPoolAvatar::prerender()
 	
 	if (sShaderLevel > 0)
 	{
-		sBufferUsage = GL_STATIC_DRAW_ARB;
+		sBufferUsage = GL_DYNAMIC_DRAW_ARB;
 	}
 	else
 	{
@@ -148,19 +172,17 @@ LLMatrix4& LLDrawPoolAvatar::getModelView()
 //-----------------------------------------------------------------------------
 
 
-S32 LLDrawPoolAvatar::getNumDeferredPasses()
-{
-	return getNumPasses();
-}
 
 void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_CHARACTERS);
 	
+	sSkipTransparent = TRUE;
+	is_deferred_render = true;
+	
 	if (LLPipeline::sImpostorRender)
-	{
-		beginDeferredSkinned();
-		return;
+	{ //impostor pass does not have rigid or impostor rendering
+		pass += 2;
 	}
 
 	switch (pass)
@@ -174,6 +196,14 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 	case 2:
 		beginDeferredSkinned();
 		break;
+#if LL_MESH_ENABLED
+	case 3:
+		beginDeferredRiggedSimple();
+		break;
+	case 4:
+		beginDeferredRiggedBump();
+		break;
+#endif
 	}
 }
 
@@ -181,10 +211,12 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_CHARACTERS);
 
+	sSkipTransparent = FALSE;
+	is_deferred_render = false;
+
 	if (LLPipeline::sImpostorRender)
 	{
-		endDeferredSkinned();
-		return;
+		pass += 2;
 	}
 
 	switch (pass)
@@ -198,6 +230,14 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 	case 2:
 		endDeferredSkinned();
 		break;
+#if LL_MESH_ENABLED
+	case 3:
+		endDeferredRiggedSimple();
+		break;
+	case 4:
+		endDeferredRiggedBump();
+		break;
+#endif
 	}
 }
 
@@ -208,10 +248,41 @@ void LLDrawPoolAvatar::renderDeferred(S32 pass)
 
 S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
 {
+#if LL_MESH_ENABLED
+	return 6;
+#else
 	return 1;
+#endif
 }
 
 void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
+{
+	switch (pass)
+	{
+	case 0:
+		beginPostDeferredAlpha();
+		break;
+#if LL_MESH_ENABLED
+	case 1:
+		beginRiggedFullbright();
+		break;
+	case 2:
+		beginRiggedFullbrightShiny();
+		break;
+	case 3:
+		beginDeferredRiggedAlpha();
+		break;
+	case 4:
+		beginRiggedFullbrightAlpha();
+		break;
+	case 5:
+		beginRiggedGlow();
+		break;
+#endif
+	}
+}
+
+void LLDrawPoolAvatar::beginPostDeferredAlpha()
 {
 	sSkipOpaque = TRUE;
 	sShaderLevel = mVertexShaderLevel;
@@ -221,10 +292,58 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 
 	gPipeline.bindDeferredShader(*sVertexProgram);
 	
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
 }
 
+#if LL_MESH_ENABLED
+void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
+{
+	sVertexProgram = &gDeferredSkinnedAlphaProgram;
+	gPipeline.bindDeferredShader(*sVertexProgram);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+	gPipeline.enableLightsDynamic();
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedAlpha()
+{
+	LLVertexBuffer::unbind();
+	gPipeline.unbindDeferredShader(*sVertexProgram);
+	sDiffuseChannel = 0;
+	LLVertexBuffer::sWeight4Loc = -1;
+	sVertexProgram = NULL;
+}
+#endif
+
 void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
+{
+	switch (pass)
+	{
+	case 0:
+		endPostDeferredAlpha();
+		break;
+#if LL_MESH_ENABLED
+	case 1:
+		endRiggedFullbright();
+		break;
+	case 2:
+		endRiggedFullbrightShiny();
+		break;
+	case 3:
+		endDeferredRiggedAlpha();
+		break;
+	case 4:
+		endRiggedFullbrightAlpha();
+		break;
+	case 5:
+		endRiggedGlow();
+		break;
+#endif
+	}
+}
+
+void LLDrawPoolAvatar::endPostDeferredAlpha()
 {
 	// if we're in software-blending, remember to set the fence _after_ we draw so we wait till this rendering is done
 	sRenderingSkinned = FALSE;
@@ -232,55 +351,85 @@ void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 	disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
 	
 	gPipeline.unbindDeferredShader(*sVertexProgram);
-
+	sDiffuseChannel = 0;
 	sShaderLevel = mVertexShaderLevel;
 }
 
 void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
 {
-	render(2); //pass 2 = skinned
+	const S32 actual_pass[] =
+	{ //map post deferred pass numbers to what render() expects
+		2, //skinned
+		4, // rigged fullbright
+		6, //rigged fullbright shiny
+		7, //rigged alpha
+		8, //rigged fullbright alpha
+		9, //rigged glow
+	};
+
+	render(actual_pass[pass]);
 }
 
 
 S32 LLDrawPoolAvatar::getNumShadowPasses()
 {
+#if LL_MESH_ENABLED
+	return 2;
+#else
 	return 1;
+#endif
 }
 
 void LLDrawPoolAvatar::beginShadowPass(S32 pass)
 {
 	LLFastTimer t(FTM_SHADOW_AVATAR);
-	
-	sVertexProgram = &gDeferredAvatarShadowProgram;
-	if (sShaderLevel > 0)
+
+	if (pass == 0)
 	{
-		gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
-	}
-	gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f);
-	
-	glColor4f(1,1,1,1);
+		sVertexProgram = &gDeferredAvatarShadowProgram;
+		if (sShaderLevel > 0)
+		{
+			gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
+		}
+		gGL.setAlphaRejectSettings(LLRender::CF_GREATER_EQUAL, 0.2f);
+		
+		glColor4f(1,1,1,1);
 
-	if ((sShaderLevel > 0))  // for hardware blending
+		if ((sShaderLevel > 0))  // for hardware blending
+		{
+			sRenderingSkinned = TRUE;
+			sVertexProgram->bind();
+			enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+		}
+	}
+	else
 	{
-		sRenderingSkinned = TRUE;
+		sVertexProgram = &gDeferredAttachmentShadowProgram;
+		sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 		sVertexProgram->bind();
-		enable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+		LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
 	}
-
 }
 
 void LLDrawPoolAvatar::endShadowPass(S32 pass)
 {
 	LLFastTimer t(FTM_SHADOW_AVATAR);
-
-	if (sShaderLevel > 0)
+	if (pass == 0)
 	{
-		sRenderingSkinned = FALSE;
+		if (sShaderLevel > 0)
+		{
+			sRenderingSkinned = FALSE;
+			sVertexProgram->unbind();
+			disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+		}
+	}
+	else
+	{
+		LLVertexBuffer::unbind();
 		sVertexProgram->unbind();
-		disable_vertex_weighting(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT]);
+		LLVertexBuffer::sWeight4Loc = -1;
+		sVertexProgram = NULL;
 	}
-
-	gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 }
 
 void LLDrawPoolAvatar::renderShadow(S32 pass)
@@ -310,15 +459,69 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
 		return;
 	}
 	
-	avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
+	if (pass == 0)
+	{
+		if (sShaderLevel > 0)
+		{
+			gAvatarMatrixParam = sVertexProgram->mUniform[LLViewerShaderMgr::AVATAR_MATRIX];
+		}
 
+		avatarp->renderSkinned(AVATAR_RENDER_PASS_SINGLE);
+	}
+#if LL_MESH_ENABLED
+	else
+	{
+		renderRigged(avatarp, RIGGED_SIMPLE);
+		renderRigged(avatarp, RIGGED_ALPHA);
+		renderRigged(avatarp, RIGGED_FULLBRIGHT);
+		renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY);
+		renderRigged(avatarp, RIGGED_SHINY);
+		renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA);
+	}
+#endif
 }
 
 S32 LLDrawPoolAvatar::getNumPasses()
 {
-	return LLPipeline::sImpostorRender ? 1 : 3;
+#if LL_MESH_ENABLED
+	if (LLPipeline::sImpostorRender)
+	{
+		return 8;
+	}
+	else if (getVertexShaderLevel() > 0)
+	{
+		return 10;
+	}
+	else
+	{
+		return 3;
+	}
+#else
+	if (LLPipeline::sImpostorRender)
+	{
+		return 1;
+	}
+	else 
+	{
+		return 3;
+	}
+#endif
 }
 
+
+S32 LLDrawPoolAvatar::getNumDeferredPasses()
+{
+	if (LLPipeline::sImpostorRender)
+	{
+		return 3;
+	}
+	else
+	{
+		return 5;
+	}
+}
+
+
 void LLDrawPoolAvatar::render(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_CHARACTERS);
@@ -338,15 +541,14 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 	LLVertexBuffer::unbind();
 
 	if (LLPipeline::sImpostorRender)
-	{
-		beginSkinned();
-		return;
+	{ //impostor render does not have impostors or rigid rendering
+		pass += 2;
 	}
 
 	switch (pass)
 	{
 	case 0:
-		beginFootShadow();
+		beginImpostor();
 		break;
 	case 1:
 		beginRigid();
@@ -354,6 +556,29 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 	case 2:
 		beginSkinned();
 		break;
+#if LL_MESH_ENABLED
+	case 3:
+		beginRiggedSimple();
+		break;
+	case 4:
+		beginRiggedFullbright();
+		break;
+	case 5:
+		beginRiggedShinySimple();
+		break;
+	case 6:
+		beginRiggedFullbrightShiny();
+		break;
+	case 7:
+		beginRiggedAlpha();
+		break;
+	case 8:
+		beginRiggedFullbrightAlpha();
+		break;
+	case 9:
+		beginRiggedGlow();
+		break;
+#endif
 	}
 }
 
@@ -363,24 +588,47 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
 
 	if (LLPipeline::sImpostorRender)
 	{
-		endSkinned();
-		return;
+		pass += 2;		
 	}
 
 	switch (pass)
 	{
 	case 0:
-		endFootShadow();
+		endImpostor();
 		break;
 	case 1:
 		endRigid();
 		break;
 	case 2:
 		endSkinned();
+		break;
+#if LL_MESH_ENABLED
+	case 3:
+		endRiggedSimple();
+		break;
+	case 4:
+		endRiggedFullbright();
+		break;
+	case 5:
+		endRiggedShinySimple();
+		break;
+	case 6:
+		endRiggedFullbrightShiny();
+		break;
+	case 7:
+		endRiggedAlpha();
+		break;
+	case 8:
+		endRiggedFullbrightAlpha();
+		break;
+	case 9:
+		endRiggedGlow();
+		break;
+#endif
 	}
 }
 
-void LLDrawPoolAvatar::beginFootShadow()
+void LLDrawPoolAvatar::beginImpostor()
 {
 	if (!LLPipeline::sReflectionRender)
 	{
@@ -389,10 +637,10 @@ void LLDrawPoolAvatar::beginFootShadow()
 	}
 
 	gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
-	diffuse_channel = 0;
+	sDiffuseChannel = 0;
 }
 
-void LLDrawPoolAvatar::endFootShadow()
+void LLDrawPoolAvatar::endImpostor()
 {
 	gPipeline.enableLightsDynamic();
 }
@@ -440,9 +688,9 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
 
 	sVertexProgram = &gDeferredImpostorProgram;
 
-	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
 	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
-	diffuse_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 
 	sVertexProgram->bind();
 }
@@ -562,9 +810,163 @@ void LLDrawPoolAvatar::endSkinned()
 	gGL.getTexUnit(0)->activate();
 }
 
+#if LL_MESH_ENABLED
+void LLDrawPoolAvatar::beginRiggedSimple()
+{
+	sVertexProgram = &gSkinnedObjectSimpleProgram;
+	sDiffuseChannel = 0;
+	gSkinnedObjectSimpleProgram.bind();
+	LLVertexBuffer::sWeight4Loc = gSkinnedObjectSimpleProgram.getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endRiggedSimple()
+{
+	sVertexProgram = NULL;
+	LLVertexBuffer::unbind();
+	gSkinnedObjectSimpleProgram.unbind();
+	LLVertexBuffer::sWeight4Loc = -1;
+}
+
+void LLDrawPoolAvatar::beginRiggedAlpha()
+{
+	sVertexProgram = &gSkinnedObjectSimpleProgram;
+	sDiffuseChannel = 0;
+	sVertexProgram->bind();
+	LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endRiggedAlpha()
+{
+	sVertexProgram->unbind();
+	sVertexProgram = NULL;
+	LLVertexBuffer::unbind();
+	LLVertexBuffer::sWeight4Loc = -1;
+}
+
+
+void LLDrawPoolAvatar::beginRiggedFullbrightAlpha()
+{
+	sVertexProgram = &gSkinnedObjectFullbrightProgram;
+	sDiffuseChannel = 0;
+	sVertexProgram->bind();
+	LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endRiggedFullbrightAlpha()
+{
+	sVertexProgram->unbind();
+	sVertexProgram = NULL;
+	LLVertexBuffer::unbind();
+	LLVertexBuffer::sWeight4Loc = -1;
+}
+
+void LLDrawPoolAvatar::beginRiggedGlow()
+{
+	sVertexProgram = &gSkinnedObjectFullbrightProgram;
+	sDiffuseChannel = 0;
+	sVertexProgram->bind();
+	LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endRiggedGlow()
+{
+	sVertexProgram->unbind();
+	sVertexProgram = NULL;
+	LLVertexBuffer::unbind();
+	LLVertexBuffer::sWeight4Loc = -1;
+}
+
+void LLDrawPoolAvatar::beginRiggedFullbright()
+{
+	sVertexProgram = &gSkinnedObjectFullbrightProgram;
+	sDiffuseChannel = 0;
+	gSkinnedObjectFullbrightProgram.bind();
+	LLVertexBuffer::sWeight4Loc = gSkinnedObjectFullbrightProgram.getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endRiggedFullbright()
+{
+	sVertexProgram = NULL;
+	LLVertexBuffer::unbind();
+	gSkinnedObjectFullbrightProgram.unbind();
+	LLVertexBuffer::sWeight4Loc = -1;
+}
+
+void LLDrawPoolAvatar::beginRiggedShinySimple()
+{
+	sVertexProgram = &gSkinnedObjectShinySimpleProgram;
+	sVertexProgram->bind();
+	LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
+	LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endRiggedShinySimple()
+{
+	LLVertexBuffer::unbind();
+	LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
+	sVertexProgram->unbind();
+	sVertexProgram = NULL;
+	LLVertexBuffer::sWeight4Loc = -1;
+}
+
+void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
+{
+	sVertexProgram = &gSkinnedObjectFullbrightShinyProgram;
+	sVertexProgram->bind();
+	LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
+	LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endRiggedFullbrightShiny()
+{
+	LLVertexBuffer::unbind();
+	LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
+	sVertexProgram->unbind();
+	sVertexProgram = NULL;
+	LLVertexBuffer::sWeight4Loc = -1;
+}
+
+
+void LLDrawPoolAvatar::beginDeferredRiggedSimple()
+{
+	sVertexProgram = &gDeferredSkinnedDiffuseProgram;
+	sDiffuseChannel = 0;
+	sVertexProgram->bind();
+	LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedSimple()
+{
+	LLVertexBuffer::unbind();
+	sVertexProgram->unbind();
+	LLVertexBuffer::sWeight4Loc = -1;
+	sVertexProgram = NULL;
+}
+
+void LLDrawPoolAvatar::beginDeferredRiggedBump()
+{
+	sVertexProgram = &gDeferredSkinnedBumpProgram;
+	sVertexProgram->bind();
+	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedBump()
+{
+	LLVertexBuffer::unbind();
+	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	sVertexProgram->unbind();
+	LLVertexBuffer::sWeight4Loc = -1;
+	normal_channel = -1;
+	sDiffuseChannel = 0;
+	sVertexProgram = NULL;
+}
+#endif
+
 void LLDrawPoolAvatar::beginDeferredSkinned()
 {
-	sSkipTransparent = TRUE;
 	sShaderLevel = mVertexShaderLevel;
 	sVertexProgram = &gDeferredAvatarProgram;
 
@@ -579,7 +981,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]);
@@ -691,11 +1092,7 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 					avatarp->mImpostor.bindTexture(1, specular_channel);
 				}
 			}
-			avatarp->renderImpostor(LLColor4U(255,255,255,255), diffuse_channel);
-		}
-		else if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS) && !LLPipeline::sRenderDeferred)
-		{
-			avatarp->renderFootShadows();	
+			avatarp->renderImpostor(LLColor4U(255,255,255,255), sDiffuseChannel);
 		}
 		return;
 	}
@@ -711,6 +1108,90 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		avatarp->renderRigid();
 		return;
 	}
+
+#if LL_MESH_ENABLED
+	if (pass == 3)
+	{
+		if (is_deferred_render)
+		{
+			renderDeferredRiggedSimple(avatarp);
+		}
+		else
+		{
+			renderRiggedSimple(avatarp);
+		}
+		return;
+	}
+
+	if (pass == 4)
+	{
+		if (is_deferred_render)
+		{
+			renderDeferredRiggedBump(avatarp);
+		}
+		else
+		{
+			renderRiggedFullbright(avatarp);
+		}
+
+		return;
+	}
+
+	if (pass == 5)
+	{
+		renderRiggedShinySimple(avatarp);
+		return;
+	}
+
+	if (pass == 6)
+	{
+		renderRiggedFullbrightShiny(avatarp);
+		return;
+	}
+
+	if (pass >= 7 && pass < 9)
+	{
+		LLGLEnable blend(GL_BLEND);
+
+		gGL.setColorMask(true, true);
+		gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
+					  LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
+					  LLRender::BF_ZERO,
+					  LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
+
+		
+		if (pass == 7)
+		{
+			renderRiggedAlpha(avatarp);
+			return;
+		}
+
+		if (pass == 8)
+		{
+			renderRiggedFullbrightAlpha(avatarp);
+			return;
+		}
+	}
+
+	if (pass == 9)
+	{
+		LLGLEnable blend(GL_BLEND);
+		LLGLDisable test(GL_ALPHA_TEST);
+		gGL.flush();
+
+		LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
+		glPolygonOffset(-1.0f, -1.0f);
+		gGL.setSceneBlendType(LLRender::BT_ADD);
+
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+		gGL.setColorMask(false, true);
+
+		renderRiggedGlow(avatarp);
+		gGL.setColorMask(true, false);
+		gGL.setSceneBlendType(LLRender::BT_ALPHA);
+		return;
+	}
+#endif
 	
 	if (sShaderLevel > 0)
 	{
@@ -748,13 +1229,205 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 	}
 }
 
+#if LL_MESH_ENABLED
+void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
+{
+	U32 data_mask = 0;
+	for (U32 i = 0; i < face->mRiggedIndex.size(); ++i)
+	{
+		if (face->mRiggedIndex[i] > -1)
+		{
+			data_mask |= rigged_data_mask[i];
+		}
+	}
+
+	LLVertexBuffer* buff = face->mVertexBuffer;
+
+	if (!buff || 
+		buff->getTypeMask() != data_mask ||
+		buff->getRequestedVerts() != vol_face.mNumVertices)
+	{
+		face->setGeomIndex(0);
+		face->setIndicesIndex(0);
+		face->setSize(vol_face.mNumVertices, vol_face.mNumIndices);
+
+		face->mVertexBuffer = new LLVertexBuffer(data_mask, 0);
+		face->mVertexBuffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true);
+
+		U16 offset = 0;
+		
+		LLMatrix4 mat_vert = skin->mBindShapeMatrix;
+		glh::matrix4f m((F32*) mat_vert.mMatrix);
+		m = m.inverse().transpose();
+		
+		F32 mat3[] = 
+		{ m.m[0], m.m[1], m.m[2],
+		  m.m[4], m.m[5], m.m[6],
+		  m.m[8], m.m[9], m.m[10] };
+
+		LLMatrix3 mat_normal(mat3);				
+
+		face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
+		buff = face->mVertexBuffer;
+	}
+}
+
+void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
+{
+	for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
+	{
+		LLFace* face = mRiggedFace[type][i];
+		LLDrawable* drawable = face->getDrawable();
+		if (!drawable)
+		{
+			continue;
+		}
+
+		LLVOVolume* vobj = drawable->getVOVolume();
+
+		if (!vobj)
+		{
+			continue;
+		}
+
+		LLVolume* volume = vobj->getVolume();
+		S32 te = face->getTEOffset();
+
+		if (!volume || volume->getNumVolumeFaces() <= te)
+		{
+			continue;
+		}
+
+		LLUUID mesh_id = volume->getParams().getSculptID();
+		if (mesh_id.isNull())
+		{
+			continue;
+		}
+
+		const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id);
+		if (!skin)
+		{
+			continue;
+		}
+
+		const LLVolumeFace& vol_face = volume->getVolumeFace(te);
+		updateRiggedFaceVertexBuffer(face, skin, volume, vol_face);
+		
+		U32 data_mask = rigged_data_mask[type];
+
+		LLVertexBuffer* buff = face->mVertexBuffer;
+
+		if (buff)
+		{
+			LLMatrix4 mat[64];
+
+			for (U32 i = 0; i < skin->mJointNames.size(); ++i)
+			{
+				LLJoint* joint = avatar->getJoint(skin->mJointNames[i]);
+				if (joint)
+				{
+					mat[i] = skin->mInvBindMatrix[i];
+					mat[i] *= joint->getWorldMatrix();
+				}
+			}
+			
+			LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette", 
+				skin->mJointNames.size(),
+				FALSE,
+				(GLfloat*) mat[0].mMatrix);
+			LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette[0]", 
+				skin->mJointNames.size(),
+				FALSE,
+				(GLfloat*) mat[0].mMatrix);
+
+			buff->setBuffer(data_mask);
+
+			U16 start = face->getGeomStart();
+			U16 end = start + face->getGeomCount()-1;
+			S32 offset = face->getIndicesStart();
+			U32 count = face->getIndicesCount();
+
+			if (glow)
+			{
+				glColor4f(0,0,0,face->getTextureEntry()->getGlow());
+			}
+
+			gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture());
+			if (normal_channel > -1)
+			{
+				LLDrawPoolBump::bindBumpMap(face, normal_channel);
+			}
+
+			if (face->mTextureMatrix)
+			{
+				glMatrixMode(GL_TEXTURE);
+				glLoadMatrixf((F32*) face->mTextureMatrix->mMatrix);
+				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
+				glLoadIdentity();
+				glMatrixMode(GL_MODELVIEW);
+			}
+			else
+			{
+				buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);		
+			}
+		}
+	}
+}
+
+void LLDrawPoolAvatar::renderDeferredRiggedSimple(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_DEFERRED_SIMPLE);
+}
+
+void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_DEFERRED_BUMP);
+}
+
+void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_SIMPLE);
+}
+
+void LLDrawPoolAvatar::renderRiggedFullbright(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_FULLBRIGHT);
+}
+
+	
+void LLDrawPoolAvatar::renderRiggedShinySimple(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_SHINY);
+}
+
+void LLDrawPoolAvatar::renderRiggedFullbrightShiny(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_FULLBRIGHT_SHINY);
+}
+
+void LLDrawPoolAvatar::renderRiggedAlpha(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_ALPHA);
+}
+
+void LLDrawPoolAvatar::renderRiggedFullbrightAlpha(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_FULLBRIGHT_ALPHA);
+}
+
+void LLDrawPoolAvatar::renderRiggedGlow(LLVOAvatar* avatar)
+{
+	renderRigged(avatar, RIGGED_GLOW, true);
+}
+#endif
+
+
+
 //-----------------------------------------------------------------------------
 // renderForSelect()
 //-----------------------------------------------------------------------------
 void LLDrawPoolAvatar::renderForSelect()
 {
-
-
 	if (mDrawFace.empty())
 	{
 		return;
@@ -848,11 +1521,66 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
 	return LLColor3(0.f, 1.f, 0.f);
 }
 
+#if LL_MESH_ENABLED
+void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
+{
+	if (facep->mRiggedIndex.empty())
+	{
+		facep->mRiggedIndex.resize(LLDrawPoolAvatar::NUM_RIGGED_PASSES);
+		for (U32 i = 0; i < facep->mRiggedIndex.size(); ++i)
+		{
+			facep->mRiggedIndex[i] = -1;
+		}
+	}
+
+	if (type >= NUM_RIGGED_PASSES)
+	{
+		llerrs << "Invalid rigged face type." << llendl;
+	}
+
+	if (facep->mRiggedIndex[type] != -1)
+	{
+		llerrs << "Tried to add a rigged face that's referenced elsewhere." << llendl;
+	}	
+
+	
+	facep->mRiggedIndex[type] = mRiggedFace[type].size();
+	facep->mDrawPoolp = this;
+	mRiggedFace[type].push_back(facep);
+}
+
+void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep)
+{
+	
+	facep->mDrawPoolp = NULL;
+
+	for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
+	{
+		S32 index = facep->mRiggedIndex[i];
+		
+		if (index > -1)
+		{
+			if (mRiggedFace[i].size() > index && mRiggedFace[i][index] == facep)
+			{
+				facep->mRiggedIndex[i] = -1;
+				mRiggedFace[i].erase(mRiggedFace[i].begin()+index);
+				for (U32 j = index; j < mRiggedFace[i].size(); ++j)
+				{ //bump indexes down for faces referenced after erased face
+					mRiggedFace[i][j]->mRiggedIndex[i] = j;
+				}
+			}
+			else
+			{
+				llerrs << "Face reference data corrupt for rigged type " << i << llendl;
+			}
+		}
+	}
+}
+#endif
+
 LLVertexBufferAvatar::LLVertexBufferAvatar()
 : LLVertexBuffer(sDataMask, 
-	LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0 ?	
-	GL_DYNAMIC_DRAW_ARB : 
-	GL_STREAM_DRAW_ARB)
+	GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
 {
 
 }
@@ -864,20 +1592,23 @@ void LLVertexBufferAvatar::setupVertexBuffer(U32 data_mask) const
 	{
 		U8* base = useVBOs() ? NULL : mMappedData;
 
-		glVertexPointer(3,GL_FLOAT, mStride, (void*)(base + 0));
-		glNormalPointer(GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_NORMAL]));
-		glTexCoordPointer(2,GL_FLOAT, mStride, (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+		glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_VERTEX], (void*)(base + 0));
+		glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+		glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
 		
-		set_vertex_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT], mStride, (F32*)(base + mOffsets[TYPE_WEIGHT]));
+		set_vertex_weights(LLDrawPoolAvatar::sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_WEIGHT], 
+						LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_WEIGHT], (F32*)(base + mOffsets[TYPE_WEIGHT]));
 
 		if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_BUMP)
 		{
-			set_binormals(sVertexProgram->mAttribute[LLViewerShaderMgr::BINORMAL], mStride, (LLVector3*)(base + mOffsets[TYPE_BINORMAL]));
+			set_binormals(LLDrawPoolAvatar::sVertexProgram->mAttribute[LLViewerShaderMgr::BINORMAL],
+				LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_BINORMAL], (LLVector3*)(base + mOffsets[TYPE_BINORMAL]));
 		}
 	
 		if (sShaderLevel >= LLDrawPoolAvatar::SHADER_LEVEL_CLOTH)
 		{
-			set_vertex_clothing_weights(sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_CLOTHING], mStride, (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
+			set_vertex_clothing_weights(LLDrawPoolAvatar::sVertexProgram->mAttribute[LLViewerShaderMgr::AVATAR_CLOTHING], 
+				LLVertexBuffer::sTypeOffsets[LLVertexBuffer::TYPE_CLOTHWEIGHT], (LLVector4*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
 		}
 	}
 	else
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index b9479436199c3b5effb22261dc51a2e4e3f93197..46ffc42f040dea5da06b76a4365e8d928b1e477c 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -1,4 +1,4 @@
-/** 
+ /** 
  * @file lldrawpoolavatar.h
  * @brief LLDrawPoolAvatar class definition
  *
@@ -36,6 +36,12 @@
 #include "lldrawpool.h"
 
 class LLVOAvatar;
+class LLGLSLShader;
+class LLFace;
+class LLMeshSkinInfo;
+class LLVolume;
+class LLVolumeFace;
+
 
 class LLDrawPoolAvatar : public LLFacePool
 {
@@ -88,11 +94,11 @@ class LLDrawPoolAvatar : public LLFacePool
 	/*virtual*/ void renderShadow(S32 pass);
 
 	void beginRigid();
-	void beginFootShadow();
+	void beginImpostor();
 	void beginSkinned();
-		
+	
 	void endRigid();
-	void endFootShadow();
+	void endImpostor();
 	void endSkinned();
 
 	void beginDeferredImpostor();
@@ -102,14 +108,114 @@ class LLDrawPoolAvatar : public LLFacePool
 	void endDeferredImpostor();
 	void endDeferredRigid();
 	void endDeferredSkinned();
+	
+	void beginPostDeferredAlpha();
+	void endPostDeferredAlpha();
+
+#if LL_MESH_ENABLED
+	void beginRiggedSimple();
+	void beginRiggedFullbright();
+	void beginRiggedFullbrightShiny();
+	void beginRiggedShinySimple();
+	void beginRiggedAlpha();
+	void beginRiggedFullbrightAlpha();
+	void beginRiggedGlow();
+	void beginDeferredRiggedAlpha();
+
+	void endRiggedSimple();
+	void endRiggedFullbright();
+	void endRiggedFullbrightShiny();
+	void endRiggedShinySimple();
+	void endRiggedAlpha();
+	void endRiggedFullbrightAlpha();
+	void endRiggedGlow();
+	void endDeferredRiggedAlpha();
+
+	void beginDeferredRiggedSimple();
+	void beginDeferredRiggedBump();
+	
+	void endDeferredRiggedSimple();
+	void endDeferredRiggedBump();
 		
+	void updateRiggedFaceVertexBuffer(LLFace* facep, 
+									  const LLMeshSkinInfo* skin, 
+									  LLVolume* volume,
+									  const LLVolumeFace& vol_face);
+
+	void renderRigged(LLVOAvatar* avatar, U32 type, bool glow = false);
+	void renderRiggedSimple(LLVOAvatar* avatar);
+	void renderRiggedAlpha(LLVOAvatar* avatar);
+	void renderRiggedFullbrightAlpha(LLVOAvatar* avatar);
+	void renderRiggedFullbright(LLVOAvatar* avatar);
+	void renderRiggedShinySimple(LLVOAvatar* avatar);
+	void renderRiggedFullbrightShiny(LLVOAvatar* avatar);
+	void renderRiggedGlow(LLVOAvatar* avatar);
+	void renderDeferredRiggedSimple(LLVOAvatar* avatar);
+	void renderDeferredRiggedBump(LLVOAvatar* avatar);
+
+	typedef enum
+	{
+		RIGGED_SIMPLE = 0,
+		RIGGED_FULLBRIGHT,
+		RIGGED_SHINY,
+		RIGGED_FULLBRIGHT_SHINY,
+		RIGGED_GLOW,
+		RIGGED_ALPHA,
+		RIGGED_FULLBRIGHT_ALPHA,
+		RIGGED_DEFERRED_BUMP,
+		RIGGED_DEFERRED_SIMPLE,
+		NUM_RIGGED_PASSES,
+		RIGGED_UNKNOWN,
+	} eRiggedPass;
+
+	typedef enum
+	{
+		RIGGED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | 
+							 LLVertexBuffer::MAP_NORMAL | 
+							 LLVertexBuffer::MAP_TEXCOORD0 |
+							 LLVertexBuffer::MAP_COLOR |
+							 LLVertexBuffer::MAP_WEIGHT4,
+		RIGGED_FULLBRIGHT_MASK = LLVertexBuffer::MAP_VERTEX | 
+							 LLVertexBuffer::MAP_TEXCOORD0 |
+							 LLVertexBuffer::MAP_COLOR |
+							 LLVertexBuffer::MAP_WEIGHT4,
+		RIGGED_SHINY_MASK = RIGGED_SIMPLE_MASK,
+		RIGGED_FULLBRIGHT_SHINY_MASK = RIGGED_SIMPLE_MASK,							 
+		RIGGED_GLOW_MASK = LLVertexBuffer::MAP_VERTEX | 
+							 LLVertexBuffer::MAP_TEXCOORD0 |
+							 LLVertexBuffer::MAP_WEIGHT4,
+		RIGGED_ALPHA_MASK = RIGGED_SIMPLE_MASK,
+		RIGGED_FULLBRIGHT_ALPHA_MASK = RIGGED_FULLBRIGHT_MASK,
+		RIGGED_DEFERRED_BUMP_MASK = LLVertexBuffer::MAP_VERTEX | 
+							 LLVertexBuffer::MAP_NORMAL | 
+							 LLVertexBuffer::MAP_TEXCOORD0 |
+							 LLVertexBuffer::MAP_BINORMAL |
+							 LLVertexBuffer::MAP_COLOR |
+							 LLVertexBuffer::MAP_WEIGHT4,
+		RIGGED_DEFERRED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | 
+							 LLVertexBuffer::MAP_NORMAL | 
+							 LLVertexBuffer::MAP_TEXCOORD0 |
+							 LLVertexBuffer::MAP_COLOR |
+							 LLVertexBuffer::MAP_WEIGHT4,
+	} eRiggedDataMask;
+
+	void addRiggedFace(LLFace* facep, U32 type);
+	void removeRiggedFace(LLFace* facep); 
+
+	std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES];
+#endif
+
 	/*virtual*/ LLViewerTexture *getDebugTexture();
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
 	void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null.
 
+
 	static BOOL sSkipOpaque;
 	static BOOL sSkipTransparent;
+	static S32 sDiffuseChannel;
+
+	static LLGLSLShader* sVertexProgram;
 };
 
 class LLVertexBufferAvatar : public LLVertexBuffer
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 19cdccb630e533da0e31af94accbf8caafd73cf5..fb58b6affaec86eb14fff5009c34ef5e54245fd5 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -94,7 +94,16 @@ void LLStandardBumpmap::shutdown()
 // static 
 void LLStandardBumpmap::restoreGL()
 {
-	llassert( LLStandardBumpmap::sStandardBumpmapCount == 0 );
+	addstandard();
+}
+
+// static
+void LLStandardBumpmap::addstandard()
+{
+	// can't assert; we destroyGL and restoreGL a lot during *first* startup, which populates this list already, THEN we explicitly init the list as part of *normal* startup.  Sigh.  So clear the list every time before we (re-)add the standard bumpmaps.
+	//llassert( LLStandardBumpmap::sStandardBumpmapCount == 0 );
+	clear();
+	llinfos << "Adding standard bumpmaps." << llendl;
 	gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("None");		// BE_NO_BUMP
 	gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Brightness");	// BE_BRIGHTNESS
 	gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount++] = LLStandardBumpmap("Darkness");	// BE_DARKNESS
@@ -156,8 +165,9 @@ void LLStandardBumpmap::restoreGL()
 }
 
 // static
-void LLStandardBumpmap::destroyGL()
+void LLStandardBumpmap::clear()
 {
+	llinfos << "Clearing standard bumpmaps." << llendl;
 	for( U32 i = 0; i < LLStandardBumpmap::sStandardBumpmapCount; i++ )
 	{
 		gStandardBumpmapList[i].mLabel.assign("");
@@ -166,6 +176,12 @@ void LLStandardBumpmap::destroyGL()
 	sStandardBumpmapCount = 0;
 }
 
+// static
+void LLStandardBumpmap::destroyGL()
+{
+	clear();
+}
+
 
 
 ////////////////////////////////////////////////////////////////
@@ -323,30 +339,43 @@ void LLDrawPoolBump::beginShiny(bool invisible)
 		sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 	}
 	
-	if (LLPipeline::sUnderWaterRender)
+	if (getVertexShaderLevel() > 0)
 	{
-		shader = &gObjectShinyWaterProgram;
+		if (LLPipeline::sUnderWaterRender)
+		{
+			shader = &gObjectShinyWaterProgram;
+		}
+		else
+		{
+			shader = &gObjectShinyProgram;
+		}
+		shader->bind();
 	}
 	else
 	{
-		shader = &gObjectShinyProgram;
+		shader = NULL;
 	}
 
+	bindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible);
+}
+
+//static
+void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
+{
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
-		if (!invisible && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0 )
+		if (!invisible && shader )
 		{
 			LLMatrix4 mat;
 			mat.initRows(LLVector4(gGLModelView+0),
 						 LLVector4(gGLModelView+4),
 						 LLVector4(gGLModelView+8),
 						 LLVector4(gGLModelView+12));
-			shader->bind();
 			LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 			LLVector4 vec4(vec, gShinyOrigin.mV[3]);
 			shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
-			if (mVertexShaderLevel > 1)
+			if (shader_level > 1)
 			{
 				cube_map->setMatrix(1);
 				// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
@@ -408,22 +437,16 @@ void LLDrawPoolBump::renderShiny(bool invisible)
 	}
 }
 
-void LLDrawPoolBump::endShiny(bool invisible)
+//static
+void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
 {
-	LLFastTimer t(FTM_RENDER_SHINY);
-	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
-		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
-	{
-		return;
-	}
-
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
 		cube_map->disable();
 		cube_map->restoreMatrix();
 
-		if (!invisible && mVertexShaderLevel > 1)
+		if (!invisible && shader_level > 1)
 		{
 			shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 					
@@ -434,7 +457,6 @@ void LLDrawPoolBump::endShiny(bool invisible)
 					shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 				}
 			}
-			shader->unbind();
 		}
 	}
 	gGL.getTexUnit(diffuse_channel)->disable();
@@ -442,6 +464,22 @@ void LLDrawPoolBump::endShiny(bool invisible)
 
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+}
+
+void LLDrawPoolBump::endShiny(bool invisible)
+{
+	LLFastTimer t(FTM_RENDER_SHINY);
+	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
+		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
+	{
+		return;
+	}
+
+	unbindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible);
+	if (shader)
+	{
+		shader->unbind();
+	}
 
 	diffuse_channel = -1;
 	cube_channel = 0;
@@ -569,18 +607,37 @@ void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL
 // static
 BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
 {
-	LLViewerTexture* bump = NULL;
-
 	U8 bump_code = params.mBump;
 
+	return bindBumpMap(bump_code, params.mTexture, params.mVSize, channel);
+}
+
+//static
+BOOL LLDrawPoolBump::bindBumpMap(LLFace* face, S32 channel)
+{
+	const LLTextureEntry* te = face->getTextureEntry();
+	if (te)
+	{
+		U8 bump_code = te->getBumpmap();
+		return bindBumpMap(bump_code, face->getTexture(), face->getVirtualSize(), channel);
+	}
+
+	return FALSE;
+}
+
+//static
+BOOL LLDrawPoolBump::bindBumpMap(U8 bump_code, LLViewerTexture* texture, F32 vsize, S32 channel)
+{
 	//Note: texture atlas does not support bump texture now.
-	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params.mTexture) ;
+	LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(texture) ;
 	if(!tex)
 	{
 		//if the texture is not a fetched texture
 		return FALSE;
 	}
 
+	LLViewerTexture* bump = NULL;
+
 	switch( bump_code )
 	{
 	case BE_NO_BUMP:		
@@ -594,7 +651,7 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
 		if( bump_code < LLStandardBumpmap::sStandardBumpmapCount )
 		{
 			bump = gStandardBumpmapList[bump_code].mImage;
-			gBumpImageList.addTextureStats(bump_code, tex->getID(), params.mVSize);
+			gBumpImageList.addTextureStats(bump_code, tex->getID(), vsize);
 		}
 		break;
 	}
@@ -618,9 +675,9 @@ BOOL LLDrawPoolBump::bindBumpMap(LLDrawInfo& params, S32 channel)
 }
 
 //static
-void LLDrawPoolBump::beginBump()
+void LLDrawPoolBump::beginBump(U32 pass)
 {	
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	if (!gPipeline.hasRenderBatches(pass))
 	{
 		return;
 	}
@@ -663,9 +720,9 @@ void LLDrawPoolBump::beginBump()
 }
 
 //static
-void LLDrawPoolBump::renderBump()
+void LLDrawPoolBump::renderBump(U32 pass)
 {
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	if (!gPipeline.hasRenderBatches(pass))
 	{
 		return;
 	}
@@ -678,13 +735,13 @@ void LLDrawPoolBump::renderBump()
 	/// Get rid of z-fighting with non-bump pass.
 	LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
 	glPolygonOffset(-1.0f, -1.0f);
-	renderBump(LLRenderPass::PASS_BUMP, sVertexMask);
+	renderBump(pass, sVertexMask);
 }
 
 //static
-void LLDrawPoolBump::endBump()
+void LLDrawPoolBump::endBump(U32 pass)
 {
-	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
+	if (!gPipeline.hasRenderBatches(pass))
 	{
 		return;
 	}
@@ -701,6 +758,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))
@@ -755,21 +824,45 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
 
 void LLDrawPoolBump::beginPostDeferredPass(S32 pass)
 {
-	beginFullbrightShiny();
+	switch (pass)
+	{
+	case 0:
+		beginFullbrightShiny();
+		break;
+	case 1:
+		beginBump(LLRenderPass::PASS_POST_BUMP);
+		break;
+	}
 }
 
 void LLDrawPoolBump::endPostDeferredPass(S32 pass)
 {
-	endFullbrightShiny();
+	switch (pass)
+	{
+	case 0:
+		endFullbrightShiny();
+		break;
+	case 1:
+		endBump(LLRenderPass::PASS_POST_BUMP);
+		break;
+	}
 }
 
 void LLDrawPoolBump::renderPostDeferred(S32 pass)
 {
-	renderFullbrightShiny();
+	switch (pass)
+	{
+	case 0:
+		renderFullbrightShiny();
+		break;
+	case 1:
+		renderBump(LLRenderPass::PASS_POST_BUMP);
+		break;
+	}
 }
 
 ////////////////////////////////////////////////////////////////
-// List of one-component bump-maps created from other texures.
+// List of bump-maps created from other textures.
 
 
 //const LLUUID TEST_BUMP_ID("3d33eaf2-459c-6f97-fd76-5fce3fc29447");
@@ -782,24 +875,32 @@ void LLBumpImageList::init()
 	LLStandardBumpmap::init();
 }
 
-void LLBumpImageList::shutdown()
+void LLBumpImageList::clear()
 {
+	llinfos << "Clearing dynamic bumpmaps." << llendl;
+	// these will be re-populated on-demand
 	mBrightnessEntries.clear();
 	mDarknessEntries.clear();
+
+	LLStandardBumpmap::clear();
+}
+
+void LLBumpImageList::shutdown()
+{
+	clear();
 	LLStandardBumpmap::shutdown();
 }
 
 void LLBumpImageList::destroyGL()
 {
-	mBrightnessEntries.clear();
-	mDarknessEntries.clear();
+	clear();
 	LLStandardBumpmap::destroyGL();
 }
 
 void LLBumpImageList::restoreGL()
 {
-	// Images will be recreated as they are needed.
 	LLStandardBumpmap::restoreGL();
+	// Images will be recreated as they are needed.
 }
 
 
@@ -851,6 +952,7 @@ void LLBumpImageList::updateImages()
 			}
 		}
 	}
+	
 	for (bump_image_map_t::iterator iter = mDarknessEntries.begin(); iter != mDarknessEntries.end(); )
 	{
 		bump_image_map_t::iterator curiter = iter++;
@@ -1002,8 +1104,8 @@ void LLBumpImageList::generateNormalMapFromAlpha(LLImageRaw* src, LLImageRaw* nr
 
 			LLVector3 right = LLVector3(norm_scale, 0, (F32) src_data[(j*resX+rX)*src_cmp+src_cmp-1]-cH);
 			LLVector3 left = LLVector3(-norm_scale, 0, (F32) src_data[(j*resX+lX)*src_cmp+src_cmp-1]-cH);
-			LLVector3 up = LLVector3(0, -norm_scale, (F32) src_data[(rY*resX+i)*src_cmp+src_cmp-1]-cH);
-			LLVector3 down = LLVector3(0, norm_scale, (F32) src_data[(lY*resX+i)*src_cmp+src_cmp-1]-cH);
+			LLVector3 up = LLVector3(0, -norm_scale, (F32) src_data[(lY*resX+i)*src_cmp+src_cmp-1]-cH);
+			LLVector3 down = LLVector3(0, norm_scale, (F32) src_data[(rY*resX+i)*src_cmp+src_cmp-1]-cH);
 
 			LLVector3 norm = right%down + down%left + left%up + up%right;
 		
@@ -1028,7 +1130,7 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 	{
 		bump_image_map_t& entries_list(bump_code == BE_BRIGHTNESS ? gBumpImageList.mBrightnessEntries : gBumpImageList.mDarknessEntries );
 		bump_image_map_t::iterator iter = entries_list.find(source_asset_id);
-		if (iter != entries_list.end())
+		if (iter != entries_list.end()) // bump not cached yet
 		{
 			LLPointer<LLImageRaw> dst_image = new LLImageRaw(src->getWidth(), src->getHeight(), 1);
 			U8* dst_data = dst_image->getData();
@@ -1113,8 +1215,8 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 				F32 twice_one_over_range = 2.f / (maximum - minimum);
 				S32 i;
 
-				const F32 ARTIFICIAL_SCALE = 2.f;  // Advantage: exagerates the effect in midrange.  Disadvantage: clamps at the extremes.
-				if( BE_DARKNESS == bump_code )
+				const F32 ARTIFICIAL_SCALE = 2.f;  // Advantage: exaggerates the effect in midrange.  Disadvantage: clamps at the extremes.
+				if (BE_DARKNESS == bump_code)
 				{
 					for( i = minimum; i <= maximum; i++ )
 					{
@@ -1124,7 +1226,6 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 				}
 				else
 				{
-					// BE_LIGHTNESS
 					for( i = minimum; i <= maximum; i++ )
 					{
 						F32 minus_one_to_one = F32(i - minimum) * twice_one_over_range - 1.f;
@@ -1139,9 +1240,9 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 			}
 
 			//---------------------------------------------------
-			//immediately assign bump to a global smart pointer in case some local smart pointer
-			//accidently releases it.
-			LLPointer<LLViewerTexture> bump = LLViewerTextureManager::getLocalTexture( TRUE);
+			// immediately assign bump to a global smart pointer in case some local smart pointer
+			// accidentally releases it.
+			LLPointer<LLViewerTexture> bump = LLViewerTextureManager::getLocalTexture( TRUE );
 			
 			if (!LLPipeline::sRenderDeferred)
 			{
@@ -1150,8 +1251,8 @@ void LLBumpImageList::onSourceLoaded( BOOL success, LLViewerTexture *src_vi, LLI
 			}
 			else
 			{
-				LLPointer<LLImageRaw> nrm_image = new LLImageRaw(src->getWidth(), src->getHeight(), 4);
-				generateNormalMapFromAlpha(src, nrm_image);
+				LLPointer<LLImageRaw> nrm_image = new LLImageRaw(dst_image->getWidth(), dst_image->getHeight(), 4);
+				generateNormalMapFromAlpha(dst_image, nrm_image);
 				bump->setExplicitFormat(GL_RGBA, GL_RGBA);
 				bump->createGLTexture(0, nrm_image);
 			}
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index bf940cf1e46ef6d5bbf0bd58eb57265fd5d58e2c..d634b7329e51c7da94a05f8c46ec3e98ce82fa30 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -41,6 +41,7 @@
 class LLImageRaw;
 class LLSpatialGroup;
 class LLDrawInfo;
+class LLGLSLShader;
 class LLViewerFetchedTexture;
 
 class LLDrawPoolBump : public LLRenderPass
@@ -75,21 +76,29 @@ protected :
 	void renderFullbrightShiny();
 	void endFullbrightShiny();
 
-	void beginBump();
-	void renderBump();
-	void endBump();
+	void beginBump(U32 pass = LLRenderPass::PASS_BUMP);
+	void renderBump(U32 pass = LLRenderPass::PASS_BUMP);
+	void endBump(U32 pass = LLRenderPass::PASS_BUMP);
 
-	virtual S32 getNumDeferredPasses() { return 1; }
+	static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
+	static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
+
+	virtual S32 getNumDeferredPasses();
 	/*virtual*/ void beginDeferredPass(S32 pass);
 	/*virtual*/ void endDeferredPass(S32 pass);
 	/*virtual*/ void renderDeferred(S32 pass);
 
-	virtual S32 getNumPostDeferredPasses() { return 1; }
+	virtual S32 getNumPostDeferredPasses() { return 2; }
 	/*virtual*/ void beginPostDeferredPass(S32 pass);
 	/*virtual*/ void endPostDeferredPass(S32 pass);
 	/*virtual*/ void renderPostDeferred(S32 pass);
 
-	BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2);
+	static BOOL bindBumpMap(LLDrawInfo& params, S32 channel = -2);
+	static BOOL bindBumpMap(LLFace* face, S32 channel = -2);
+
+private:
+	static BOOL bindBumpMap(U8 bump_code, LLViewerTexture* tex, F32 vsize, S32 channel);
+
 };
 
 enum EBumpEffect
@@ -115,9 +124,12 @@ class LLStandardBumpmap
 
 	static	U32 sStandardBumpmapCount;  // Number of valid values in gStandardBumpmapList[]
 
+	static void clear();
+	static void addstandard();
+
 	static void init();
 	static void shutdown();
-	static void	restoreGL();
+	static void restoreGL();
 	static void destroyGL();
 };
 
@@ -136,6 +148,7 @@ class LLBumpImageList
 
 	void		init();
 	void		shutdown();
+	void            clear();
 	void		destroyGL();
 	void		restoreGL();
 	void		updateImages();
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index ca7a1b47c2cacb3754d3a82ccec361ac239b7e8a..91191287cd95e7497e0db99ff89c79478203edd6 100644
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -55,6 +55,10 @@ void LLDrawPoolGlow::render(S32 pass)
 	LLFastTimer t(FTM_RENDER_GLOW);
 	LLGLEnable blend(GL_BLEND);
 	LLGLDisable test(GL_ALPHA_TEST);
+	gGL.flush();
+	/// Get rid of z-fighting with non-glow pass.
+	LLGLEnable polyOffset(GL_POLYGON_OFFSET_FILL);
+	glPolygonOffset(-1.0f, -1.0f);
 	gGL.setSceneBlendType(LLRender::BT_ADD);
 	
 	U32 shader_level = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
@@ -147,7 +151,8 @@ void LLDrawPoolSimple::render(S32 pass)
 		renderTexture(LLRenderPass::PASS_SIMPLE, getVertexDataMask());
 
 		if (LLPipeline::sRenderDeferred)
-		{
+		{ //if deferred rendering is enabled, bump faces aren't reigstered as simple
+			//render bump faces here as simple so bump faces will appear under water
 			renderTexture(LLRenderPass::PASS_BUMP, getVertexDataMask());
 		}
 	}
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index e0e5b32299a36cf8faa2e2a23e190af76411215f..c48106863ed8552977f22c60dd1bee8c6d2a1112 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -39,8 +39,10 @@
 #include "llviewercontrol.h"
 #include "llvolume.h"
 #include "m3math.h"
+#include "llmatrix4a.h"
 #include "v3color.h"
 
+#include "lldrawpoolavatar.h"
 #include "lldrawpoolbump.h"
 #include "llgl.h"
 #include "llrender.h"
@@ -73,35 +75,43 @@ The resulting texture coordinate <u,v> is:
 	u = 2(B dot P)
 	v = 2(T dot P)
 */
-void planarProjection(LLVector2 &tc, const LLVector3& normal,
-					  const LLVector3 &mCenter, const LLVector3& vec)
-{	//DONE!
-	LLVector3 binormal;
-	float d = normal * LLVector3(1,0,0);
+void planarProjection(LLVector2 &tc, const LLVector4a& normal,
+					  const LLVector4a &center, const LLVector4a& vec)
+{	
+	LLVector4a binormal;
+	F32 d = normal[0];
+
 	if (d >= 0.5f || d <= -0.5f)
 	{
-		binormal = LLVector3(0,1,0);
-		if (normal.mV[0] < 0)
+		if (d < 0)
 		{
-			binormal = -binormal;
+			binormal.set(0,-1,0);
+		}
+		else
+		{
+			binormal.set(0, 1, 0);
 		}
 	}
 	else
 	{
-        binormal = LLVector3(1,0,0);
-		if (normal.mV[1] > 0)
+        if (normal[1] > 0)
+		{
+			binormal.set(-1,0,0);
+		}
+		else
 		{
-			binormal = -binormal;
+			binormal.set(1,0,0);
 		}
 	}
-	LLVector3 tangent = binormal % normal;
+	LLVector4a tangent;
+	tangent.setCross3(binormal,normal);
 
-	tc.mV[1] = -((tangent*vec)*2 - 0.5f);
-	tc.mV[0] = 1.0f+((binormal*vec)*2 - 0.5f);
+	tc.mV[1] = -((tangent.dot3(vec))*2 - 0.5f);
+	tc.mV[0] = 1.0f+((binormal.dot3(vec))*2 - 0.5f);
 }
 
-void sphericalProjection(LLVector2 &tc, const LLVector3& normal,
-						 const LLVector3 &mCenter, const LLVector3& vec)
+void sphericalProjection(LLVector2 &tc, const LLVector4a& normal,
+						 const LLVector4a &mCenter, const LLVector4a& vec)
 {	//BROKEN
 	/*tc.mV[0] = acosf(vd.mNormal * LLVector3(1,0,0))/3.14159f;
 	
@@ -112,7 +122,7 @@ void sphericalProjection(LLVector2 &tc, const LLVector3& normal,
 	}*/
 }
 
-void cylindricalProjection(LLVector2 &tc, const LLVector3& normal, const LLVector3 &mCenter, const LLVector3& vec)
+void cylindricalProjection(LLVector2 &tc, const LLVector4a& normal, const LLVector4a &mCenter, const LLVector4a& vec)
 {	//BROKEN
 	/*LLVector3 binormal;
 	float d = vd.mNormal * LLVector3(1,0,0);
@@ -142,6 +152,8 @@ void cylindricalProjection(LLVector2 &tc, const LLVector3& normal, const LLVecto
 
 void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 {
+	mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*2);
+
 	mLastUpdateTime = gFrameTimeSeconds;
 	mLastMoveTime = 0.f;
 	mVSize = 0.f;
@@ -185,22 +197,50 @@ 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 (gDebugGL)
+	{
+		gPipeline.checkReferences(this);
+	}
+
 	if(mTexture.notNull())
 	{
+		LLFastTimer t(FTM_DESTROY_TEXTURE);
 		mTexture->removeFace(this) ;
 	}
 	
 	if (mDrawPoolp)
 	{
-		mDrawPoolp->removeFace(this);
+		LLFastTimer t(FTM_DESTROY_DRAWPOOL);
+
+#if LL_MESH_ENABLED
+		if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR)
+		{
+			((LLDrawPoolAvatar*) mDrawPoolp)->removeRiggedFace(this);
+		}
+		else
+#endif
+		{
+			mDrawPoolp->removeFace(this);
+		}
+	
 		mDrawPoolp = NULL;
 	}
 
 	if (mTextureMatrix)
 	{
+		LLFastTimer t(FTM_DESTROY_TEXTURE_MATRIX);
 		delete mTextureMatrix;
 		mTextureMatrix = NULL;
 
@@ -215,11 +255,24 @@ void LLFace::destroy()
 		}
 	}
 	
-	setDrawInfo(NULL);
+	{
+		LLFastTimer t(FTM_DESTROY_DRAW_INFO);
+		setDrawInfo(NULL);
+	}
 	
-	removeAtlas();
-	mDrawablep = NULL;
-	mVObjp = NULL;
+	{
+		LLFastTimer t(FTM_DESTROY_ATLAS);
+		removeAtlas();
+	}
+	
+	{
+		LLFastTimer t(FTM_FACE_DEREF);
+		mDrawablep = NULL;
+		mVObjp = NULL;
+	}
+
+	ll_aligned_free_16(mExtents);
+	mExtents = NULL;
 }
 
 
@@ -335,8 +388,21 @@ void LLFace::setDrawable(LLDrawable *drawable)
 	mXform      = &drawable->mXform;
 }
 
-void LLFace::setSize(const S32 num_vertices, const S32 num_indices)
+void LLFace::setSize(S32 num_vertices, S32 num_indices, bool align)
 {
+	if (align)
+	{
+		//allocate vertices in blocks of 4 for alignment
+		num_vertices = (num_vertices + 0x3) & ~0x3;
+	}
+	else
+	{
+		if (mDrawablep->getVOVolume())
+		{
+			llerrs << "WTF?" << llendl;
+		}
+	}
+
 	if (mGeomCount != num_vertices ||
 		mIndicesCount != num_indices)
 	{
@@ -672,95 +738,117 @@ static void xform(LLVector2 &tex_coord, F32 cosAng, F32 sinAng, F32 offS, F32 of
 
 
 BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
-								const LLMatrix4& mat_vert, const LLMatrix3& mat_normal, BOOL global_volume)
+								const LLMatrix4& mat_vert_in, const LLMatrix3& mat_normal_in, BOOL global_volume)
 {
 	LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
 
 	//get bounding box
 	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
 	{
+		//VECTORIZE THIS
+		LLMatrix4a mat_vert;
+		mat_vert.loadu(mat_vert_in);
+
+		LLMatrix4a mat_normal;
+		mat_normal.loadu(mat_normal_in);
+
 		//if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME))
 		//{ //vertex buffer no longer valid
 		//	mVertexBuffer = NULL;
 		//	mLastVertexBuffer = NULL;
 		//}
 
-		LLVector3 min,max;
+		//VECTORIZE THIS
+		LLVector4a min,max;
 	
 		if (f >= volume.getNumVolumeFaces())
 		{
-			min = LLVector3(-1,-1,-1);
-			max = LLVector3(1,1,1);
-		}
-		else
-		{
-			const LLVolumeFace &face = volume.getVolumeFace(f);
-			min = face.mExtents[0];
-			max = face.mExtents[1];
+			llwarns << "Generating bounding box for invalid face index!" << llendl;
+			f = 0;
 		}
 
+		const LLVolumeFace &face = volume.getVolumeFace(f);
+		min = face.mExtents[0];
+		max = face.mExtents[1];
+		
+
 		//min, max are in volume space, convert to drawable render space
-		LLVector3 center = ((min + max) * 0.5f)*mat_vert;
-		LLVector3 size = ((max-min) * 0.5f);
+		LLVector4a center;
+		LLVector4a t;
+		t.setAdd(min, max);
+		t.mul(0.5f);
+		mat_vert.affineTransform(t, center);
+		LLVector4a size;
+		size.setSub(max, min);
+		size.mul(0.5f);
+
 		if (!global_volume)
 		{
-			size.scaleVec(mDrawablep->getVObj()->getScale());
+			//VECTORIZE THIS
+			LLVector4a scale;
+			scale.load3(mDrawablep->getVObj()->getScale().mV);
+			size.mul(scale);
 		}
 
-		LLMatrix3 mat = mat_normal;
-		LLVector3 x = mat.getFwdRow();
-		LLVector3 y = mat.getLeftRow();
-		LLVector3 z = mat.getUpRow();
-		x.normVec();
-		y.normVec();
-		z.normVec();
+		mat_normal.mMatrix[0].normalize3fast();
+		mat_normal.mMatrix[1].normalize3fast();
+		mat_normal.mMatrix[2].normalize3fast();
+		
+		LLVector4a v[4];
 
-		mat.setRows(x,y,z);
+		//get 4 corners of bounding box
+		mat_normal.rotate(size,v[0]);
 
-		LLQuaternion rotation = LLQuaternion(mat);
+		//VECTORIZE THIS
+		LLVector4a scale;
 		
-		LLVector3 v[4];
-		//get 4 corners of bounding box
-		v[0] = (size * rotation);
-		v[1] = (LLVector3(-size.mV[0], -size.mV[1], size.mV[2]) * rotation);
-		v[2] = (LLVector3(size.mV[0], -size.mV[1], -size.mV[2]) * rotation);
-		v[3] = (LLVector3(-size.mV[0], size.mV[1], -size.mV[2]) * rotation);
+		scale.set(-1.f, -1.f, 1.f);
+		scale.mul(size);
+		mat_normal.rotate(scale, v[1]);
+		
+		scale.set(1.f, -1.f, -1.f);
+		scale.mul(size);
+		mat_normal.rotate(scale, v[2]);
+		
+		scale.set(-1.f, 1.f, -1.f);
+		scale.mul(size);
+		mat_normal.rotate(scale, v[3]);
 
-		LLVector3& newMin = mExtents[0];
-		LLVector3& newMax = mExtents[1];
+		LLVector4a& newMin = mExtents[0];
+		LLVector4a& newMax = mExtents[1];
 		
 		newMin = newMax = center;
 		
 		for (U32 i = 0; i < 4; i++)
 		{
-			for (U32 j = 0; j < 3; j++)
-			{
-				F32 delta = fabsf(v[i].mV[j]);
-				F32 min = center.mV[j] - delta;
-				F32 max = center.mV[j] + delta;
-				
-				if (min < newMin.mV[j])
-				{
-					newMin.mV[j] = min;
-				}
-				
-				if (max > newMax.mV[j])
-				{
-					newMax.mV[j] = max;
-				}
-			}
+			LLVector4a delta;
+			delta.setAbs(v[i]);
+			LLVector4a min;
+			min.setSub(center, delta);
+			LLVector4a max;
+			max.setAdd(center, delta);
+
+			newMin.setMin(min);
+			newMax.setMax(max);
 		}
 
 		if (!mDrawablep->isActive())
 		{
-			LLVector3 offset = mDrawablep->getRegion()->getOriginAgent();
-			newMin += offset;
-			newMax += offset;
+			LLVector4a offset;
+			offset.load3(mDrawablep->getRegion()->getOriginAgent().mV);
+			newMin.add(offset);
+			newMax.add(offset);
 		}
 
-		mCenterLocal = (newMin+newMax)*0.5f;
-		LLVector3 tmp = (newMin - newMax) ;
-		mBoundingSphereRadius = tmp.length() * 0.5f ;
+		t.setAdd(newMin, newMax);
+		t.mul(0.5f);
+
+		//VECTORIZE THIS
+		mCenterLocal.set(t.getF32());
+		
+		t.setSub(newMax,newMin);
+		t.mul(0.5f);
+		mBoundingSphereRadius = t.length3();
 
 		updateCenterAgent();
 	}
@@ -787,18 +875,26 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position,
 		return surface_coord;
 	}
 
+	//VECTORIZE THIS
 	// see if we have a non-default mapping
     U8 texgen = getTextureEntry()->getTexGen();
 	if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
 	{
-		LLVector3 center = mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter;
+		LLVector4a& center = *(mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter);
+		
+		LLVector4a volume_position;
+		volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(position).mV);
 		
-		LLVector3 scale  = (mDrawablep->getVOVolume()->isVolumeGlobal()) ? LLVector3(1,1,1) : mVObjp->getScale();
-		LLVector3 volume_position = mDrawablep->getVOVolume()->agentPositionToVolume(position);
-		volume_position.scaleVec(scale);
+		if (!mDrawablep->getVOVolume()->isVolumeGlobal())
+		{
+			LLVector4a scale;
+			scale.load3(mVObjp->getScale().mV);
+			volume_position.mul(scale);
+		}
 		
-		LLVector3 volume_normal   = mDrawablep->getVOVolume()->agentDirectionToVolume(normal);
-		volume_normal.normalize();
+		LLVector4a volume_normal;
+		volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(normal).mV);
+		volume_normal.normalize3fast();
 		
 		switch (texgen)
 		{
@@ -862,14 +958,43 @@ void LLFace::updateRebuildFlags()
 	}
 }
 
+
+bool LLFace::canRenderAsMask()
+{
+	if (LLPipeline::sNoAlpha)
+	{
+		return true;
+	}
+
+	const LLTextureEntry* te = getTextureEntry();
+	return (
+		(
+		 (LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaDeferred) ||
+		 
+		 (!LLPipeline::sRenderDeferred && LLPipeline::sAutoMaskAlphaNonDeferred)		 
+		 ) // 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
+
+		getTexture()->getIsAlphaMask() // texture actually qualifies for masking (lazily recalculated but expensive)
+		);
+}
+
+
+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)
+								const LLMatrix4& mat_vert_in, const LLMatrix3& mat_norm_in,
+								const U16 &index_offset,
+								bool force_rebuild)
 {
+	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();
+	S32 num_vertices = (S32)vf.mNumVertices;
+	S32 num_indices = (S32) vf.mNumIndices;
 	
 	if (mVertexBuffer.notNull())
 	{
@@ -894,15 +1019,20 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 	}
 
-	LLStrider<LLVector3> vertices;
+	LLStrider<LLVector3> vert;
+	LLVector4a* vertices = NULL;
 	LLStrider<LLVector2> tex_coords;
 	LLStrider<LLVector2> tex_coords2;
-	LLStrider<LLVector3> normals;
+	LLVector4a* normals = NULL;
+	LLStrider<LLVector3> norm;
 	LLStrider<LLColor4U> colors;
-	LLStrider<LLVector3> binormals;
+	LLVector4a* binormals = NULL;
+	LLStrider<LLVector3> binorm;
 	LLStrider<U16> indicesp;
+	LLVector4a* weights = NULL;
+	LLStrider<LLVector4> wght;
 
-	BOOL full_rebuild = mDrawablep->isState(LLDrawable::REBUILD_VOLUME);
+	BOOL full_rebuild = force_rebuild || mDrawablep->isState(LLDrawable::REBUILD_VOLUME);
 	
 	BOOL global_volume = mDrawablep->getVOVolume()->isVolumeGlobal();
 	LLVector3 scale;
@@ -915,28 +1045,37 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		scale = mVObjp->getScale();
 	}
 	
-	BOOL rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION);
-	BOOL rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR);
-	BOOL rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
-	BOOL rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
-	BOOL rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL);
+	bool rebuild_pos = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_POSITION);
+	bool rebuild_color = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_COLOR);
+	bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
+	bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
+	bool rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL);
+	bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4);
 
 	const LLTextureEntry *tep = mVObjp->getTE(f);
-	U8  bump_code = tep ? tep->getBumpmap() : 0;
+	const U8 bump_code = tep ? tep->getBumpmap() : 0;
 
 	if (rebuild_pos)
 	{
-		mVertexBuffer->getVertexStrider(vertices, mGeomIndex);
+		mVertexBuffer->getVertexStrider(vert, mGeomIndex);
+		vertices = (LLVector4a*) vert.get();
 	}
 	if (rebuild_normal)
 	{
-		mVertexBuffer->getNormalStrider(normals, mGeomIndex);
+		mVertexBuffer->getNormalStrider(norm, mGeomIndex);
+		normals = (LLVector4a*) norm.get();
 	}
 	if (rebuild_binormal)
 	{
-		mVertexBuffer->getBinormalStrider(binormals, mGeomIndex);
+		mVertexBuffer->getBinormalStrider(binorm, mGeomIndex);
+		binormals = (LLVector4a*) binorm.get();
 	}
-
+	if (rebuild_weights)
+	{
+		mVertexBuffer->getWeight4Strider(wght, mGeomIndex);
+		weights = (LLVector4a*) wght.get();
+	}
+	
 	F32 tcoord_xoffset = 0.f ;
 	F32 tcoord_yoffset = 0.f ;
 	F32 tcoord_xscale = 1.f ;
@@ -968,8 +1107,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		mVertexBuffer->getColorStrider(colors, mGeomIndex);
 	}
 
-	F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
-	
 	BOOL is_static = mDrawablep->isStatic();
 	BOOL is_global = is_static;
 
@@ -984,59 +1121,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		clearState(GLOBAL);
 	}
 
-	LLVector2 tmin, tmax;
-	
-	
-
-	if (rebuild_tcoord)
-	{
-		if (tep)
-		{
-			r  = tep->getRotation();
-			os = tep->mOffsetS;
-			ot = tep->mOffsetT;
-			ms = tep->mScaleS;
-			mt = tep->mScaleT;
-			cos_ang = cos(r);
-			sin_ang = sin(r);
-		}
-		else
-		{
-			cos_ang = 1.0f;
-			sin_ang = 0.0f;
-			os = 0.0f;
-			ot = 0.0f;
-			ms = 1.0f;
-			mt = 1.0f;
-		}
-	}
-
-	U8 tex_mode = 0;
-	
-	if (isState(TEXTURE_ANIM))
-	{
-		LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;	
-		tex_mode = vobj->mTexAnimMode;
-
-		if (!tex_mode)
-		{
-			clearState(TEXTURE_ANIM);
-		}
-		else
-		{
-			os = ot = 0.f;
-			r = 0.f;
-			cos_ang = 1.f;
-			sin_ang = 0.f;
-			ms = mt = 1.f;
-		}
-
-		if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
-		{ //don't override texture transform during tc bake
-			tex_mode = 0;
-		}
-	}
-
 	LLColor4U color = tep->getColor();
 
 	if (rebuild_color)
@@ -1058,265 +1142,460 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		}
 	}
 
-    // INDICES
+	// INDICES
 	if (full_rebuild)
 	{
 		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
-		if (LLPipeline::sUseTriStrips)
+		__m128i* dst = (__m128i*) indicesp.get();
+		__m128i* src = (__m128i*) vf.mIndices;
+		__m128i offset = _mm_set1_epi16(index_offset);
+
+		S32 end = num_indices/8;
+		
+		for (S32 i = 0; i < end; i++)
 		{
-			for (U32 i = 0; i < (U32) num_indices; i++)
-			{
-				*indicesp++ = vf.mTriStrip[i] + index_offset;
-			}
+			__m128i res = _mm_add_epi16(src[i], offset);
+			_mm_storeu_si128(dst+i, res);
 		}
-		else
+
+		for (S32 i = end*8; i < num_indices; ++i)
 		{
-			for (U32 i = 0; i < (U32) num_indices; i++)
-			{
-				*indicesp++ = vf.mIndices[i] + index_offset;
-			}
+			indicesp[i] = vf.mIndices[i]+index_offset;
 		}
 	}
 	
+	LLMatrix4a mat_normal;
+	mat_normal.loadu(mat_norm_in);
 	
-	//bump setup
-	LLVector3 binormal_dir( -sin_ang, cos_ang, 0 );
-	LLVector3 bump_s_primary_light_ray;
-	LLVector3 bump_t_primary_light_ray;
+	//if it's not fullbright and has no normals, bake sunlight based on face normal
+	//bool bake_sunlight = !getTextureEntry()->getFullbright() &&
+	//  !mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
 
-	LLQuaternion bump_quat;
-	if (mDrawablep->isActive())
-	{
-		bump_quat = LLQuaternion(mDrawablep->getRenderMatrix());
-	}
-	
-	if (bump_code)
+	F32 r = 0, os = 0, ot = 0, ms = 0, mt = 0, cos_ang = 0, sin_ang = 0;
+
+	if (rebuild_tcoord)
 	{
-		mVObjp->getVolume()->genBinormals(f);
-		F32 offset_multiple; 
-		switch( bump_code )
+		bool do_xform;
+			
+		if (tep)
 		{
-			case BE_NO_BUMP:
-			offset_multiple = 0.f;
-			break;
-			case BE_BRIGHTNESS:
-			case BE_DARKNESS:
-			if( mTexture.notNull() && mTexture->hasGLTexture())
+			r  = tep->getRotation();
+			os = tep->mOffsetS;
+			ot = tep->mOffsetT;
+			ms = tep->mScaleS;
+			mt = tep->mScaleT;
+			cos_ang = cos(r);
+			sin_ang = sin(r);
+
+			if (cos_ang != 1.f || 
+				sin_ang != 0.f ||
+				os != 0.f ||
+				ot != 0.f ||
+				ms != 1.f ||
+				mt != 1.f)
 			{
-				// Offset by approximately one texel
-				S32 cur_discard = mTexture->getDiscardLevel();
-				S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() );
-				max_size <<= cur_discard;
-				const F32 ARTIFICIAL_OFFSET = 2.f;
-				offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size;
+				do_xform = true;
 			}
 			else
 			{
-				offset_multiple = 1.f/256;
-			}
-			break;
-
-			default:  // Standard bumpmap textures.  Assumed to be 256x256
-			offset_multiple = 1.f / 256;
-			break;
+				do_xform = false;
+			}	
 		}
-
-		F32 s_scale = 1.f;
-		F32 t_scale = 1.f;
-		if( tep )
+		else
 		{
-			tep->getScale( &s_scale, &t_scale );
+			do_xform = false;
 		}
-		// Use the nudged south when coming from above sun angle, such
-		// that emboss mapping always shows up on the upward faces of cubes when 
-		// it's noon (since a lot of builders build with the sun forced to noon).
-		LLVector3   sun_ray  = gSky.mVOSkyp->mBumpSunDir;
-		LLVector3   moon_ray = gSky.getMoonDirection();
-		LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray;
-
-		bump_s_primary_light_ray = offset_multiple * s_scale * primary_light_ray;
-		bump_t_primary_light_ray = offset_multiple * t_scale * primary_light_ray;
-	}
-		
-	U8 texgen = getTextureEntry()->getTexGen();
-	if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
-	{ //planar texgen needs binormals
-		mVObjp->getVolume()->genBinormals(f);
-	}
+						
+		//bump setup
+		LLVector4a binormal_dir( -sin_ang, cos_ang, 0.f );
+		LLVector4a bump_s_primary_light_ray(0.f, 0.f, 0.f);
+		LLVector4a bump_t_primary_light_ray(0.f, 0.f, 0.f);
 
-	for (S32 i = 0; i < num_vertices; i++)
-	{
-		if (rebuild_tcoord)
+		LLQuaternion bump_quat;
+		if (mDrawablep->isActive())
 		{
-			LLVector2 tc = vf.mVertices[i].mTexCoord;
+			bump_quat = LLQuaternion(mDrawablep->getRenderMatrix());
+		}
 		
-			if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+		if (bump_code)
+		{
+			mVObjp->getVolume()->genBinormals(f);
+			F32 offset_multiple; 
+			switch( bump_code )
 			{
-				LLVector3 vec = vf.mVertices[i].mPosition; 
-			
-				vec.scaleVec(scale);
-
-				switch (texgen)
+				case BE_NO_BUMP:
+				offset_multiple = 0.f;
+				break;
+				case BE_BRIGHTNESS:
+				case BE_DARKNESS:
+				if( mTexture.notNull() && mTexture->hasGLTexture())
 				{
-					case LLTextureEntry::TEX_GEN_PLANAR:
-						planarProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec);
-						break;
-					case LLTextureEntry::TEX_GEN_SPHERICAL:
-						sphericalProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec);
-						break;
-					case LLTextureEntry::TEX_GEN_CYLINDRICAL:
-						cylindricalProjection(tc, vf.mVertices[i].mNormal, vf.mCenter, vec);
-						break;
-					default:
-						break;
-				}		
+					// Offset by approximately one texel
+					S32 cur_discard = mTexture->getDiscardLevel();
+					S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() );
+					max_size <<= cur_discard;
+					const F32 ARTIFICIAL_OFFSET = 2.f;
+					offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size;
+				}
+				else
+				{
+					offset_multiple = 1.f/256;
+				}
+				break;
+
+				default:  // Standard bumpmap textures.  Assumed to be 256x256
+				offset_multiple = 1.f / 256;
+				break;
 			}
 
-			if (tex_mode && mTextureMatrix)
+			F32 s_scale = 1.f;
+			F32 t_scale = 1.f;
+			if( tep )
 			{
-				LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
-				tmp = tmp * *mTextureMatrix;
-				tc.mV[0] = tmp.mV[0];
-				tc.mV[1] = tmp.mV[1];
+				tep->getScale( &s_scale, &t_scale );
+			}
+			// Use the nudged south when coming from above sun angle, such
+			// that emboss mapping always shows up on the upward faces of cubes when 
+			// it's noon (since a lot of builders build with the sun forced to noon).
+			LLVector3   sun_ray  = gSky.mVOSkyp->mBumpSunDir;
+			LLVector3   moon_ray = gSky.getMoonDirection();
+			LLVector3& primary_light_ray = (sun_ray.mV[VZ] > 0) ? sun_ray : moon_ray;
+
+			bump_s_primary_light_ray.load3((offset_multiple * s_scale * primary_light_ray).mV);
+			bump_t_primary_light_ray.load3((offset_multiple * t_scale * primary_light_ray).mV);
+		}
+
+		U8 texgen = getTextureEntry()->getTexGen();
+		if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+		{ //planar texgen needs binormals
+			mVObjp->getVolume()->genBinormals(f);
+		}
+
+		U8 tex_mode = 0;
+	
+		if (isState(TEXTURE_ANIM))
+		{
+			LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;	
+			tex_mode = vobj->mTexAnimMode;
+
+			if (!tex_mode)
+			{
+				clearState(TEXTURE_ANIM);
 			}
 			else
 			{
-				xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+				os = ot = 0.f;
+				r = 0.f;
+				cos_ang = 1.f;
+				sin_ang = 0.f;
+				ms = mt = 1.f;
+
+				do_xform = false;
 			}
 
-			if(in_atlas)
-			{
-				//
-				//manually calculate tex-coord per vertex for varying address modes.
-				//should be removed if shader can handle this.
-				//
+			if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
+			{ //don't override texture transform during tc bake
+				tex_mode = 0;
+			}
+		}
 
-				S32 int_part = 0 ;
-				switch(mTexture->getAddressMode())
-				{
-				case LLTexUnit::TAM_CLAMP:
-					if(tc.mV[0] < 0.f)
-					{
-						tc.mV[0] = 0.f ;
-					}
-					else if(tc.mV[0] > 1.f)
-					{
-						tc.mV[0] = 1.f;
-					}
+		LLVector4a scalea;
+		scalea.load3(scale.mV);
 
-					if(tc.mV[1] < 0.f)
-					{
-						tc.mV[1] = 0.f ;
-					}
-					else if(tc.mV[1] > 1.f)
-					{
-						tc.mV[1] = 1.f;
-					}
-					break;
-				case LLTexUnit::TAM_MIRROR:
-					if(tc.mV[0] < 0.f)
-					{
-						tc.mV[0] = -tc.mV[0] ;
-					}
-					int_part = (S32)tc.mV[0] ;
-					if(int_part & 1) //odd number
-					{
-						tc.mV[0] = int_part + 1 - tc.mV[0] ;
-					}
-					else //even number
-					{
-						tc.mV[0] -= int_part ;
-					}
+		bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1);
+		bool do_tex_mat = tex_mode && mTextureMatrix;
 
-					if(tc.mV[1] < 0.f)
+		if (!in_atlas && !do_bump)
+		{ //not in atlas or not bump mapped, might be able to do a cheap update
+			if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
+			{
+				if (!do_tex_mat)
+				{
+					if (!do_xform)
 					{
-						tc.mV[1] = -tc.mV[1] ;
+						LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, num_vertices*2);
 					}
-					int_part = (S32)tc.mV[1] ;
-					if(int_part & 1) //odd number
+					else
 					{
-						tc.mV[1] = int_part + 1 - tc.mV[1] ;
+						for (S32 i = 0; i < num_vertices; i++)
+						{	
+							LLVector2 tc(vf.mTexCoords[i]);
+							xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+							*tex_coords++ = tc;	
+						}
 					}
-					else //even number
-					{
-						tc.mV[1] -= int_part ;
+				}
+				else
+				{ //do tex mat, no texgen, no atlas, no bump
+					for (S32 i = 0; i < num_vertices; i++)
+					{	
+						LLVector2 tc(vf.mTexCoords[i]);
+						//LLVector4a& norm = vf.mNormals[i];
+						//LLVector4a& center = *(vf.mCenter);
+
+						LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+						tmp = tmp * *mTextureMatrix;
+						tc.mV[0] = tmp.mV[0];
+						tc.mV[1] = tmp.mV[1];
+						*tex_coords++ = tc;	
 					}
-					break;
-				case LLTexUnit::TAM_WRAP:
-					if(tc.mV[0] > 1.f)
-						tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ;
-					else if(tc.mV[0] < -1.f)
-						tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ;
-
-					if(tc.mV[1] > 1.f)
-						tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ;
-					else if(tc.mV[1] < -1.f)
-						tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ;
-
-					if(tc.mV[0] < 0.f)
-					{
-						tc.mV[0] = 1.0f + tc.mV[0] ;
+				}
+			}
+			else
+			{ //no bump, no atlas, tex gen planar
+				if (do_tex_mat)
+				{
+					for (S32 i = 0; i < num_vertices; i++)
+					{	
+						LLVector2 tc(vf.mTexCoords[i]);
+						LLVector4a& norm = vf.mNormals[i];
+						LLVector4a& center = *(vf.mCenter);
+						LLVector4a vec = vf.mPositions[i];	
+						vec.mul(scalea);
+						planarProjection(tc, norm, center, vec);
+						
+						LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+						tmp = tmp * *mTextureMatrix;
+						tc.mV[0] = tmp.mV[0];
+						tc.mV[1] = tmp.mV[1];
+				
+						*tex_coords++ = tc;	
 					}
-					if(tc.mV[1] < 0.f)
-					{
-						tc.mV[1] = 1.0f + tc.mV[1] ;
+				}
+				else
+				{
+					for (S32 i = 0; i < num_vertices; i++)
+					{	
+						LLVector2 tc(vf.mTexCoords[i]);
+						LLVector4a& norm = vf.mNormals[i];
+						LLVector4a& center = *(vf.mCenter);
+						LLVector4a vec = vf.mPositions[i];	
+						vec.mul(scalea);
+						planarProjection(tc, norm, center, vec);
+						
+						xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+
+						*tex_coords++ = tc;	
 					}
-					break;
-				default:
-					break;
 				}
-			
-				tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
-				tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
 			}
+		}
+		else
+		{ //either bump mapped or in atlas, just do the whole expensive loop
+			for (S32 i = 0; i < num_vertices; i++)
+			{	
+				LLVector2 tc(vf.mTexCoords[i]);
 			
+				LLVector4a& norm = vf.mNormals[i];
+				
+				LLVector4a& center = *(vf.mCenter);
 
-			*tex_coords++ = tc;
-		
-			if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
-			{
-				LLVector3 tangent = vf.mVertices[i].mBinormal % vf.mVertices[i].mNormal;
-
-				LLMatrix3 tangent_to_object;
-				tangent_to_object.setRows(tangent, vf.mVertices[i].mBinormal, vf.mVertices[i].mNormal);
-				LLVector3 binormal = binormal_dir * tangent_to_object;
-				binormal = binormal * mat_normal;
+				if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+				{
+					LLVector4a vec = vf.mPositions[i];
 				
-				if (mDrawablep->isActive())
+					vec.mul(scalea);
+
+					switch (texgen)
+					{
+						case LLTextureEntry::TEX_GEN_PLANAR:
+							planarProjection(tc, norm, center, vec);
+							break;
+						case LLTextureEntry::TEX_GEN_SPHERICAL:
+							sphericalProjection(tc, norm, center, vec);
+							break;
+						case LLTextureEntry::TEX_GEN_CYLINDRICAL:
+							cylindricalProjection(tc, norm, center, vec);
+							break;
+						default:
+							break;
+					}		
+				}
+
+				if (tex_mode && mTextureMatrix)
 				{
-					binormal *= bump_quat;
+					LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+					tmp = tmp * *mTextureMatrix;
+					tc.mV[0] = tmp.mV[0];
+					tc.mV[1] = tmp.mV[1];
+				}
+				else
+				{
+					xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
 				}
 
-				binormal.normVec();
-				tc += LLVector2( bump_s_primary_light_ray * tangent, bump_t_primary_light_ray * binormal );
+				if(in_atlas)
+				{
+					//
+					//manually calculate tex-coord per vertex for varying address modes.
+					//should be removed if shader can handle this.
+					//
+
+					S32 int_part = 0 ;
+					switch(mTexture->getAddressMode())
+					{
+					case LLTexUnit::TAM_CLAMP:
+						if(tc.mV[0] < 0.f)
+						{
+							tc.mV[0] = 0.f ;
+						}
+						else if(tc.mV[0] > 1.f)
+						{
+							tc.mV[0] = 1.f;
+						}
+
+						if(tc.mV[1] < 0.f)
+						{
+							tc.mV[1] = 0.f ;
+						}
+						else if(tc.mV[1] > 1.f)
+						{
+							tc.mV[1] = 1.f;
+						}
+						break;
+					case LLTexUnit::TAM_MIRROR:
+						if(tc.mV[0] < 0.f)
+						{
+							tc.mV[0] = -tc.mV[0] ;
+						}
+						int_part = (S32)tc.mV[0] ;
+						if(int_part & 1) //odd number
+						{
+							tc.mV[0] = int_part + 1 - tc.mV[0] ;
+						}
+						else //even number
+						{
+							tc.mV[0] -= int_part ;
+						}
+
+						if(tc.mV[1] < 0.f)
+						{
+							tc.mV[1] = -tc.mV[1] ;
+						}
+						int_part = (S32)tc.mV[1] ;
+						if(int_part & 1) //odd number
+						{
+							tc.mV[1] = int_part + 1 - tc.mV[1] ;
+						}
+						else //even number
+						{
+							tc.mV[1] -= int_part ;
+						}
+						break;
+					case LLTexUnit::TAM_WRAP:
+						if(tc.mV[0] > 1.f)
+							tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ;
+						else if(tc.mV[0] < -1.f)
+							tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ;
+
+						if(tc.mV[1] > 1.f)
+							tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ;
+						else if(tc.mV[1] < -1.f)
+							tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ;
+
+						if(tc.mV[0] < 0.f)
+						{
+							tc.mV[0] = 1.0f + tc.mV[0] ;
+						}
+						if(tc.mV[1] < 0.f)
+						{
+							tc.mV[1] = 1.0f + tc.mV[1] ;
+						}
+						break;
+					default:
+						break;
+					}
 				
-				*tex_coords2++ = tc;
-			}	
+					tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
+					tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
+				}
+				
+
+				*tex_coords++ = tc;
+				
+				if (bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
+				{
+					LLVector4a tangent;
+					tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]);
+
+					LLMatrix4a tangent_to_object;
+					tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]);
+					LLVector4a t;
+					tangent_to_object.rotate(binormal_dir, t);
+					LLVector4a binormal;
+					mat_normal.rotate(t, binormal);
+						
+					//VECTORIZE THIS
+					if (mDrawablep->isActive())
+					{
+						LLVector3 t;
+						t.set(binormal.getF32());
+						t *= bump_quat;
+						binormal.load3(t.mV);
+					}
+
+					binormal.normalize3fast();
+					tc += LLVector2( bump_s_primary_light_ray.dot3(tangent), bump_t_primary_light_ray.dot3(binormal) );
+					
+					*tex_coords2++ = tc;
+				}	
+			}
 		}
-			
-		if (rebuild_pos)
-		{
-			*vertices++ = vf.mVertices[i].mPosition * mat_vert;
+	}
+
+	if (rebuild_pos)
+	{
+		LLMatrix4a mat_vert;
+		mat_vert.loadu(mat_vert_in);
+
+		LLVector4a* src = vf.mPositions;
+		LLVector4a* dst = vertices;
+
+		LLVector4a* end = dst+num_vertices;
+		do
+		{	
+			mat_vert.affineTransform(*src++, *dst++);
 		}
+		while(dst < end);
+	}
 		
-		if (rebuild_normal)
-		{
-			LLVector3 normal = vf.mVertices[i].mNormal * mat_normal;
-			normal.normVec();
-			
-			*normals++ = normal;
+	if (rebuild_normal)
+	{
+		for (S32 i = 0; i < num_vertices; i++)
+		{	
+			LLVector4a normal;
+			mat_normal.rotate(vf.mNormals[i], normal);
+			normal.normalize3fast();
+			normals[i] = normal;
 		}
+	}
 		
-		if (rebuild_binormal)
-		{
-			LLVector3 binormal = vf.mVertices[i].mBinormal * mat_normal;
-			binormal.normVec();
-			*binormals++ = binormal;
+	if (rebuild_binormal)
+	{
+		for (S32 i = 0; i < num_vertices; i++)
+		{	
+			LLVector4a binormal;
+			mat_normal.rotate(vf.mBinormals[i], binormal);
+			binormal.normalize3fast();
+			binormals[i] = binormal;
 		}
-		
-		if (rebuild_color)
-		{
-			*colors++ = color;		
+	}
+	
+	if (rebuild_weights && vf.mWeights)
+	{
+		LLVector4a::memcpyNonAliased16((F32*) weights, (F32*) vf.mWeights, num_vertices/4);
+	}
+
+	if (rebuild_color)
+	{
+		LLVector4a src;
+
+		src.splat(reinterpret_cast<F32&>(color.mAll));
+
+		F32* dst = (F32*) colors.get();
+		for (S32 i = 0; i < num_vertices; i+=4)
+		{	
+			LLVector4a::copy4a(dst+i, (F32*) &src);
 		}
 	}
 
@@ -1416,20 +1695,31 @@ F32 LLFace::getTextureVirtualSize()
 
 BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
 {
+	//VECTORIZE THIS
 	//get area of circle around face
-	LLVector3 center = getPositionAgent();
-	LLVector3 size = (mExtents[1] - mExtents[0]) * 0.5f;	
+	LLVector4a center;
+	center.load3(getPositionAgent().mV);
+	LLVector4a size;
+	size.setSub(mExtents[1], mExtents[0]);
+	size.mul(0.5f);
+
 	LLViewerCamera* camera = LLViewerCamera::getInstance();
 
-	F32 size_squared = size.lengthSquared() ;
-	LLVector3 lookAt = center - camera->getOrigin();
-	F32 dist = lookAt.normVec() ;	
+	F32 size_squared = size.dot3(size);
+	LLVector4a lookAt;
+	LLVector4a t;
+	t.load3(camera->getOrigin().mV);
+	lookAt.setSub(center, t);
+	F32 dist = lookAt.length3();
+	lookAt.normalize3fast() ;	
 
 	//get area of circle around node
 	F32 app_angle = atanf(fsqrtf(size_squared) / dist);
 	radius = app_angle*LLDrawable::sCurPixelAngle;
 	mPixelArea = radius*radius * 3.14159f;
-	cos_angle_to_view_dir = lookAt * camera->getXAxis() ;
+	LLVector4a x_axis;
+	x_axis.load3(camera->getXAxis().mV);
+	cos_angle_to_view_dir = lookAt.dot3(x_axis);
 
 	//if has media, check if the face is out of the view frustum.	
 	if(hasMedia())
@@ -1445,7 +1735,10 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
 		}
 		else
 		{		
-			if(dist * dist * (lookAt - camera->getXAxis()).lengthSquared() < size_squared)
+			LLVector4a d;
+			d.setSub(lookAt, x_axis);
+
+			if(dist * dist * d.dot3(d) < size_squared)
 			{
 				cos_angle_to_view_dir = 1.0f ;
 			}
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 67dd97e6f7ad0954a8a80e84aadbd2ea2f02fea4..0cd472a2fd851be310246bfd9dbabfd8c4aa576d 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -65,6 +65,17 @@ class LLFace
 {
 public:
 
+	LLFace(const LLFace& rhs)
+	{
+		*this = rhs;
+	}
+
+	const LLFace& operator=(const LLFace& rhs)
+	{
+		llerrs << "Illegal operation!" << llendl;
+		return *this;
+	}
+
 	enum EMasks
 	{
 		LIGHT			= 0x0001,
@@ -73,6 +84,7 @@ class LLFace
 		HUD_RENDER		= 0x0008,
 		USE_FACE_COLOR	= 0x0010,
 		TEXTURE_ANIM	= 0x0020, 
+		RIGGED			= 0x0040,
 	};
 
 	static void initClass();
@@ -138,14 +150,15 @@ class LLFace
 	void			unsetFaceColor(); // switch back to material color
 	const LLColor4&	getFaceColor() const { return mFaceColor; } 
 	const LLColor4& getRenderColor() const;
-	
 
 	//for volumes
 	void updateRebuildFlags();
+	bool canRenderAsMask(); // logic helper
 	BOOL getGeometryVolume(const LLVolume& volume,
 						const S32 &f,
 						const LLMatrix4& mat_vert, const LLMatrix3& mat_normal,
-						const U16 &index_offset);
+						const U16 &index_offset,
+						bool force_rebuild = false);
 
 	// For avatar
 	U16			 getGeometryAvatar(
@@ -164,7 +177,7 @@ class LLFace
 	S32 getColors(LLStrider<LLColor4U> &colors);
 	S32 getIndices(LLStrider<U16> &indices);
 
-	void		setSize(const S32 numVertices, const S32 num_indices = 0);
+	void		setSize(S32 numVertices, S32 num_indices = 0, bool align = false);
 	
 	BOOL		genVolumeBBoxes(const LLVolume &volume, S32 f,
 								   const LLMatrix4& mat, const LLMatrix3& inv_trans_mat, BOOL global_volume = FALSE);
@@ -219,7 +232,9 @@ class LLFace
 	
 	LLVector3		mCenterLocal;
 	LLVector3		mCenterAgent;
-	LLVector3		mExtents[2];
+	
+	LLVector4a*		mExtents;
+	
 	LLVector2		mTexExtents[2];
 	F32				mDistance;
 	LLPointer<LLVertexBuffer> mVertexBuffer;
@@ -232,6 +247,7 @@ class LLFace
 private:
 	friend class LLGeometryManager;
 	friend class LLVolumeGeometryManager;
+	friend class LLDrawPoolAvatar;
 
 	U32			mState;
 	LLFacePool*	mDrawPoolp;
@@ -257,6 +273,8 @@ class LLFace
 	S32			mTEOffset;
 
 	S32			mReferenceIndex;
+	std::vector<S32> mRiggedIndex;
+	 
 	F32			mVSize;
 	F32			mPixelArea;
 
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/llflexibleobject.cpp b/indra/newview/llflexibleobject.cpp
index 561965d0214f4991e78177f7e3e9c1884404005d..8be4e3474881bd7e967b3eccee02c1098f0f9c3d 100644
--- a/indra/newview/llflexibleobject.cpp
+++ b/indra/newview/llflexibleobject.cpp
@@ -97,11 +97,13 @@ void LLVolumeImplFlexible::onParameterChanged(U16 param_type, LLNetworkData *dat
 	}
 }
 
-void LLVolumeImplFlexible::onShift(const LLVector3 &shift_vector)
+void LLVolumeImplFlexible::onShift(const LLVector4a &shift_vector)
 {	
+	//VECTORIZE THIS
+	LLVector3 shift(shift_vector.getF32());
 	for (int section = 0; section < (1<<FLEXIBLE_OBJECT_MAX_SECTIONS)+1; ++section)
 	{
-		mSection[section].mPosition += shift_vector;	
+		mSection[section].mPosition += shift;	
 	}
 }
 
diff --git a/indra/newview/llflexibleobject.h b/indra/newview/llflexibleobject.h
index 811ae24df2a921edb601d3515536cf3969789f25..bdfbded82de98faffb4bebc3a879c6ef923bf65b 100644
--- a/indra/newview/llflexibleobject.h
+++ b/indra/newview/llflexibleobject.h
@@ -90,7 +90,7 @@ class LLVolumeImplFlexible : public LLVolumeInterface
 		void onSetVolume(const LLVolumeParams &volume_params, const S32 detail);
 		void onSetScale(const LLVector3 &scale, BOOL damped);
 		void onParameterChanged(U16 param_type, LLNetworkData *data, BOOL in_use, bool local_origin);
-		void onShift(const LLVector3 &shift_vector);
+		void onShift(const LLVector4a &shift_vector);
 		bool isVolumeUnique() const { return true; }
 		bool isVolumeGlobal() const { return true; }
 		bool isActive() const { return true; }
diff --git a/indra/newview/llfloateranimpreview.cpp b/indra/newview/llfloateranimpreview.cpp
index 043f753e01e90764b72874c10ced321ab985e883..07551e029089828a5f05349384327ee96d089cf4 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/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 8a20712ea851a29dde628ceff372cd4adb465ed7..28fe2a14b770b40751580db7ec35e1a31f36226d 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -69,7 +69,7 @@ const S32 PREVIEW_BORDER_WIDTH = 2;
 const S32 PREVIEW_RESIZE_HANDLE_SIZE = S32(RESIZE_HANDLE_WIDTH * OO_SQRT2) + PREVIEW_BORDER_WIDTH;
 const S32 PREVIEW_HPAD = PREVIEW_RESIZE_HANDLE_SIZE;
 const S32 PREF_BUTTON_HEIGHT = 16 + 7 + 16;
-const S32 PREVIEW_TEXTURE_HEIGHT = 300;
+const S32 PREVIEW_TEXTURE_HEIGHT = 320;
 
 //-----------------------------------------------------------------------------
 // LLFloaterImagePreview()
@@ -864,8 +864,8 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
 	}
 
 	const LLVolumeFace &vf = mVolume->getVolumeFace(0);
-	U32 num_indices = vf.mIndices.size();
-	U32 num_vertices = vf.mVertices.size();
+	U32 num_indices = vf.mNumIndices;
+	U32 num_vertices = vf.mNumVertices;
 
 	mVertexBuffer = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0);
 	mVertexBuffer->allocateBuffer(num_vertices, num_indices, TRUE);
@@ -879,10 +879,16 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
 	mVertexBuffer->getIndexStrider(index_strider);
 
 	// build vertices and normals
+	LLStrider<LLVector3> pos;
+	pos = (LLVector3*) vf.mPositions; pos.setStride(16);
+	LLStrider<LLVector3> norm;
+	norm = (LLVector3*) vf.mNormals; norm.setStride(16);
+		
+
 	for (U32 i = 0; i < num_vertices; i++)
 	{
-		*(vertex_strider++) = vf.mVertices[i].mPosition;
-		LLVector3 normal = vf.mVertices[i].mNormal;
+		*(vertex_strider++) = *pos++;
+		LLVector3 normal = *norm++;
 		normal.normalize();
 		*(normal_strider++) = normal;
 	}
@@ -901,7 +907,6 @@ void LLImagePreviewSculpted::setPreviewTarget(LLImageRaw* imagep, F32 distance)
 BOOL LLImagePreviewSculpted::render()
 {
 	mNeedsUpdate = FALSE;
-
 	LLGLSUIDefault def;
 	LLGLDisable no_blend(GL_BLEND);
 	LLGLEnable cull(GL_CULL_FACE);
@@ -946,7 +951,7 @@ BOOL LLImagePreviewSculpted::render()
 	LLViewerCamera::getInstance()->setPerspective(FALSE, mOrigin.mX, mOrigin.mY, mFullWidth, mFullHeight, FALSE);
 
 	const LLVolumeFace &vf = mVolume->getVolumeFace(0);
-	U32 num_indices = vf.mIndices.size();
+	U32 num_indices = vf.mNumIndices;
 	
 	mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL);
 
@@ -959,7 +964,6 @@ BOOL LLImagePreviewSculpted::render()
 	mVertexBuffer->draw(LLRender::TRIANGLES, num_indices, 0);
 
 	gGL.popMatrix();
-		
 	return TRUE;
 }
 
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 2299cd719c49b6c4a8bcbd6a30cf9e36f4cddff2..32ee9a073cab16fd70b5086e68d91c744746ec60 100644
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -844,7 +844,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
@@ -857,7 +857,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
@@ -903,6 +903,30 @@ 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") &&
+	    LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
+		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 && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO") && (ctrl_deferred->get() ? TRUE : FALSE);
+		
+		ctrl_ssao->setEnabled(enabled);
+
+		enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail");
+
+		ctrl_shadow->setEnabled(enabled);
+	}
+
+
 	// now turn off any features that are unavailable
 	disableUnavailableSettings();
 
@@ -911,12 +935,15 @@ void LLFloaterPreference::refreshEnabledState()
 
 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"))
@@ -928,13 +955,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
@@ -942,10 +978,47 @@ 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 deferred
+	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred"))
+	{
+		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 deferred SSAO
+	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO"))
+	{
+		ctrl_ssao->setEnabled(FALSE);
+		ctrl_ssao->setValue(FALSE);
 	}
 	
+	// disabled deferred shadows
+	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail"))
+	{
+		ctrl_shadows->setEnabled(FALSE);
+		ctrl_shadows->setValue(0);
+	}
+
 	// disabled reflections
-	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderWaterReflections"))
+	if(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionDetail"))
 	{
 		ctrl_reflections->setEnabled(FALSE);
 		ctrl_reflections->setValue(FALSE);
@@ -959,13 +1032,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 129dd55e489c61db6426d4ef39c752932cf00125..468fd685ae0d68048954573b5862400269023295 100644
--- a/indra/newview/llfloatersnapshot.cpp
+++ b/indra/newview/llfloatersnapshot.cpp
@@ -973,7 +973,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);
@@ -996,7 +996,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)
 		{
@@ -1009,17 +1009,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 a42f6ee00fedabee30925a52b518e4e1b5075a11..9f942c041bdec44a950eaae858147d3a89ad4776 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -425,7 +425,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/llhudicon.cpp b/indra/newview/llhudicon.cpp
index 28b0e7356a1e50ef14d929e8a5a88f2ccbde1573..63040904dffd459927f65f773ab230f33d8b149f 100644
--- a/indra/newview/llhudicon.cpp
+++ b/indra/newview/llhudicon.cpp
@@ -39,6 +39,7 @@
 
 #include "llviewerobject.h"
 #include "lldrawable.h"
+#include "llvector4a.h"
 #include "llviewercamera.h"
 #include "llviewertexture.h"
 #include "llviewerwindow.h"
@@ -266,21 +267,42 @@ BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 	LLVector3 x_scale = image_aspect * (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * x_pixel_vec;
 	LLVector3 y_scale = (F32)gViewerWindow->getWindowHeightScaled() * mScale * scale_factor * y_pixel_vec;
 
-	LLVector3 lower_left = icon_position - (x_scale * 0.5f);
-	LLVector3 lower_right = icon_position + (x_scale * 0.5f);
-	LLVector3 upper_left = icon_position - (x_scale * 0.5f) + y_scale;
-	LLVector3 upper_right = icon_position + (x_scale * 0.5f) + y_scale;
+	LLVector4a x_scalea;
+	LLVector4a icon_positiona;
+	LLVector4a y_scalea;
 
-	
-	F32 t = 0.f;
-	LLVector3 dir = end-start;
+	x_scalea.load3(x_scale.mV);
+	x_scalea.mul(0.5f);
+	y_scalea.load3(y_scale.mV);
+
+	icon_positiona.load3(icon_position.mV);
+
+	LLVector4a lower_left;
+	lower_left.setSub(icon_positiona, x_scalea);
+	LLVector4a lower_right;
+	lower_right.setAdd(icon_positiona, x_scalea);
+	LLVector4a upper_left;
+	upper_left.setAdd(lower_left, y_scalea);
+	LLVector4a upper_right;
+	upper_right.setAdd(lower_right, y_scalea);
+
+	LLVector4a enda;
+	enda.load3(end.mV);
+	LLVector4a starta;
+	starta.load3(start.mV);
+	LLVector4a dir;
+	dir.setSub(enda, starta);
+
+	F32 a,b,t;
 
-	if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, start, dir, NULL, NULL, &t, FALSE) ||
-		LLTriangleRayIntersect(upper_left, lower_left, lower_right, start, dir, NULL, NULL, &t, FALSE))
+	if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, starta, dir, a,b,t) ||
+		LLTriangleRayIntersect(upper_left, lower_left, lower_right, starta, dir, a,b,t))
 	{
 		if (intersection)
 		{
-			*intersection = start + dir*t;
+			dir.mul(t);
+			starta.add(dir);
+			*intersection = LLVector3((F32*) &starta.mQ);
 		}
 		return TRUE;
 	}
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 8d1d27444b900fecb8222dc41ce7c93621f3a8b7..7f9eddc837c44ddd36d0a23b54a1e8f8afee9ff9 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -207,10 +207,11 @@ BOOL LLHUDText::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 		}
 
 		LLVector3 dir = end-start;
-		F32 t = 0.f;
+		F32 a,b,t;
 
-		if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, NULL, NULL, &t, FALSE) ||
-			LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, NULL, NULL, &t, FALSE) )
+
+		if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE) ||
+			LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, a, b, t, FALSE) )
 		{
 			if (t <= 1.f)
 			{
@@ -567,6 +568,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 7ce96a6ac14736dd5b279de96b59a170b192db9f..a7d48806646609ef8939a2389c0bc4b992c440c8 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -918,6 +918,16 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
 			// Only should happen for broken links.
 			new_listener = new LLLinkItemBridge(inventory, root, uuid);
 			break;
+#if LL_MESH_ENABLED
+	    case LLAssetType::AT_MESH:
+			if(!(inv_type == LLInventoryType::IT_MESH))
+			{
+				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << LLInventoryType::lookupHumanReadable(inv_type) << " on uuid " << uuid << llendl;
+			}
+			new_listener = new LLMeshBridge(inventory, root, uuid);
+			break;
+#endif
+
 		default:
 			llinfos << "Unhandled asset type (llassetstorage.h): "
 					<< (S32)asset_type << llendl;
@@ -2253,6 +2263,9 @@ LLUIImagePtr LLFolderBridge::getIcon() const
 LLUIImagePtr LLFolderBridge::getIcon(LLFolderType::EType preferred_type)
 {
 	return LLUI::getUIImage(LLViewerFolderType::lookupIconName(preferred_type, FALSE));
+		/*case LLAssetType::AT_MESH:
+			control = "inv_folder_mesh.tga";
+			break;*/
 }
 
 LLUIImagePtr LLFolderBridge::getOpenIcon() const
@@ -2705,6 +2718,9 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
 		case DAD_LINK:
+#if LL_MESH_ENABLED
+		case DAD_MESH:
+#endif
 			accept = dragItemIntoFolder((LLInventoryItem*)cargo_data,
 										drop);
 			break;
@@ -3574,6 +3590,9 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
 			case DAD_BODYPART:
 			case DAD_ANIMATION:
 			case DAD_GESTURE:
+#if LL_MESH_ENABLED
+			case DAD_MESH:
+#endif
 			{
 				LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
 				const LLPermissions& perm = inv_item->getPermissions();
@@ -4751,6 +4770,7 @@ void LLWearableBridge::removeFromAvatar()
 	}
 }
 
+
 // +=================================================+
 // |        LLLinkItemBridge                         |
 // +=================================================+
@@ -4780,6 +4800,65 @@ void LLLinkItemBridge::buildContextMenu(LLMenuGL& menu, U32 flags)
 	hide_context_entries(menu, items, disabled_items);
 }
 
+#if LL_MESH_ENABLED
+// +=================================================+
+// |        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);
+}
+
+#endif
+
 // +=================================================+
 // |        LLLinkBridge                             |
 // +=================================================+
@@ -5086,6 +5165,7 @@ class LLWearableBridgeAction: public LLInvFVBridgeAction
 	{
 		wearOnAvatar();
 	}
+
 	virtual ~LLWearableBridgeAction(){}
 protected:
 	LLWearableBridgeAction(const LLUUID& id,LLInventoryModel* model) : LLInvFVBridgeAction(id,model) {}
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index d97dfd535e5dc17b01369841c2bc445a0612b0b4..3287f310c37edbf01075864ce90ab2383963fdc9 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -47,6 +47,7 @@ class LLMenuGL;
 class LLCallingCardObserver;
 class LLViewerJointAttachment;
 
+
 typedef std::vector<std::string> menuentry_vec_t;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -525,6 +526,27 @@ class LLLinkFolderBridge : public LLItemBridge
 	static std::string sPrefix;
 };
 
+
+#if LL_MESH_ENABLED
+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, 
+		     LLFolderView* root,
+		     const LLUUID& uuid) :
+                       LLItemBridge(inventory, root, uuid) {}
+};
+#endif
+
+
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLInvFVBridgeAction
 //
@@ -555,13 +577,23 @@ class LLInvFVBridgeAction
 	LLInventoryModel* mModel;
 };
 
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-// Recent Inventory Panel related classes
-//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class LLMeshBridgeAction: public LLInvFVBridgeAction
+{
+	friend class LLInvFVBridgeAction;
+public:
+	virtual void	doIt() ;
+	virtual ~LLMeshBridgeAction(){}
+protected:
+	LLMeshBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){}
+
+};
+
+
 
 // Overridden version of the Inventory-Folder-View-Bridge for Folders
 class LLRecentItemsFolderBridge : public LLFolderBridge
 {
+	friend class LLInvFVBridgeAction;
 public:
 	// Creates context menu for Folders related to Recent Inventory Panel.
 	// Uses base logic and than removes from visible items "New..." menu items.
diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp
index c86d463a08844e6afa6ef8cd27a335f0b08b0665..d2fa8a683ea063563a0460c65036016812b97d41 100644
--- a/indra/newview/llinventoryfunctions.cpp
+++ b/indra/newview/llinventoryfunctions.cpp
@@ -686,3 +686,4 @@ void LLOpenFoldersWithSelection::doFolder(LLFolderViewFolder* folder)
 		folder->getParentFolder()->setOpenArrangeRecursively(TRUE, LLFolderViewFolder::RECURSE_UP);
 	}
 }
+
diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp
index ba50081fb2958df1eb4db91a01c1673ea35121fb..91166b0f5b926e1c16d3c00b153165a74ed52c79 100644
--- a/indra/newview/llpanelgroupnotices.cpp
+++ b/indra/newview/llpanelgroupnotices.cpp
@@ -159,6 +159,9 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
 		case DAD_CALLINGCARD:
+#if LL_MESH_ENABLED
+		case DAD_MESH:
+#endif
 		{
 			LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
 			if(gInventory.getItem(inv_item->getUUID())
diff --git a/indra/newview/llpanelobject.cpp b/indra/newview/llpanelobject.cpp
index 30221da12a8d1091007341215cf6511a16a4c207..77f3984ecb3125a2ed7c24e2984cb7ed5d647e48 100644
--- a/indra/newview/llpanelobject.cpp
+++ b/indra/newview/llpanelobject.cpp
@@ -137,6 +137,10 @@ BOOL	LLPanelObject::postBuild()
 	// Phantom checkbox
 	mCheckPhantom = getChild<LLCheckBoxCtrl>("Phantom Checkbox Ctrl");
 	childSetCommitCallback("Phantom Checkbox Ctrl",onCommitPhantom,this);
+
+	// PhysicsShapeType combobox
+	mComboPhysicsShapeType = getChild<LLComboBox>("Physics Shape Type Combo Ctrl");
+	childSetCommitCallback("Physics Shape Type Combo Ctrl", onCommitPhysicsShapeType,this);
 	
 	// Position
 	mLabelPosition = getChild<LLTextBox>("label position");
@@ -320,6 +324,7 @@ LLPanelObject::LLPanelObject()
 	mIsPhysical(FALSE),
 	mIsTemporary(FALSE),
 	mIsPhantom(FALSE),
+	mPhysicsShapeType(0),
 	mCastShadows(TRUE),
 	mSelectedType(MI_BOX),
 	mSculptTextureRevert(LLUUID::null),
@@ -527,6 +532,10 @@ void LLPanelObject::getState( )
 	mCheckPhantom->set( mIsPhantom );
 	mCheckPhantom->setEnabled( roots_selected>0 && editable && !is_flexible );
 
+	mPhysicsShapeType = objectp->getPhysicsShapeType();
+	mComboPhysicsShapeType->setCurrentByIndex(mPhysicsShapeType);
+	mComboPhysicsShapeType->setEnabled(editable);
+
 #if 0 // 1.9.2
 	mCastShadows = root_objectp->flagCastShadows();
 	mCheckCastShadows->set( mCastShadows );
@@ -1232,6 +1241,39 @@ void LLPanelObject::sendIsPhantom()
 	}
 }
 
+#include "llsdutil.h"
+class CostResponder : public LLHTTPClient::Responder
+{
+public:
+	CostResponder(U32 id) { mID = id; }
+	virtual void result(const LLSD& content) { llinfos << ll_pretty_print_sd(content) << llendl; }
+
+	U32 mID;
+};
+
+void LLPanelObject::sendPhysicsShapeType()
+{
+	U8 value = (U8)mComboPhysicsShapeType->getCurrentIndex();
+	if (mPhysicsShapeType != value)
+	{
+		LLSelectMgr::getInstance()->selectionUpdatePhysicsShapeType(value);
+		mPhysicsShapeType = value;
+		
+		llinfos << "update physics shape type sent" << llendl;
+	}
+	else
+	{
+		llinfos << "update physics shape type not changed" << llendl;
+	}
+
+	std::string url = gAgent.getRegion()->getCapability("GetObjectCost");
+	LLSD body = LLSD::emptyArray();
+	
+	body.append(LLSelectMgr::getInstance()->getSelection()->getFirstObject()->getID());
+	
+	LLHTTPClient::post( url, body, new CostResponder(body[0].asInteger()) );
+}
+
 void LLPanelObject::sendCastShadows()
 {
 	BOOL value = mCheckCastShadows->get();
@@ -1905,6 +1947,8 @@ void LLPanelObject::clearCtrls()
 	mCheckTemporary	->setEnabled( FALSE );
 	mCheckPhantom	->set(FALSE);
 	mCheckPhantom	->setEnabled( FALSE );
+	mComboPhysicsShapeType->setCurrentByIndex(0);
+	mComboPhysicsShapeType->setEnabled(FALSE);
 #if 0 // 1.9.2
 	mCheckCastShadows->set(FALSE);
 	mCheckCastShadows->setEnabled( FALSE );
@@ -1999,6 +2043,13 @@ void LLPanelObject::onCommitPhantom( LLUICtrl* ctrl, void* userdata )
 	self->sendIsPhantom();
 }
 
+// static
+void LLPanelObject::onCommitPhysicsShapeType(LLUICtrl* ctrl, void* userdata )
+{
+	LLPanelObject* self = (LLPanelObject*) userdata;
+	self->sendPhysicsShapeType();
+}
+
 // static
 void LLPanelObject::onCommitCastShadows( LLUICtrl* ctrl, void* userdata )
 {
diff --git a/indra/newview/llpanelobject.h b/indra/newview/llpanelobject.h
index 58d9fe9b76e6a82b719e7aeab63a1e3a84b6ffb4..7f368c38c70f0c95aab3fe9f20f79c13e8505d98 100644
--- a/indra/newview/llpanelobject.h
+++ b/indra/newview/llpanelobject.h
@@ -65,13 +65,14 @@ class LLPanelObject : public LLPanel
 	static bool		precommitValidate(const LLSD& data);
 	
 	static void		onCommitLock(LLUICtrl *ctrl, void *data);
-	static void 	onCommitPosition(		LLUICtrl* ctrl, void* userdata);
-	static void 	onCommitScale(			LLUICtrl* ctrl, void* userdata);
-	static void 	onCommitRotation(		LLUICtrl* ctrl, void* userdata);
-	static void 	onCommitPhysics(		LLUICtrl* ctrl, void* userdata);
-	static void 	onCommitTemporary(		LLUICtrl* ctrl, void* userdata);
-	static void 	onCommitPhantom(		LLUICtrl* ctrl, void* userdata);
-	static void 	onCommitCastShadows(	LLUICtrl* ctrl, void* userdata);
+	static void 	onCommitPosition(			LLUICtrl* ctrl, void* userdata);
+	static void 	onCommitScale(				LLUICtrl* ctrl, void* userdata);
+	static void 	onCommitRotation(			LLUICtrl* ctrl, void* userdata);
+	static void 	onCommitPhysics(			LLUICtrl* ctrl, void* userdata);
+	static void 	onCommitTemporary(			LLUICtrl* ctrl, void* userdata);
+	static void 	onCommitPhantom(			LLUICtrl* ctrl, void* userdata);
+	static void     onCommitPhysicsShapeType(   LLUICtrl* ctrl, void* userdata);
+	static void 	onCommitCastShadows(		LLUICtrl* ctrl, void* userdata);
 
 	static void 	onCommitParametric(LLUICtrl* ctrl, void* userdata);
 
@@ -93,6 +94,7 @@ class LLPanelObject : public LLPanel
 	void			sendIsPhysical();
 	void			sendIsTemporary();
 	void			sendIsPhantom();
+	void            sendPhysicsShapeType();
 	void			sendCastShadows();
 	void            sendSculpt();
 	
@@ -165,8 +167,9 @@ class LLPanelObject : public LLPanel
 	LLCheckBoxCtrl	*mCheckPhysics;
 	LLCheckBoxCtrl	*mCheckTemporary;
 	LLCheckBoxCtrl	*mCheckPhantom;
+	LLComboBox      *mComboPhysicsShapeType;
 	LLCheckBoxCtrl	*mCheckCastShadows;
-
+	
 	LLTextureCtrl   *mCtrlSculptTexture;
 	LLTextBox       *mLabelSculptType;
 	LLComboBox      *mCtrlSculptType;
@@ -177,6 +180,7 @@ class LLPanelObject : public LLPanel
 	BOOL			mIsPhysical;			// to avoid sending "physical" when not changed
 	BOOL			mIsTemporary;			// to avoid sending "temporary" when not changed
 	BOOL			mIsPhantom;				// to avoid sending "phantom" when not changed
+	U8              mPhysicsShapeType;		// to avoid sending "physics shape type" when not changed
 	BOOL			mCastShadows;			// to avoid sending "cast shadows" when not changed
 	S32				mSelectedType;			// So we know what selected type we last were
 
diff --git a/indra/newview/llpanelobjectinventory.cpp b/indra/newview/llpanelobjectinventory.cpp
index ad3a5c23804daff2e9ebf7df4654ca9745c9c655..a06b66dab0734b7f4375bde115fa61b5ee6c0c86 100644
--- a/indra/newview/llpanelobjectinventory.cpp
+++ b/indra/newview/llpanelobjectinventory.cpp
@@ -819,6 +819,9 @@ BOOL LLTaskCategoryBridge::dragOrDrop(MASK mask, BOOL drop,
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
 		case DAD_CALLINGCARD:
+#if LL_MESH_ENABLED
+		case DAD_MESH:
+#endif
 			accept = LLToolDragAndDrop::isInventoryDropAcceptable(object, (LLViewerInventoryItem*)cargo_data);
 			if(accept && drop)
 			{
@@ -1239,6 +1242,119 @@ LLUIImagePtr LLTaskWearableBridge::getIcon() const
 	return LLInventoryIcon::getIcon(mAssetType, mInventoryType, mFlags, FALSE );
 }
 
+#if LL_MESH_ENABLED
+///----------------------------------------------------------------------------
+/// 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(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 LLInventoryIcon::getIcon(LLAssetType::AT_MESH, LLInventoryType::IT_MESH, 0, FALSE);
+}
+
+void LLTaskMeshBridge::openItem()
+{
+	// open mesh
+}
+
+
+// virtual
+void LLTaskMeshBridge::performAction(LLInventoryModel* model, std::string action)
+{
+	if (action == "mesh action")
+	{
+		LLInventoryItem* item = findItem();
+		if(item)
+		{
+			// do action
+		}
+	}
+	LLTaskInvFVBridge::performAction(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);
+}
+
+#endif
 
 ///----------------------------------------------------------------------------
 /// LLTaskInvFVBridge impl
@@ -1319,6 +1435,13 @@ LLTaskInvFVBridge* LLTaskInvFVBridge::createObjectBridge(LLPanelObjectInventory*
 						 object->getUUID(),
 						 object->getName());
 		break;
+#if LL_MESH_ENABLED
+	case LLAssetType::AT_MESH:
+		new_bridge = new LLTaskMeshBridge(panel,
+										  object->getUUID(),
+										  object->getName());
+		break;
+#endif
 	default:
 		llinfos << "Unhandled inventory type (llassetstorage.h): "
 				<< (S32)type << llendl;
diff --git a/indra/newview/llpanelprimmediacontrols.cpp b/indra/newview/llpanelprimmediacontrols.cpp
index 0648d996851e5e56a3a3fffb58e7ef8d252ce6a5..98fbebbc5d2bc0d54a04bc539bf4d11872b3ecb9 100644
--- a/indra/newview/llpanelprimmediacontrols.cpp
+++ b/indra/newview/llpanelprimmediacontrols.cpp
@@ -65,6 +65,7 @@
 #include "llweb.h"
 #include "llwindow.h"
 #include "llfloatertools.h"  // to enable hide if build tools are up
+#include "llvector4a.h"
 
 // Functions pulled from pipeline.cpp
 glh::matrix4f glh_get_current_modelview();
@@ -574,7 +575,9 @@ void LLPanelPrimMediaControls::updateShape()
 		{
 			const LLVolumeFace& vf = volume->getVolumeFace(mTargetObjectFace);
 			
-			const LLVector3* ext = vf.mExtents;
+			LLVector3 ext[2];
+			ext[0].set(vf.mExtents[0].getF32());
+			ext[1].set(vf.mExtents[1].getF32());
 			
 			LLVector3 center = (ext[0]+ext[1])*0.5f;
 			LLVector3 size = (ext[1]-ext[0])*0.5f;
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/llpolymesh.cpp b/indra/newview/llpolymesh.cpp
index d5a2d66bcfc6444273b7e49d2d9644d50e04ef05..d10e4fee3a0ad3911a8512ff63d824e8a296f955 100644
--- a/indra/newview/llpolymesh.cpp
+++ b/indra/newview/llpolymesh.cpp
@@ -35,7 +35,8 @@
 //-----------------------------------------------------------------------------
 #include "llviewerprecompiledheaders.h"
 
-#include "llpolymesh.h"
+#include "llfasttimer.h"
+#include "llmemory.h"
 
 #include "llviewercontrol.h"
 #include "llxmltree.h"
@@ -45,7 +46,7 @@
 #include "llvolume.h"
 #include "llendianswizzle.h"
 
-#include "llfasttimer.h"
+#include "llpolymesh.h"
 
 #define HEADER_ASCII "Linden Mesh 1.0"
 #define HEADER_BINARY "Linden Binary Mesh 1.0"
@@ -140,7 +141,7 @@ void LLPolyMeshSharedData::freeMeshData()
 		delete [] mDetailTexCoords;
 		mDetailTexCoords = NULL;
 
-		delete [] mWeights;
+		ll_aligned_free_16(mWeights);
 		mWeights = NULL;
 	}
 
@@ -230,7 +231,7 @@ BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices )
 	mBaseBinormals = new LLVector3[ numVertices ];
 	mTexCoords = new LLVector2[ numVertices ];
 	mDetailTexCoords = new LLVector2[ numVertices ];
-	mWeights = new F32[ numVertices ];
+	mWeights = (F32*) ll_aligned_malloc_16((numVertices*sizeof(F32)+0xF) & ~0xF);
 	for (i = 0; i < numVertices; i++)
 	{
 		mWeights[i] = 0.f;
@@ -708,20 +709,29 @@ LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_
 		mClothingWeights = reference_mesh->mClothingWeights;
 	}
 	else
-	{
+	{ 	 
 #if 1	// Allocate memory without initializing every vector
 		// NOTE: This makes asusmptions about the size of LLVector[234]
 		int nverts = mSharedData->mNumVertices;
-		int nfloats = nverts * (3*5 + 2 + 4);
-		mVertexData = new F32[nfloats];
+		int nfloats = nverts * (2*4 + 3*3 + 2 + 4);
+
+		//use aligned vertex data to make LLPolyMesh SSE friendly
+		mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4);
 		int offset = 0;
-		mCoords = 				(LLVector3*)(mVertexData + offset); offset += 3*nverts;
-		mNormals = 				(LLVector3*)(mVertexData + offset); offset += 3*nverts;
-		mScaledNormals = 		(LLVector3*)(mVertexData + offset); offset += 3*nverts;
-		mBinormals = 			(LLVector3*)(mVertexData + offset); offset += 3*nverts;
-		mScaledBinormals = 		(LLVector3*)(mVertexData + offset); offset += 3*nverts;
-		mTexCoords = 			(LLVector2*)(mVertexData + offset); offset += 2*nverts;
-		mClothingWeights = 	(LLVector4*)(mVertexData + offset); offset += 4*nverts;
+
+		//all members must be 16-byte aligned except the last 3
+		mCoords				= 	(LLVector4*)(mVertexData + offset); offset += 4*nverts;
+		mNormals			=	(LLVector4*)(mVertexData + offset); offset += 4*nverts;
+		mClothingWeights	= 	(LLVector4*)(mVertexData + offset); offset += 4*nverts;
+		mTexCoords			= 	(LLVector2*)(mVertexData + offset); offset += 2*nverts;
+
+		// these members don't need to be 16-byte aligned, but the first one might be
+		// read during an aligned memcpy of mTexCoords
+		mScaledNormals		=	(LLVector3*)(mVertexData + offset); offset += 3*nverts;
+		mBinormals			=	(LLVector3*)(mVertexData + offset); offset += 3*nverts;
+		mScaledBinormals	=	(LLVector3*)(mVertexData + offset); offset += 3*nverts;
+		
+		
 #else
 		mCoords = new LLVector3[mSharedData->mNumVertices];
 		mNormals = new LLVector3[mSharedData->mNumVertices];
@@ -757,7 +767,7 @@ LLPolyMesh::~LLPolyMesh()
 	delete [] mClothingWeights;
 	delete [] mTexCoords;
 #else
-	delete [] mVertexData;
+	ll_aligned_free_16(mVertexData);
 #endif
 }
 
@@ -864,7 +874,7 @@ void LLPolyMesh::dumpDiagInfo()
 //-----------------------------------------------------------------------------
 // getWritableCoords()
 //-----------------------------------------------------------------------------
-LLVector3 *LLPolyMesh::getWritableCoords()
+LLVector4 *LLPolyMesh::getWritableCoords()
 {
 	return mCoords;
 }
@@ -872,7 +882,7 @@ LLVector3 *LLPolyMesh::getWritableCoords()
 //-----------------------------------------------------------------------------
 // getWritableNormals()
 //-----------------------------------------------------------------------------
-LLVector3 *LLPolyMesh::getWritableNormals()
+LLVector4 *LLPolyMesh::getWritableNormals()
 {
 	return mNormals;
 }
@@ -927,8 +937,12 @@ void LLPolyMesh::initializeForMorph()
 	if (!mSharedData)
 		return;
 
-	memcpy(mCoords, mSharedData->mBaseCoords, sizeof(LLVector3) * mSharedData->mNumVertices);	/*Flawfinder: ignore*/
-	memcpy(mNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices);	/*Flawfinder: ignore*/
+	for (U32 i = 0; i < mSharedData->mNumVertices; ++i)
+	{
+		mCoords[i] = LLVector4(mSharedData->mBaseCoords[i]);
+		mNormals[i] = LLVector4(mSharedData->mBaseNormals[i]);
+	}
+
 	memcpy(mScaledNormals, mSharedData->mBaseNormals, sizeof(LLVector3) * mSharedData->mNumVertices);	/*Flawfinder: ignore*/
 	memcpy(mBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices);	/*Flawfinder: ignore*/
 	memcpy(mScaledBinormals, mSharedData->mBaseBinormals, sizeof(LLVector3) * mSharedData->mNumVertices);		/*Flawfinder: ignore*/
diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h
index c2e5451dfe3f085ea21ef1ad7dfffe3ad2381ace..d86568a1ba76eb9e8f1711540c5010805cfce1d0 100644
--- a/indra/newview/llpolymesh.h
+++ b/indra/newview/llpolymesh.h
@@ -223,15 +223,15 @@ class LLPolyMesh
 	}
 
 	// Get coords
-	const LLVector3	*getCoords() const{
+	const LLVector4	*getCoords() const{
 		return mCoords;
 	}
 
 	// non const version
-	LLVector3 *getWritableCoords();
+	LLVector4 *getWritableCoords();
 
 	// Get normals
-	const LLVector3	*getNormals() const{ 
+	const LLVector4	*getNormals() const{ 
 		return mNormals; 
 	}
 
@@ -253,7 +253,7 @@ class LLPolyMesh
 	}
 
 	// intermediate morphed normals and output normals
-	LLVector3 *getWritableNormals();
+	LLVector4 *getWritableNormals();
 	LLVector3 *getScaledNormals();
 
 	LLVector3 *getWritableBinormals();
@@ -347,11 +347,11 @@ class LLPolyMesh
 	// Single array of floats for allocation / deletion
 	F32						*mVertexData;
 	// deformed vertices (resulting from application of morph targets)
-	LLVector3				*mCoords;
+	LLVector4				*mCoords;
 	// deformed normals (resulting from application of morph targets)
 	LLVector3				*mScaledNormals;
 	// output normals (after normalization)
-	LLVector3				*mNormals;
+	LLVector4				*mNormals;
 	// deformed binormals (resulting from application of morph targets)
 	LLVector3				*mScaledBinormals;
 	// output binormals (after normalization)
diff --git a/indra/newview/llpolymorph.cpp b/indra/newview/llpolymorph.cpp
index 80983cad2434d0be8002ce9834a1973fc8f8d5cb..2058c351c4ea8fefdcb4cbd84a5cdba8233a1079 100644
--- a/indra/newview/llpolymorph.cpp
+++ b/indra/newview/llpolymorph.cpp
@@ -461,10 +461,10 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 	if (delta_weight != 0.f)
 	{
 		llassert(!mMesh->isLOD());
-		LLVector3 *coords = mMesh->getWritableCoords();
+		LLVector4 *coords = mMesh->getWritableCoords();
 
 		LLVector3 *scaled_normals = mMesh->getScaledNormals();
-		LLVector3 *normals = mMesh->getWritableNormals();
+		LLVector4 *normals = mMesh->getWritableNormals();
 
 		LLVector3 *scaled_binormals = mMesh->getScaledBinormals();
 		LLVector3 *binormals = mMesh->getWritableBinormals();
@@ -484,7 +484,8 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 				maskWeight = maskWeightArray[vert_index_morph];
 			}
 
-			coords[vert_index_mesh] += mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight;
+			coords[vert_index_mesh] += LLVector4(mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight);
+
 			if (getInfo()->mIsClothingMorph && clothing_weights)
 			{
 				LLVector3 clothing_offset = mMorphData->mCoords[vert_index_morph] * delta_weight * maskWeight;
@@ -499,7 +500,7 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 			scaled_normals[vert_index_mesh] += mMorphData->mNormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR;
 			LLVector3 normalized_normal = scaled_normals[vert_index_mesh];
 			normalized_normal.normVec();
-			normals[vert_index_mesh] = normalized_normal;
+			normals[vert_index_mesh] = LLVector4(normalized_normal);
 
 			// calculate new binormals
 			scaled_binormals[vert_index_mesh] += mMorphData->mBinormals[vert_index_morph] * delta_weight * maskWeight * NORMAL_SOFTEN_FACTOR;
@@ -548,7 +549,7 @@ void	LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3
 
 		if (maskWeights)
 		{
-			LLVector3 *coords = mMesh->getWritableCoords();
+			LLVector4 *coords = mMesh->getWritableCoords();
 			LLVector3 *scaled_normals = mMesh->getScaledNormals();
 			LLVector3 *scaled_binormals = mMesh->getScaledBinormals();
 			LLVector2 *tex_coords = mMesh->getWritableTexCoords();
@@ -559,7 +560,7 @@ void	LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S3
 				S32 out_vert = mMorphData->mVertexIndices[vert];
 
 				// remove effect of existing masked morph
-				coords[out_vert] -= mMorphData->mCoords[vert] * lastMaskWeight;
+				coords[out_vert] -= LLVector4(mMorphData->mCoords[vert]) * lastMaskWeight;
 				scaled_normals[out_vert] -= mMorphData->mNormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR;
 				scaled_binormals[out_vert] -= mMorphData->mBinormals[vert] * lastMaskWeight * NORMAL_SOFTEN_FACTOR;
 				tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight;
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index af16b962e62b3b30bb1c56f85ae1c4f28577850c..0ce7ffb0776d71e9fed5bb6d59847062f2fc99e3 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()
 //-----------------------------------------------------------------------------
@@ -1100,8 +1100,8 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &
 		mGridRotation = first_grid_object->getRenderRotation();
 		LLVector3 first_grid_obj_pos = first_grid_object->getRenderPosition();
 
-		LLVector3 min_extents(F32_MAX, F32_MAX, F32_MAX);
-		LLVector3 max_extents(-F32_MAX, -F32_MAX, -F32_MAX);
+		LLVector4a min_extents(F32_MAX);
+		LLVector4a max_extents(-F32_MAX);
 		BOOL grid_changed = FALSE;
 		for (LLObjectSelection::iterator iter = mGridObjects.begin();
 			 iter != mGridObjects.end(); ++iter)
@@ -1110,7 +1110,7 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &
 			LLDrawable* drawable = object->mDrawable;
 			if (drawable)
 			{
-				const LLVector3* ext = drawable->getSpatialExtents();
+				const LLVector4a* ext = drawable->getSpatialExtents();
 				update_min_max(min_extents, max_extents, ext[0]);
 				update_min_max(min_extents, max_extents, ext[1]);
 				grid_changed = TRUE;
@@ -1118,13 +1118,19 @@ void LLSelectMgr::getGrid(LLVector3& origin, LLQuaternion &rotation, LLVector3 &
 		}
 		if (grid_changed)
 		{
-			mGridOrigin = lerp(min_extents, max_extents, 0.5f);
+			LLVector4a center, size;
+			center.setAdd(min_extents, max_extents);
+			center.mul(0.5f);
+			size.setSub(max_extents, min_extents);
+			size.mul(0.5f);
+
+			mGridOrigin.set(center.getF32());
 			LLDrawable* drawable = first_grid_object->mDrawable;
 			if (drawable && drawable->isActive())
 			{
 				mGridOrigin = mGridOrigin * first_grid_object->getRenderMatrix();
 			}
-			mGridScale = (max_extents - min_extents) * 0.5f;
+			mGridScale.set(size.getF32());
 		}
 	}
 	else // GRID_MODE_WORLD or just plain default
@@ -3931,6 +3937,28 @@ void LLSelectMgr::selectionUpdateCastShadows(BOOL cast_shadows)
 	getSelection()->applyToObjects(&func);	
 }
 
+struct LLSelectMgrApplyPhysicsShapeType : public LLSelectedObjectFunctor
+{
+	LLSelectMgrApplyPhysicsShapeType(U8 value) : mValue(value) {}
+	U8 mValue;
+	virtual bool apply(LLViewerObject* object)
+	{
+		if ( object->permModify() ) 	// preemptive permissions check
+		{
+			object->setPhysicsShapeType( mValue );
+			object->updateFlags();
+		}
+		return true;
+	}
+};
+
+
+void LLSelectMgr::selectionUpdatePhysicsShapeType(U8 type)
+{
+	llwarns << "physics shape type ->" << (U32)type << llendl;
+	LLSelectMgrApplyPhysicsShapeType func(type);
+	getSelection()->applyToObjects(&func);	
+}
 
 //----------------------------------------------------------------------
 // Helpful packing functions for sendObjectMessage()
@@ -4620,7 +4648,6 @@ void LLSelectMgr::processForceObjectSelect(LLMessageSystem* msg, void**)
 	LLSelectMgr::getInstance()->highlightObjectAndFamily(objects);
 }
 
-
 extern LLGLdouble	gGLModelView[16];
 
 void LLSelectMgr::updateSilhouettes()
@@ -5348,6 +5375,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 +5464,13 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 		return;
 	}
 
+	LLVOVolume* vobj = drawable->getVOVolume();
+	if (vobj && vobj->isMesh())
+	{
+		renderOneWireframe(color);
+		return;
+	}
+
 	if (!mSilhouetteExists)
 	{
 		return;
@@ -6054,10 +6160,34 @@ 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 LL_MESH_ENABLED
+	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;
+				}
+			}
+
+		}
+	}
+#endif
+
 	return count;
 }
 
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index d315f40ff3ba07da0865f523837bee111447674e..34f2082b825dd78328ded47218d6f919712a2516 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();
 
@@ -483,6 +484,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	void selectionUpdatePhysics(BOOL use_physics);
 	void selectionUpdateTemporary(BOOL is_temporary);
 	void selectionUpdatePhantom(BOOL is_ghost);
+	void selectionUpdatePhysicsShapeType(U8 type);
 	void selectionUpdateCastShadows(BOOL cast_shadows);
 	void selectionDump();
 
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index d6e9256feea2af8ad1461e46505e914117135fb2..bda59f49d1f0f2833d1b4a71083011d916b33f47 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -38,6 +38,7 @@
 #include "llviewerobjectlist.h"
 #include "llvovolume.h"
 #include "llvolume.h"
+#include "llvolumeoctree.h"
 #include "llviewercamera.h"
 #include "llface.h"
 #include "llviewercontrol.h"
@@ -101,23 +102,6 @@ void sg_assert(BOOL expr)
 #endif
 }
 
-#if LL_DEBUG
-void validate_drawable(LLDrawable* drawablep)
-{
-	F64 rad = drawablep->getBinRadius();
-	const LLVector3* ext = drawablep->getSpatialExtents();
-
-	if (rad < 0 || rad > 4096 ||
-		(ext[1]-ext[0]).magVec() > 4096)
-	{
-		llwarns << "Invalid drawable found in octree." << llendl;
-	}
-}
-#else
-#define validate_drawable(x)
-#endif
-
-
 S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad)
 {
 	return AABBSphereIntersectR2(min, max, origin, rad*rad);
@@ -157,6 +141,55 @@ S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVe
 }
 
 
+S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad)
+{
+	return AABBSphereIntersectR2(min, max, origin, rad*rad);
+}
+
+S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &r)
+{
+	F32 d = 0.f;
+	F32 t;
+	
+	LLVector4a origina;
+	origina.load3(origin.mV);
+
+	LLVector4a v;
+	v.setSub(min, origina);
+	
+	if (v.dot3(v) < r)
+	{
+		v.setSub(max, origina);
+		if (v.dot3(v) < r)
+		{
+			return 2;
+		}
+	}
+
+
+	for (U32 i = 0; i < 3; i++)
+	{
+		if (origin.mV[i] < min[i])
+		{
+			t = min[i] - origin.mV[i];
+			d += t*t;
+		}
+		else if (origin.mV[i] > max[i])
+		{
+			t = origin.mV[i] - max[i];
+			d += t*t;
+		}
+
+		if (d > r)
+		{
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+
 typedef enum
 {
 	b000 = 0x00,
@@ -174,42 +207,31 @@ typedef enum
 //gives you a triangle fan index array
 static U8 sOcclusionIndices[] =
 {
-	 // 000
+	 //000
 		b111, b110, b010, b011, b001, b101, b100, b110,
-	//001 
-		b110, b000, b010, b011, b111, b101, b100, b000,
+	 //001 
+		b011, b010, b000, b001, b101, b111, b110, b010,
 	 //010
 		b101, b100, b110, b111, b011, b001, b000, b100,
 	 //011 
-		b100, b010, b110, b111, b101, b001, b000, b010,
-	//100 
-		b011, b010, b000, b001, b101, b111, b110, b010,
+		b001, b000, b100, b101, b111, b011, b010, b000,
+	 //100 
+		b110, b000, b010, b011, b111, b101, b100, b000,
 	 //101 
 		b010, b100, b000, b001, b011, b111, b110, b100,
 	 //110
-		b001, b000, b100, b101, b111, b011, b010, b000,
+		b100, b010, b110, b111, b101, b001, b000, b010,
 	 //111
 		b000, b110, b100, b101, b001, b011, b010, b110,
 };
 
-U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center)
+U8* get_box_fan_indices(LLCamera* camera, const LLVector4a& center)
 {
-	LLVector3 d = center - camera->getOrigin();
-
-	U8 cypher = 0;
-	if (d.mV[0] > 0)
-	{
-		cypher |= b100;
-	}
-	if (d.mV[1] > 0)
-	{
-		cypher |= b010;
-	}
-	if (d.mV[2] > 0)
-	{
-		cypher |= b001;
-	}
+	LLVector4a origin;
+	origin.load3(camera->getOrigin().mV);
 
+	S32 cypher = center.greaterThan4(origin).getComparisonMask() & 0x7;
+	
 	return sOcclusionIndices+cypher*8;
 }
 						
@@ -217,33 +239,49 @@ void LLSpatialGroup::buildOcclusion()
 {
 	if (!mOcclusionVerts)
 	{
-		mOcclusionVerts = new F32[8*3];
+		mOcclusionVerts = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*8);
 	}
 
-	LLVector3 r = mBounds[1] + LLVector3(SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE, SG_OCCLUSION_FUDGE);
+	LLVector4a fudge;
+	fudge.splat(SG_OCCLUSION_FUDGE);
 
-	for (U32 k = 0; k < 3; k++)
-	{
-		r.mV[k] = llmin(mBounds[1].mV[k]+0.25f, r.mV[k]);
-	}
+	LLVector4a r;
+	r.setAdd(mBounds[1], fudge);
+
+	LLVector4a r2;
+	r2.splat(0.25f);
+	r2.add(mBounds[1]);
 
-	F32* v = mOcclusionVerts;
-	F32* c = mBounds[0].mV;
-	F32* s = r.mV;
+	r.setMin(r2);
+
+	LLVector4a* v = mOcclusionVerts;
+	const LLVector4a& c = mBounds[0];
+	const LLVector4a& s = r;
 	
+	static const LLVector4a octant[] =
+	{
+		LLVector4a(-1.f, -1.f, -1.f),
+		LLVector4a(-1.f, -1.f, 1.f),
+		LLVector4a(-1.f, 1.f, -1.f),
+		LLVector4a(-1.f, 1.f, 1.f),
+
+		LLVector4a(1.f, -1.f, -1.f),
+		LLVector4a(1.f, -1.f, 1.f),
+		LLVector4a(1.f, 1.f, -1.f),
+		LLVector4a(1.f, 1.f, 1.f),
+	};
+
 	//vertex positions are encoded so the 3 bits of their vertex index 
 	//correspond to their axis facing, with bit position 3,2,1 matching
 	//axis facing x,y,z, bit set meaning positive facing, bit clear 
 	//meaning negative facing
-	v[0] = c[0]-s[0]; v[1]  = c[1]-s[1]; v[2]  = c[2]-s[2];  // 0 - 0000 
-	v[3] = c[0]-s[0]; v[4]  = c[1]-s[1]; v[5]  = c[2]+s[2];  // 1 - 0001
-	v[6] = c[0]-s[0]; v[7]  = c[1]+s[1]; v[8]  = c[2]-s[2];  // 2 - 0010
-	v[9] = c[0]-s[0]; v[10] = c[1]+s[1]; v[11] = c[2]+s[2];  // 3 - 0011
-																					   
-	v[12] = c[0]+s[0]; v[13] = c[1]-s[1]; v[14] = c[2]-s[2]; // 4 - 0100
-	v[15] = c[0]+s[0]; v[16] = c[1]-s[1]; v[17] = c[2]+s[2]; // 5 - 0101
-	v[18] = c[0]+s[0]; v[19] = c[1]+s[1]; v[20] = c[2]-s[2]; // 6 - 0110
-	v[21] = c[0]+s[0]; v[22] = c[1]+s[1]; v[23] = c[2]+s[2]; // 7 - 0111
+	
+	for (S32 i = 0; i < 8; ++i)
+	{
+		v[i] = s;
+		v[i].mul(octant[i]);
+		v[i].add(c);
+	}
 
 	clearState(LLSpatialGroup::OCCLUSION_DIRTY);
 }
@@ -287,6 +325,11 @@ LLSpatialGroup::~LLSpatialGroup()
 		llerrs << "Illegal deletion of LLSpatialGroup!" << llendl;
 	}*/
 
+	if (gDebugGL)
+	{
+		gPipeline.checkReferences(this);
+	}
+
 	if (isState(DEAD))
 	{
 		sZombieGroups--;
@@ -299,11 +342,13 @@ LLSpatialGroup::~LLSpatialGroup()
 		sQueryPool.release(mOcclusionQuery[LLViewerCamera::sCurCameraID]);
 	}
 
-	delete [] mOcclusionVerts;
+	ll_aligned_free_16(mOcclusionVerts);
 
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	clearDrawMap();
 	clearAtlasList() ;
+
+	ll_aligned_free_16(mBounds);
 }
 
 BOOL LLSpatialGroup::hasAtlas(LLTextureAtlas* atlasp)
@@ -455,8 +500,10 @@ void LLSpatialGroup::validate()
 	sg_assert(!isState(DIRTY));
 	sg_assert(!isDead());
 
-	LLVector3 myMin = mBounds[0] - mBounds[1];
-	LLVector3 myMax = mBounds[0] + mBounds[1];
+	LLVector4a myMin;
+	myMin.setSub(mBounds[0], mBounds[1]);
+	LLVector4a myMax;
+	myMax.setAdd(mBounds[0], mBounds[1]);
 
 	validateDrawMap();
 
@@ -488,16 +535,18 @@ void LLSpatialGroup::validate()
 		group->validate();
 		
 		//ensure all children are enclosed in this node
-		LLVector3 center = group->mBounds[0];
-		LLVector3 size = group->mBounds[1];
+		LLVector4a center = group->mBounds[0];
+		LLVector4a size = group->mBounds[1];
 		
-		LLVector3 min = center - size;
-		LLVector3 max = center + size;
+		LLVector4a min;
+		min.setSub(center, size);
+		LLVector4a max;
+		max.setAdd(center, size);
 		
 		for (U32 j = 0; j < 3; j++)
 		{
-			sg_assert(min.mV[j] >= myMin.mV[j]-0.02f);
-			sg_assert(max.mV[j] <= myMax.mV[j]+0.02f);
+			sg_assert(min[j] >= myMin[j]-0.02f);
+			sg_assert(max[j] <= myMax[j]+0.02f);
 		}
 	}
 
@@ -507,52 +556,8 @@ void LLSpatialGroup::validate()
 void LLSpatialGroup::checkStates()
 {
 #if LL_OCTREE_PARANOIA_CHECK
-	LLOctreeStateCheck checker;
-	checker.traverse(mOctreeNode);
-#endif
-}
-
-void validate_draw_info(LLDrawInfo& params)
-{
-#if LL_OCTREE_PARANOIA_CHECK
-	if (params.mVertexBuffer.isNull())
-	{
-		llerrs << "Draw batch has no vertex buffer." << llendl;
-	}
-	
-	//bad range
-	if (params.mStart >= params.mEnd)
-	{
-		llerrs << "Draw batch has invalid range." << llendl;
-	}
-	
-	if (params.mEnd >= (U32) params.mVertexBuffer->getNumVerts())
-	{
-		llerrs << "Draw batch has buffer overrun error." << llendl;
-	}
-	
-	if (params.mOffset + params.mCount > (U32) params.mVertexBuffer->getNumIndices())
-	{
-		llerrs << "Draw batch has index buffer ovverrun error." << llendl;
-	}
-	
-	//bad indices
-	U16* indicesp = (U16*) params.mVertexBuffer->getIndicesPointer();
-	if (indicesp)
-	{
-		for (U32 i = params.mOffset; i < params.mOffset+params.mCount; i++)
-		{
-			if (indicesp[i] < (U16)params.mStart)
-			{
-				llerrs << "Draw batch has vertex buffer index out of range error (index too low)." << llendl;
-			}
-			
-			if (indicesp[i] > (U16)params.mEnd)
-			{
-				llerrs << "Draw batch has vertex buffer index out of range error (index too high)." << llendl;
-			}
-		}
-	}
+	//LLOctreeStateCheck checker;
+	//checker.traverse(mOctreeNode);
 #endif
 }
 
@@ -565,8 +570,8 @@ void LLSpatialGroup::validateDrawMap()
 		for (drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
 		{
 			LLDrawInfo& params = **j;
-			
-			validate_draw_info(params);
+		
+			params.validate();
 		}
 	}
 #endif
@@ -577,19 +582,17 @@ BOOL LLSpatialGroup::updateInGroup(LLDrawable *drawablep, BOOL immediate)
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 		
 	drawablep->updateSpatialExtents();
-	validate_drawable(drawablep);
 
 	OctreeNode* parent = mOctreeNode->getOctParent();
 	
 	if (mOctreeNode->isInside(drawablep->getPositionGroup()) && 
 		(mOctreeNode->contains(drawablep) ||
-		 (drawablep->getBinRadius() > mOctreeNode->getSize().mdV[0] &&
+		 (drawablep->getBinRadius() > mOctreeNode->getSize()[0] &&
 				parent && parent->getElementCount() >= LL_OCTREE_MAX_CAPACITY)))
 	{
 		unbound();
 		setState(OBJECT_DIRTY);
 		//setState(GEOM_DIRTY);
-		validate_drawable(drawablep);
 		return TRUE;
 	}
 		
@@ -607,7 +610,6 @@ BOOL LLSpatialGroup::addObject(LLDrawable *drawablep, BOOL add_all, BOOL from_oc
 	else
 	{
 		drawablep->setSpatialGroup(this);
-		validate_drawable(drawablep);
 		setState(OBJECT_DIRTY | GEOM_DIRTY);
 		setOcclusionState(LLSpatialGroup::DISCARD_QUERY, LLSpatialGroup::STATE_MODE_ALL_CAMERAS);
 		gPipeline.markRebuild(this, TRUE);
@@ -708,7 +710,7 @@ void LLSpatialPartition::rebuildMesh(LLSpatialGroup* group)
 
 }
 
-BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxOut)
+BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector4a& minOut, LLVector4a& maxOut)
 {	
 	const OctreeNode* node = mOctreeNode;
 
@@ -721,8 +723,8 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
 		return FALSE;
 	}
 
-	LLVector3& newMin = mObjectExtents[0];
-	LLVector3& newMax = mObjectExtents[1];
+	LLVector4a& newMin = mObjectExtents[0];
+	LLVector4a& newMax = mObjectExtents[1];
 	
 	if (isState(OBJECT_DIRTY))
 	{ //calculate new bounding box
@@ -731,10 +733,10 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
 		//initialize bounding box to first element
 		OctreeNode::const_element_iter i = node->getData().begin();
 		LLDrawable* drawablep = *i;
-		const LLVector3* minMax = drawablep->getSpatialExtents();
+		const LLVector4a* minMax = drawablep->getSpatialExtents();
 
-		newMin.setVec(minMax[0]);
-		newMax.setVec(minMax[1]);
+		newMin = minMax[0];
+		newMax = minMax[1];
 
 		for (++i; i != node->getData().end(); ++i)
 		{
@@ -758,8 +760,10 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
 			}*/
 		}
 		
-		mObjectBounds[0] = (newMin + newMax) * 0.5f;
-		mObjectBounds[1] = (newMax - newMin) * 0.5f;
+		mObjectBounds[0].setAdd(newMin, newMax);
+		mObjectBounds[0].mul(0.5f);
+		mObjectBounds[1].setSub(newMax, newMin);
+		mObjectBounds[1].mul(0.5f);
 	}
 	
 	if (empty)
@@ -769,17 +773,8 @@ BOOL LLSpatialGroup::boundObjects(BOOL empty, LLVector3& minOut, LLVector3& maxO
 	}
 	else
 	{
-		for (U32 i = 0; i < 3; i++)
-		{
-			if (newMin.mV[i] < minOut.mV[i])
-			{
-				minOut.mV[i] = newMin.mV[i];
-			}
-			if (newMax.mV[i] > maxOut.mV[i])
-			{
-				maxOut.mV[i] = newMax.mV[i];
-			}
-		}
+		minOut.setMin(newMin);
+		maxOut.setMax(newMax);
 	}
 		
 	return TRUE;
@@ -870,18 +865,19 @@ BOOL LLSpatialGroup::removeObject(LLDrawable *drawablep, BOOL from_octree)
 	return TRUE;
 }
 
-void LLSpatialGroup::shift(const LLVector3 &offset)
+void LLSpatialGroup::shift(const LLVector4a &offset)
 {
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
-	LLVector3d offsetd(offset);
-	mOctreeNode->setCenter(mOctreeNode->getCenter()+offsetd);
+	LLVector4a t = mOctreeNode->getCenter();
+	t.add(offset);	
+	mOctreeNode->setCenter(t);
 	mOctreeNode->updateMinMax();
-	mBounds[0] += offset;
-	mExtents[0] += offset;
-	mExtents[1] += offset;
-	mObjectBounds[0] += offset;
-	mObjectExtents[0] += offset;
-	mObjectExtents[1] += offset;
+	mBounds[0].add(offset);
+	mExtents[0].add(offset);
+	mExtents[1].add(offset);
+	mObjectBounds[0].add(offset);
+	mObjectExtents[0].add(offset);
+	mObjectExtents[1].add(offset);
 
 	//if (!mSpatialPartition->mRenderByGroup)
 	{
@@ -893,10 +889,7 @@ void LLSpatialGroup::shift(const LLVector3 &offset)
 	{
 		for (U32 i = 0; i < 8; i++)
 		{
-			F32* v = mOcclusionVerts+i*3;
-			v[0] += offset.mV[0];
-			v[1] += offset.mV[1];
-			v[2] += offset.mV[2];
+			mOcclusionVerts[i].add(offset);
 		}
 	}
 }
@@ -1162,8 +1155,6 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 	mDepth(0.f),
 	mLastUpdateDistance(-1.f), 
 	mLastUpdateTime(gFrameTimeSeconds),
-	mViewAngle(0.f),
-	mLastUpdateViewAngle(-1.f),
 	mAtlasList(4),
 	mCurUpdatingTime(0),
 	mCurUpdatingSlotp(NULL),
@@ -1172,13 +1163,25 @@ LLSpatialGroup::LLSpatialGroup(OctreeNode* node, LLSpatialPartition* part) :
 	sNodeCount++;
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 
+	mBounds = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a) * V4_COUNT);
+	mExtents = mBounds + EXTENTS;
+	mObjectBounds = mBounds + OBJECT_BOUNDS;
+	mObjectExtents = mBounds + OBJECT_EXTENTS;
+	mViewAngle = mBounds+VIEW_ANGLE;
+	mLastUpdateViewAngle = mBounds+LAST_VIEW_ANGLE;
+
+	mViewAngle->splat(0.f);
+	mLastUpdateViewAngle->splat(-1.f);
+	mExtents[0] = mExtents[1] = mObjectBounds[0] = mObjectBounds[0] = mObjectBounds[1] = 
+		mObjectExtents[0] = mObjectExtents[1] = *mViewAngle;
+
 	sg_assert(mOctreeNode->getListenerCount() == 0);
 	mOctreeNode->addListener(this);
 	setState(SG_INITIAL_STATE_MASK);
 	gPipeline.markRebuild(this, TRUE);
 
-	mBounds[0] = LLVector3(node->getCenter());
-	mBounds[1] = LLVector3(node->getSize());
+	mBounds[0] = node->getCenter();
+	mBounds[1] = node->getSize();
 
 	part->mLODSeed = (part->mLODSeed+1)%part->mLODPeriod;
 	mLODHash = part->mLODSeed;
@@ -1215,8 +1218,8 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 #endif
 	if (!getData().empty())
 	{
-		mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].magVec() :
-						(F32) mOctreeNode->getSize().magVec();
+		mRadius = mSpatialPartition->mRenderByGroup ? mObjectBounds[1].length3() :
+						(F32) mOctreeNode->getSize().length3();
 		mDistance = mSpatialPartition->calcDistance(this, camera);
 		mPixelArea = mSpatialPartition->calcPixelArea(this, camera);
 	}
@@ -1224,27 +1227,34 @@ void LLSpatialGroup::updateDistance(LLCamera &camera)
 
 F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 {
-	LLVector3 eye = group->mObjectBounds[0] - camera.getOrigin();
+	LLVector4a eye;
+	LLVector4a origin;
+	origin.load3(camera.getOrigin().mV);
+
+	eye.setSub(group->mObjectBounds[0], origin);
 
 	F32 dist = 0.f;
 
 	if (group->mDrawMap.find(LLRenderPass::PASS_ALPHA) != group->mDrawMap.end())
 	{
-		LLVector3 v = eye;
-		dist = eye.normVec();
+		LLVector4a v = eye;
+
+		dist = eye.length3();
+		eye.normalize3fast();
 
 		if (!group->isState(LLSpatialGroup::ALPHA_DIRTY))
 		{
 			if (!group->mSpatialPartition->isBridge())
 			{
-				LLVector3 view_angle = LLVector3(eye * LLVector3(1,0,0),
-												 eye * LLVector3(0,1,0),
-												 eye * LLVector3(0,0,1));
+				LLVector4a view_angle = eye;
+
+				LLVector4a diff;
+				diff.setSub(view_angle, *group->mLastUpdateViewAngle);
 
-				if ((view_angle-group->mLastUpdateViewAngle).magVec() > 0.64f)
+				if (diff.length3() > 0.64f)
 				{
-					group->mViewAngle = view_angle;
-					group->mLastUpdateViewAngle = view_angle;
+					*group->mViewAngle = view_angle;
+					*group->mLastUpdateViewAngle = view_angle;
 					//for occasional alpha sorting within the group
 					//NOTE: If there is a trivial way to detect that alpha sorting here would not change the render order,
 					//not setting this node to dirty would be a very good thing
@@ -1258,17 +1268,20 @@ F32 LLSpatialPartition::calcDistance(LLSpatialGroup* group, LLCamera& camera)
 
 		LLVector3 at = camera.getAtAxis();
 
-		//front of bounding box
-		for (U32 i = 0; i < 3; i++)
-		{
-			v.mV[i] -= group->mObjectBounds[1].mV[i]*0.25f * at.mV[i];
-		}
+		LLVector4a ata;
+		ata.load3(at.mV);
 
-		group->mDepth = v * at;
+		LLVector4a t = ata;
+		//front of bounding box
+		t.mul(0.25f);
+		t.mul(group->mObjectBounds[1]);
+		v.sub(t);
+		
+		group->mDepth = v.dot3(ata);
 	}
 	else
 	{
-		dist = eye.magVec();
+		dist = eye.length3();
 	}
 
 	if (dist < 16.f)
@@ -1421,7 +1434,7 @@ void LLSpatialGroup::destroyGL()
 		}
 	}
 
-	delete [] mOcclusionVerts;
+	ll_aligned_free_16(mOcclusionVerts);
 	mOcclusionVerts = NULL;
 
 	for (LLSpatialGroup::element_iter i = getData().begin(); i != getData().end(); ++i)
@@ -1464,8 +1477,8 @@ BOOL LLSpatialGroup::rebound()
 	}
 	else
 	{
-		LLVector3& newMin = mExtents[0];
-		LLVector3& newMax = mExtents[1];
+		LLVector4a& newMin = mExtents[0];
+		LLVector4a& newMax = mExtents[1];
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
 		group->clearState(SKIP_FRUSTUM_CHECK);
 		group->rebound();
@@ -1479,26 +1492,19 @@ BOOL LLSpatialGroup::rebound()
 			group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
 			group->clearState(SKIP_FRUSTUM_CHECK);
 			group->rebound();
-			const LLVector3& max = group->mExtents[1];
-			const LLVector3& min = group->mExtents[0];
+			const LLVector4a& max = group->mExtents[1];
+			const LLVector4a& min = group->mExtents[0];
 
-			for (U32 j = 0; j < 3; j++)
-			{
-				if (max.mV[j] > newMax.mV[j])
-				{
-					newMax.mV[j] = max.mV[j];
-				}
-				if (min.mV[j] < newMin.mV[j])
-				{
-					newMin.mV[j] = min.mV[j];
-				}
-			}
+			newMax.setMax(max);
+			newMin.setMin(min);
 		}
 
 		boundObjects(FALSE, newMin, newMax);
 		
-		mBounds[0] = (newMin + newMax)*0.5f;
-		mBounds[1] = (newMax - newMin)*0.5f;
+		mBounds[0].setAdd(newMin, newMax);
+		mBounds[0].mul(0.5f);
+		mBounds[1].setSub(newMax, newMin);
+		mBounds[1].mul(0.5f);
 	}
 	
 	setState(OCCLUSION_DIRTY);
@@ -1513,6 +1519,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 +1527,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])
 			{
@@ -1583,7 +1589,7 @@ void LLSpatialGroup::doOcclusion(LLCamera* camera)
 				}
 
 				glBeginQueryARB(GL_SAMPLES_PASSED_ARB, mOcclusionQuery[LLViewerCamera::sCurCameraID]);					
-				glVertexPointer(3, GL_FLOAT, 0, mOcclusionVerts);
+				glVertexPointer(3, GL_FLOAT, 16, mOcclusionVerts);
 				if (camera->getOrigin().isExactlyZero())
 				{ //origin is invalid, draw entire box
 					glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
@@ -1624,8 +1630,11 @@ LLSpatialPartition::LLSpatialPartition(U32 data_mask, BOOL render_by_group, U32
 
 	LLGLNamePool::registerPool(&sQueryPool);
 
-	mOctree = new LLSpatialGroup::OctreeRoot(LLVector3d(0,0,0), 
-											LLVector3d(1,1,1), 
+	LLVector4a center, size;
+	center.splat(0.f);
+	size.splat(1.f);
+
+	mOctree = new LLSpatialGroup::OctreeRoot(center,size,
 											NULL);
 	new LLSpatialGroup(mOctree, this);
 }
@@ -1645,7 +1654,6 @@ LLSpatialGroup *LLSpatialPartition::put(LLDrawable *drawablep, BOOL was_visible)
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 		
 	drawablep->updateSpatialExtents();
-	validate_drawable(drawablep);
 
 	//keep drawable from being garbage collected
 	LLPointer<LLDrawable> ptr = drawablep;
@@ -1729,16 +1737,16 @@ void LLSpatialPartition::move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL
 class LLSpatialShift : public LLSpatialGroup::OctreeTraveler
 {
 public:
-	LLSpatialShift(LLVector3 offset) : mOffset(offset) { }
+	const LLVector4a& mOffset;
+
+	LLSpatialShift(const LLVector4a& offset) : mOffset(offset) { }
 	virtual void visit(const LLSpatialGroup::OctreeNode* branch) 
 	{ 
 		((LLSpatialGroup*) branch->getListener(0))->shift(mOffset); 
 	}
-		
-	LLVector3 mOffset;
 };
 
-void LLSpatialPartition::shift(const LLVector3 &offset)
+void LLSpatialPartition::shift(const LLVector4a &offset)
 { //shift octree node bounding boxes by offset
 	LLMemType mt(LLMemType::MTYPE_SPACE_PARTITION);
 	LLSpatialShift shifter(offset);
@@ -1900,7 +1908,7 @@ class LLOctreeCullShadow : public LLOctreeCull
 class LLOctreeCullVisExtents: public LLOctreeCullShadow
 {
 public:
-	LLOctreeCullVisExtents(LLCamera* camera, LLVector3& min, LLVector3& max)
+	LLOctreeCullVisExtents(LLCamera* camera, LLVector4a& min, LLVector4a& max)
 		: LLOctreeCullShadow(camera), mMin(min), mMax(max), mEmpty(TRUE) { }
 
 	virtual bool earlyFail(LLSpatialGroup* group)
@@ -1924,11 +1932,8 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow
 			return;
 		}
 		
-		if (mRes == 2)
-		{
-			//fully in, don't traverse further (won't effect extents
-		}
-		else if (mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK))
+		if ((mRes && group->isState(LLSpatialGroup::SKIP_FRUSTUM_CHECK)) ||
+			mRes == 2)
 		{	//don't need to do frustum check
 			LLSpatialGroup::OctreeTraveler::traverse(n);
 		}
@@ -1970,8 +1975,8 @@ class LLOctreeCullVisExtents: public LLOctreeCullShadow
 	}
 
 	BOOL mEmpty;
-	LLVector3& mMin;
-	LLVector3& mMax;
+	LLVector4a& mMin;
+	LLVector4a& mMax;
 };
 
 class LLOctreeCullDetectVisible: public LLOctreeCullShadow
@@ -2040,6 +2045,8 @@ class LLOctreeSelect : public LLOctreeCull
 
 void drawBox(const LLVector3& c, const LLVector3& r)
 {
+	LLVertexBuffer::unbind();
+
 	gGL.begin(LLRender::TRIANGLE_STRIP);
 	//left front
 	gGL.vertex3fv((c+r.scaledVec(LLVector3(-1,1,-1))).mV);
@@ -2075,6 +2082,11 @@ void drawBox(const LLVector3& c, const LLVector3& r)
 	gGL.end();	
 }
 
+void drawBox(const LLVector4a& c, const LLVector4a& r)
+{
+	drawBox(reinterpret_cast<const LLVector3&>(c), reinterpret_cast<const LLVector3&>(r));
+}
+
 void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
 {
 	LLVector3 v1 = size.scaledVec(LLVector3( 1, 1,1));
@@ -2121,6 +2133,11 @@ void drawBoxOutline(const LLVector3& pos, const LLVector3& size)
 	gGL.end();
 }
 
+void drawBoxOutline(const LLVector4a& pos, const LLVector4a& size)
+{
+	drawBoxOutline(reinterpret_cast<const LLVector3&>(pos), reinterpret_cast<const LLVector3&>(size));
+}
+
 class LLOctreeDirty : public LLOctreeTraveler<LLDrawable>
 {
 public:
@@ -2164,14 +2181,21 @@ BOOL LLSpatialPartition::isOcclusionEnabled()
 
 BOOL LLSpatialPartition::getVisibleExtents(LLCamera& camera, LLVector3& visMin, LLVector3& visMax)
 {
+	LLVector4a visMina, visMaxa;
+	visMina.load3(visMin.mV);
+	visMaxa.load3(visMax.mV);
+
 	{
 		LLFastTimer ftm(FTM_CULL_REBOUND);		
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctree->getListener(0);
 		group->rebound();
 	}
 
-	LLOctreeCullVisExtents vis(&camera, visMin, visMax);
+	LLOctreeCullVisExtents vis(&camera, visMina, visMaxa);
 	vis.traverse(mOctree);
+
+	visMin.set(visMina.getF32());
+	visMax.set(visMaxa.getF32());
 	return vis.mEmpty;
 }
 
@@ -2234,25 +2258,36 @@ BOOL earlyFail(LLCamera* camera, LLSpatialGroup* group)
 	}
 
 	const F32 vel = SG_OCCLUSION_FUDGE*2.f;
-	LLVector3 c = group->mBounds[0];
-	LLVector3 r = group->mBounds[1] + LLVector3(vel,vel,vel);
-    
+	LLVector4a fudge;
+	fudge.splat(vel);
+
+	const LLVector4a& c = group->mBounds[0];
+	LLVector4a r;
+	r.setAdd(group->mBounds[1], fudge);
+
 	/*if (r.magVecSquared() > 1024.0*1024.0)
 	{
 		return TRUE;
 	}*/
 
-	LLVector3 e = camera->getOrigin();
+	LLVector4a e;
+	e.load3(camera->getOrigin().mV);
 	
-	LLVector3 min = c - r;
-	LLVector3 max = c + r;
+	LLVector4a min;
+	min.setSub(c,r);
+	LLVector4a max;
+	max.setAdd(c,r);
 	
-	for (U32 j = 0; j < 3; j++)
+	S32 lt = e.lessThan4(min).getComparisonMask() & 0x7;
+	if (lt)
 	{
-		if (e.mV[j] < min.mV[j] || e.mV[j] > max.mV[j])
-		{
-			return FALSE;
-		}
+		return FALSE;
+	}
+
+	S32 gt = e.greaterThan4(max).getComparisonMask() & 0x7;
+	if (gt)
+	{
+		return FALSE;
 	}
 
 	return TRUE;
@@ -2294,7 +2329,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)
@@ -2458,7 +2492,13 @@ void renderOctree(LLSpatialGroup* group)
 	}
 
 	gGL.color4fv(col.mV);
-	drawBox(group->mObjectBounds[0], group->mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f));
+	LLVector4a fudge;
+	fudge.splat(0.001f);
+	LLVector4a size = group->mObjectBounds[1];
+	size.mul(1.01f);
+	size.add(fudge);
+
+	drawBox(group->mObjectBounds[0], fudge);
 	
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
@@ -2489,8 +2529,12 @@ void renderOctree(LLSpatialGroup* group)
 				for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
 				{
 					LLDrawInfo* draw_info = *j;
-					LLVector3 center = (draw_info->mExtents[1] + draw_info->mExtents[0])*0.5f;
-					LLVector3 size = (draw_info->mExtents[1] - draw_info->mExtents[0])*0.5f;
+					LLVector4a center;
+					center.setAdd(draw_info->mExtents[1], draw_info->mExtents[0]);
+					center.mul(0.5f);
+					LLVector4a size;
+					size.setSub(draw_info->mExtents[1], draw_info->mExtents[0]);
+					size.mul(0.5f);
 					drawBoxOutline(center, size);
 				}
 			}
@@ -2540,7 +2584,7 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 		else if (camera && group->mOcclusionVerts)
 		{
 			LLVertexBuffer::unbind();
-			glVertexPointer(3, GL_FLOAT, 0, group->mOcclusionVerts);
+			glVertexPointer(3, GL_FLOAT, 16, group->mOcclusionVerts);
 
 			glColor4f(1.0f, 0.f, 0.f, 0.5f);
 			glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8, GL_UNSIGNED_BYTE, get_box_fan_indices(camera, group->mBounds[0]));
@@ -2619,8 +2663,8 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
 		}
 	}
 
-	const LLVector3* ext;
-	LLVector3 pos, size;
+	const LLVector4a* ext;
+	LLVector4a pos, size;
 
 	//render face bounding boxes
 	for (S32 i = 0; i < drawable->getNumFaces(); i++)
@@ -2629,20 +2673,21 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
 
 		ext = facep->mExtents;
 
-		if (ext[0].isExactlyZero() && ext[1].isExactlyZero())
-		{
-			continue;
-		}
-		pos = (ext[0] + ext[1]) * 0.5f;
-		size = (ext[1] - ext[0]) * 0.5f;
+		pos.setAdd(ext[0], ext[1]);
+		pos.mul(0.5f);
+		size.setSub(ext[1], ext[0]);
+		size.mul(0.5f);
+		
 		drawBoxOutline(pos,size);
 	}
 
 	//render drawable bounding box
 	ext = drawable->getSpatialExtents();
 
-	pos = (ext[0] + ext[1]) * 0.5f;
-	size = (ext[1] - ext[0]) * 0.5f;
+	pos.setAdd(ext[0], ext[1]);
+	pos.mul(0.5f);
+	size.setSub(ext[1], ext[0]);
+	size.mul(0.5f);
 	
 	LLViewerObject* vobj = drawable->getVObj();
 	if (vobj && vobj->onActiveList())
@@ -2659,7 +2704,56 @@ void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE)
 	{
 		drawBoxOutline(pos,size);
 	}
-	
+}
+
+void renderNormals(LLDrawable* drawablep)
+{
+	LLVertexBuffer::unbind();
+
+	LLVOVolume* vol = drawablep->getVOVolume();
+	if (vol)
+	{
+		LLVolume* volume = vol->getVolume();
+		gGL.pushMatrix();
+		glMultMatrixf((F32*) vol->getRelativeXform().mMatrix);
+		
+		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+		LLVector4a scale(gSavedSettings.getF32("RenderDebugNormalScale"));
+
+		for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+		{
+			const LLVolumeFace& face = volume->getVolumeFace(i);
+
+			gGL.begin(LLRender::LINES);
+			
+			for (S32 j = 0; j < face.mNumVertices; ++j)
+			{
+				LLVector4a n,p;
+				
+				n.setMul(face.mNormals[j], scale);
+				p.setAdd(face.mPositions[j], n);
+				
+				gGL.color4f(1,1,1,1);
+				gGL.vertex3fv(face.mPositions[j].getF32());
+				gGL.vertex3fv(p.getF32());
+				
+				if (face.mBinormals)
+				{
+					n.setMul(face.mBinormals[j], scale);
+					p.setAdd(face.mPositions[j], n);
+				
+					gGL.color4f(0,1,1,1);
+					gGL.vertex3fv(face.mPositions[j].getF32());
+					gGL.vertex3fv(p.getF32());
+				}	
+			}
+
+			gGL.end();
+		}
+
+		gGL.popMatrix();
+	}
 }
 
 void renderTexturePriority(LLDrawable* drawable)
@@ -2698,8 +2792,13 @@ void renderTexturePriority(LLDrawable* drawable)
 		//	gGL.color4f(1,0,1,1);
 		//}
 		
-		LLVector3 center = (facep->mExtents[1]+facep->mExtents[0])*0.5f;
-		LLVector3 size = (facep->mExtents[1]-facep->mExtents[0])*0.5f + LLVector3(0.01f, 0.01f, 0.01f);
+		LLVector4a center;
+		center.setAdd(facep->mExtents[1],facep->mExtents[0]);
+		center.mul(0.5f);
+		LLVector4a size;
+		size.setSub(facep->mExtents[1],facep->mExtents[0]);
+		size.mul(0.5f);
+		size.add(LLVector4a(0.01f));
 		drawBox(center, size);
 		
 		/*S32 boost = imagep->getBoostLevel();
@@ -2723,7 +2822,6 @@ void renderPoints(LLDrawable* drawablep)
 	{
 		gGL.begin(LLRender::POINTS);
 		gGL.color3f(1,1,1);
-		LLVector3 center(drawablep->getPositionGroup());
 		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 		{
 			gGL.vertex3fv(drawablep->getFace(i)->mCenterLocal.mV);
@@ -2755,8 +2853,12 @@ void renderShadowFrusta(LLDrawInfo* params)
 	LLGLEnable blend(GL_BLEND);
 	gGL.setSceneBlendType(LLRender::BT_ADD);
 
-	LLVector3 center = (params->mExtents[1]+params->mExtents[0])*0.5f;
-	LLVector3 size = (params->mExtents[1]-params->mExtents[0])*0.5f;
+	LLVector4a center;
+	center.setAdd(params->mExtents[1], params->mExtents[0]);
+	center.mul(0.5f);
+	LLVector4a size;
+	size.setSub(params->mExtents[1],params->mExtents[0]);
+	size.mul(0.5f);
 
 	if (gPipeline.mShadowCamera[4].AABBInFrustum(center, size))
 	{
@@ -2800,10 +2902,14 @@ void renderLights(LLDrawable* drawablep)
 			pushVerts(drawablep->getFace(i), LLVertexBuffer::MAP_VERTEX);
 		}
 
-		const LLVector3* ext = drawablep->getSpatialExtents();
+		const LLVector4a* ext = drawablep->getSpatialExtents();
 
-		LLVector3 pos = (ext[0] + ext[1]) * 0.5f;
-		LLVector3 size = (ext[1] - ext[0]) * 0.5f;
+		LLVector4a pos;
+		pos.setAdd(ext[0], ext[1]);
+		pos.mul(0.5f);
+		LLVector4a size;
+		size.setSub(ext[1], ext[0]);
+		size.mul(0.5f);
 
 		{
 			LLGLDepthTest depth(GL_FALSE, GL_TRUE);
@@ -2813,10 +2919,32 @@ void renderLights(LLDrawable* drawablep)
 
 		gGL.color4f(1,1,0,1);
 		F32 rad = drawablep->getVOVolume()->getLightRadius();
-		drawBoxOutline(pos, LLVector3(rad,rad,rad));
+		drawBoxOutline(pos, LLVector4a(rad));
 	}
 }
 
+class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
+{
+public:
+	
+	LLRenderOctreeRaycast(const LLVector3& start, const LLVector3& end)
+	{
+		mStart.load3(start.mV);
+		mEnd.load3(end.mV);
+		mDir.setSub(mEnd, mStart);
+	}
+
+	void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+	{
+		LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
+
+		LLVector3 center, size;
+		center.set(vl->mBounds[0].getF32());
+		size.set(vl->mBounds[1].getF32());
+
+		drawBoxOutline(center, size);
+	}
+};
 
 void renderRaycast(LLDrawable* drawablep)
 {
@@ -2835,6 +2963,27 @@ void renderRaycast(LLDrawable* drawablep)
 			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 			pushVerts(drawablep->getFace(gDebugRaycastFaceHit), LLVertexBuffer::MAP_VERTEX);
 			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+			LLVOVolume* vobj = drawablep->getVOVolume();
+			LLVolume* volume = vobj->getVolume();
+			if (volume && volume->getNumVolumeFaces() > gDebugRaycastFaceHit)
+			{
+				const LLVolumeFace& face = volume->getVolumeFace(gDebugRaycastFaceHit);
+				if (!face.mOctree)
+				{
+					((LLVolumeFace*) &face)->createOctree(); 
+				}
+
+				gGL.pushMatrix();
+				glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
+				LLVector3 start, end;
+				start = vobj->agentPositionToVolume(gDebugRaycastStart);
+				end = vobj->agentPositionToVolume(gDebugRaycastEnd);
+
+				LLRenderOctreeRaycast render(start, end);
+				render.traverse(face.mOctree);
+				gGL.popMatrix();		
+			}
 		}
 		else if (drawablep->isAvatar())
 		{
@@ -2863,10 +3012,14 @@ void renderRaycast(LLDrawable* drawablep)
 		glPopMatrix();
 
 		// draw bounding box of prim
-		const LLVector3* ext = drawablep->getSpatialExtents();
+		const LLVector4a* ext = drawablep->getSpatialExtents();
 
-		LLVector3 pos = (ext[0] + ext[1]) * 0.5f;
-		LLVector3 size = (ext[1] - ext[0]) * 0.5f;
+		LLVector4a pos;
+		pos.setAdd(ext[0], ext[1]);
+		pos.mul(0.5f);
+		LLVector4a size;
+		size.setSub(ext[1], ext[0]);
+		size.mul(0.5f);
 
 		LLGLDepthTest depth(GL_FALSE, GL_TRUE);
 		gGL.color4f(0,0.5f,0.5f,1);
@@ -2953,8 +3106,8 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 			return;
 		}
 
-		LLVector3 nodeCenter = group->mBounds[0];
-		LLVector3 octCenter = LLVector3(group->mOctreeNode->getCenter());
+		LLVector4a nodeCenter = group->mBounds[0];
+		LLVector4a octCenter = group->mOctreeNode->getCenter();
 
 		group->rebuildGeom();
 		group->rebuildMesh();
@@ -2977,14 +3130,25 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 			{
 				renderBoundingBox(drawable);			
 			}
+
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_NORMALS))
+			{
+				renderNormals(drawable);
+			}
 			
 			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_BUILD_QUEUE))
 			{
 				if (drawable->isState(LLDrawable::IN_REBUILD_Q2))
 				{
 					gGL.color4f(0.6f, 0.6f, 0.1f, 1.f);
-					const LLVector3* ext = drawable->getSpatialExtents();
-					drawBoxOutline((ext[0]+ext[1])*0.5f, (ext[1]-ext[0])*0.5f);
+					const LLVector4a* ext = drawable->getSpatialExtents();
+					LLVector4a center;
+					center.setAdd(ext[0], ext[1]);
+					center.mul(0.5f);
+					LLVector4a size;
+					size.setSub(ext[1], ext[0]);
+					size.mul(0.5f);
+					drawBoxOutline(center, size);
 				}
 			}	
 
@@ -3170,6 +3334,7 @@ void LLSpatialPartition::renderDebug()
 									  LLPipeline::RENDER_DEBUG_LIGHTS |
 									  LLPipeline::RENDER_DEBUG_BATCH_SIZE |
 									  LLPipeline::RENDER_DEBUG_BBOXES |
+									  LLPipeline::RENDER_DEBUG_NORMALS |
 									  LLPipeline::RENDER_DEBUG_POINTS |
 									  LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY |
 									  LLPipeline::RENDER_DEBUG_TEXTURE_ANIM |
@@ -3215,7 +3380,11 @@ void LLSpatialPartition::renderDebug()
 void LLSpatialGroup::drawObjectBox(LLColor4 col)
 {
 	gGL.color4fv(col.mV);
-	drawBox(mObjectBounds[0], mObjectBounds[1]*1.01f+LLVector3(0.001f, 0.001f, 0.001f));
+	LLVector4a size;
+	size = mObjectBounds[0];
+	size.mul(1.01f);
+	size.add(LLVector4a(0.001f));
+	drawBox(mObjectBounds[0], size);
 }
 
 
@@ -3275,8 +3444,8 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 
 			LLSpatialGroup* group = (LLSpatialGroup*) child->getListener(0);
 			
-			LLVector3 size;
-			LLVector3 center;
+			LLVector4a size;
+			LLVector4a center;
 			
 			size = group->mBounds[1];
 			center = group->mBounds[0];
@@ -3293,7 +3462,11 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 				local_end   = mEnd   * local_matrix;
 			}
 
-			if (LLLineSegmentBoxIntersect(local_start, local_end, center, size))
+			LLVector4a start, end;
+			start.load3(local_start.mV);
+			end.load3(local_end.mV);
+
+			if (LLLineSegmentBoxIntersect(start, end, center, size))
 			{
 				check(child);
 			}
@@ -3383,18 +3556,10 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
 	mDistance(0.f),
 	mDrawMode(LLRender::TRIANGLES)
 {
-	mDebugColor = (rand() << 16) + rand();
-	if (mStart >= mVertexBuffer->getRequestedVerts() ||
-		mEnd >= mVertexBuffer->getRequestedVerts())
-	{
-		llerrs << "Invalid draw info vertex range." << llendl;
-	}
+	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
+	mExtents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*2);
 
-	if (mOffset >= (U32) mVertexBuffer->getRequestedIndices() ||
-		mOffset + mCount > (U32) mVertexBuffer->getRequestedIndices())
-	{
-		llerrs << "Invalid draw info index range." << llendl;
-	}
+	mDebugColor = (rand() << 16) + rand();
 }
 
 LLDrawInfo::~LLDrawInfo()	
@@ -3408,6 +3573,18 @@ LLDrawInfo::~LLDrawInfo()
 	{
 		mFace->setDrawInfo(NULL);
 	}
+
+	if (gDebugGL)
+	{
+		gPipeline.checkReferences(this);
+	}
+
+	ll_aligned_free_16(mExtents);
+}
+
+void LLDrawInfo::validate()
+{
+	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
 }
 
 LLVertexBuffer* LLGeometryManager::createVertexBuffer(U32 type_mask, U32 usage)
@@ -3423,11 +3600,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 +3625,7 @@ void LLCullResult::clear()
 			mRenderMap[i][j] = 0;
 		}
 		mRenderMapSize[i] = 0;
+		mRenderMapEnd[i] = mRenderMap[i].begin();
 	}
 }
 
@@ -3446,7 +3636,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 +3646,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 +3656,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 +3666,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 +3676,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 +3686,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 +3696,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 +3710,7 @@ void LLCullResult::pushVisibleGroup(LLSpatialGroup* group)
 		mVisibleGroups.push_back(group);
 	}
 	++mVisibleGroupsSize;
+	mVisibleGroupsEnd = mVisibleGroups.begin()+mVisibleGroupsSize;
 }
 
 void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
@@ -3533,6 +3724,7 @@ void LLCullResult::pushAlphaGroup(LLSpatialGroup* group)
 		mAlphaGroups.push_back(group);
 	}
 	++mAlphaGroupsSize;
+	mAlphaGroupsEnd = mAlphaGroups.begin()+mAlphaGroupsSize;
 }
 
 void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
@@ -3546,6 +3738,7 @@ void LLCullResult::pushOcclusionGroup(LLSpatialGroup* group)
 		mOcclusionGroups.push_back(group);
 	}
 	++mOcclusionGroupsSize;
+	mOcclusionGroupsEnd = mOcclusionGroups.begin()+mOcclusionGroupsSize;
 }
 
 void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
@@ -3559,6 +3752,7 @@ void LLCullResult::pushDrawableGroup(LLSpatialGroup* group)
 		mDrawableGroups.push_back(group);
 	}
 	++mDrawableGroupsSize;
+	mDrawableGroupsEnd = mDrawableGroups.begin()+mDrawableGroupsSize;
 }
 
 void LLCullResult::pushDrawable(LLDrawable* drawable)
@@ -3572,6 +3766,7 @@ void LLCullResult::pushDrawable(LLDrawable* drawable)
 		mVisibleList.push_back(drawable);
 	}
 	++mVisibleListSize;
+	mVisibleListEnd = mVisibleList.begin()+mVisibleListSize;
 }
 
 void LLCullResult::pushBridge(LLSpatialBridge* bridge)
@@ -3585,6 +3780,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 +3794,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..119945113ab7cb5a1fb0773662fa81be1e26dce9 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -45,7 +45,7 @@
 #include "lldrawpool.h"
 #include "llface.h"
 #include "llviewercamera.h"
-
+#include "llvector4a.h"
 #include <queue>
 
 #define SG_STATE_INHERIT_MASK (OCCLUDED)
@@ -57,11 +57,15 @@ class LLSpatialGroup;
 class LLTextureAtlas;
 class LLTextureAtlasSlot;
 
+S32 AABBSphereIntersect(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &rad);
+S32 AABBSphereIntersectR2(const LLVector4a& min, const LLVector4a& max, const LLVector3 &origin, const F32 &radius_squared);
+
 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);
+U8* get_box_fan_indices(LLCamera* camera, const LLVector4a& center);
 
 class LLDrawInfo : public LLRefCount 
 {
@@ -69,11 +73,27 @@ class LLDrawInfo : public LLRefCount
 	~LLDrawInfo();	
 	
 public:
+
+	LLDrawInfo(const LLDrawInfo& rhs)
+	{
+		*this = rhs;
+	}
+
+	const LLDrawInfo& operator=(const LLDrawInfo& rhs)
+	{
+		llerrs << "Illegal operation!" << llendl;
+		return *this;
+	}
+
 	LLDrawInfo(U16 start, U16 end, U32 count, U32 offset, 
 				LLViewerTexture* image, LLVertexBuffer* buffer, 
 				BOOL fullbright = FALSE, U8 bump = 0, BOOL particle = FALSE, F32 part_size = 0);
 	
 
+	void validate();
+
+	LLVector4a* mExtents;
+	
 	LLPointer<LLVertexBuffer> mVertexBuffer;
 	LLPointer<LLViewerTexture>     mTexture;
 	LLColor4U mGlowColor;
@@ -92,7 +112,6 @@ class LLDrawInfo : public LLRefCount
 	LLSpatialGroup* mGroup;
 	LLFace* mFace; //associated face
 	F32 mDistance;
-	LLVector3 mExtents[2];
 	U32 mDrawMode;
 
 	struct CompareTexture
@@ -155,11 +174,24 @@ class LLDrawInfo : public LLRefCount
 	};
 };
 
+LL_ALIGN_PREFIX(64)
 class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 {
 	friend class LLSpatialPartition;
 	friend class LLOctreeStateCheck;
 public:
+
+	LLSpatialGroup(const LLSpatialGroup& rhs)
+	{
+		*this = rhs;
+	}
+
+	const LLSpatialGroup& operator=(const LLSpatialGroup& rhs)
+	{
+		llerrs << "Illegal operation!" << llendl;
+		return *this;
+	}
+
 	static U32 sNodeCount;
 	static BOOL sNoDelete; //deletion of spatial groups and draw info not allowed if TRUE
 
@@ -270,8 +302,8 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	BOOL isVisible() const;
 	BOOL isRecentlyVisible() const;
 	void setVisible();
-	void shift(const LLVector3 &offset);
-	BOOL boundObjects(BOOL empty, LLVector3& newMin, LLVector3& newMax);
+	void shift(const LLVector4a &offset);
+	BOOL boundObjects(BOOL empty, LLVector4a& newMin, LLVector4a& newMax);
 	void unbound();
 	BOOL rebound();
 	void buildOcclusion(); //rebuild mOcclusionVerts
@@ -319,6 +351,27 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	void addAtlas(LLTextureAtlas* atlasp, S8 recursive_level = 3) ;
 	void removeAtlas(LLTextureAtlas* atlasp, BOOL remove_group = TRUE, S8 recursive_level = 3) ;
 	void clearAtlasList() ;
+
+public:
+
+	typedef enum
+	{
+		BOUNDS = 0,
+		EXTENTS = 2,
+		OBJECT_BOUNDS = 4,
+		OBJECT_EXTENTS = 6,
+		VIEW_ANGLE = 8,
+		LAST_VIEW_ANGLE = 9,
+		V4_COUNT = 10
+	} eV4Index;
+
+	LLVector4a* mBounds; // bounding box (center, size) of this node and all its children (tight fit to objects)
+	LLVector4a* mExtents; // extents (min, max) of this node and all its children
+	LLVector4a* mObjectExtents; // extents (min, max) of objects in this node
+	LLVector4a* mObjectBounds; // bounding box (center, size) of objects in this node
+	LLVector4a* mViewAngle;
+	LLVector4a* mLastUpdateViewAngle;
+		
 private:
 	U32                     mCurUpdatingTime ;
 	//do not make the below two to use LLPointer
@@ -346,14 +399,9 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	F32 mBuilt;
 	OctreeNode* mOctreeNode;
 	LLSpatialPartition* mSpatialPartition;
-	LLVector3 mBounds[2];
-	LLVector3 mExtents[2];
 	
-	LLVector3 mObjectExtents[2];
-	LLVector3 mObjectBounds[2];
-
 	LLPointer<LLVertexBuffer> mVertexBuffer;
-	F32*					mOcclusionVerts;
+	LLVector4a*				mOcclusionVerts;
 	GLuint					mOcclusionQuery[LLViewerCamera::NUM_CAMERAS];
 
 	U32 mBufferUsage;
@@ -364,13 +412,10 @@ class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 	F32 mDepth;
 	F32 mLastUpdateDistance;
 	F32 mLastUpdateTime;
-			
-	LLVector3 mViewAngle;
-	LLVector3 mLastUpdateViewAngle;
 	
 	F32 mPixelArea;
 	F32 mRadius;
-};
+} LL_ALIGN_POSTFIX(64);
 
 class LLGeometryManager
 {
@@ -406,7 +451,7 @@ class LLSpatialPartition: public LLGeometryManager
 	
 	// If the drawable moves, move it here.
 	virtual void move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate = FALSE);
-	virtual void shift(const LLVector3 &offset);
+	virtual void shift(const LLVector4a &offset);
 
 	virtual F32 calcDistance(LLSpatialGroup* group, LLCamera& camera);
 	virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera);
@@ -464,7 +509,7 @@ class LLSpatialBridge : public LLDrawable, public LLSpatialPartition
 	virtual void makeActive();
 	virtual void move(LLDrawable *drawablep, LLSpatialGroup *curp, BOOL immediate = FALSE);
 	virtual BOOL updateMove();
-	virtual void shiftPos(const LLVector3& vec);
+	virtual void shiftPos(const LLVector4a& vec);
 	virtual void cleanupReferences();
 	virtual LLSpatialPartition* asPartition()		{ return this; }
 	virtual LLSpatialBridge* asBridge()				{ return this; }
@@ -534,12 +579,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 +658,20 @@ class LLCloudPartition : public LLParticlePartition
 //class for wrangling geometry out of volumes (implemented in LLVOVolume.cpp)
 class LLVolumeGeometryManager: public LLGeometryManager
 {
-public:
+ public:
+	typedef enum
+	{
+		NONE = 0,
+		BATCH_SORT,
+		DISTANCE_SORT
+	} eSortType;
+
 	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);
-
 };
 
 //spatial partition that uses volume geometry manager (implemented in LLVOVolume.cpp)
@@ -642,7 +700,7 @@ class LLHUDBridge : public LLVolumeBridge
 {
 public:
 	LLHUDBridge(LLDrawable* drawablep);
-	virtual void shiftPos(const LLVector3& vec);
+	virtual void shiftPos(const LLVector4a& vec);
 	virtual F32 calcPixelArea(LLSpatialGroup* group, LLCamera& camera);
 };
 
@@ -659,11 +717,9 @@ class LLHUDPartition : public LLBridgePartition
 {
 public:
 	LLHUDPartition();
-	virtual void shift(const LLVector3 &offset);
+	virtual void shift(const LLVector4a &offset);
 };
 
-void validate_draw_info(LLDrawInfo& params);
-
 extern const F32 SG_BOX_SIDE;
 extern const F32 SG_BOX_OFFSET;
 extern const F32 SG_BOX_RAD;
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index 48e4a6ccc7517902f4a357fc9ff87ff962c8f853..06431d428f1819ac6653c00236569c9faa79ff91 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -860,8 +860,10 @@ void LLSurfacePatch::updateVisibility()
 	F32 stride_per_distance = DEFAULT_DELTA_ANGLE / mSurfacep->getMetersPerGrid();
 	U32 grids_per_patch_edge = mSurfacep->getGridsPerPatchEdge();
 
-	LLVector3 center = mCenterRegion + mSurfacep->getOriginAgent();
-	LLVector3 radius = LLVector3(mRadius, mRadius, mRadius);
+	LLVector4a center;
+	center.load3( (mCenterRegion + mSurfacep->getOriginAgent()).mV);
+	LLVector4a radius;
+	radius.splat(mRadius);
 
 	// sphere in frustum on global coordinates
 	if (LLViewerCamera::getInstance()->AABBInFrustumNoFarClip(center, radius))
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index a1ab051021222c2bd94609cc7473860109161f1d..6088c3155962cf7bc14b0c5d969f0d8044599943 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -292,7 +292,11 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop(
 {
 	BOOL handled = FALSE;
 
-	if (cargo_type == DAD_TEXTURE)
+	bool is_mesh = false;
+#if LL_MESH_ENABLED
+	is_mesh = cargo_type == DAD_MESH;
+#endif
+	if ((cargo_type == DAD_TEXTURE) || is_mesh)
 	{
 		LLInventoryItem *item = (LLInventoryItem *)cargo_data;
 
@@ -1177,7 +1181,13 @@ 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))
+	bool is_mesh = false;
+#if LL_MESH_ENABLED
+	is_mesh = cargo_type == DAD_MESH;
+#endif
+	if (getEnabled() &&
+		((cargo_type == DAD_TEXTURE) || is_mesh) &&
+		 allowDrop(item))
 	{
 		if (drop)
 		{
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index c862c02b82b14d776ca0ed320a0610998d855034..d679ccd3d8db137f09f4e904fb9e6d7da3f9f1a5 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -331,6 +331,9 @@ 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));
+#if LL_MESH_ENABLED
+	addEntry(DAD_MESH, 			new DragAndDropEntry(&LLToolDragAndDrop::dad3dNULL,	&LLToolDragAndDrop::dad3dNULL,					&LLToolDragAndDrop::dad3dGiveInventory,		&LLToolDragAndDrop::dad3dMeshObject,			&LLToolDragAndDrop::dad3dNULL));
+#endif
 	// TODO: animation on self could play it?  edit it?
 	// TODO: gesture on self could play it?  edit it?
 };
@@ -403,7 +406,7 @@ void LLToolDragAndDrop::beginDrag(EDragAndDropType type,
 			{
 				folder_ids.push_back(cargo_id);
 			}
-			gInventory.collectDescendentsIf (
+			gInventory.collectDescendentsIf(
 				cargo_id,
 				cats,
 				items,
@@ -474,7 +477,7 @@ void LLToolDragAndDrop::beginMultiDrag(
 				{
 					cat_ids.insert(cat->getUUID());
 				}
-				gInventory.collectDescendentsIf (
+				gInventory.collectDescendentsIf(
 					cat->getUUID(),
 					cats,
 					items,
@@ -1034,6 +1037,33 @@ void LLToolDragAndDrop::dropTextureAllFaces(LLViewerObject* hit_obj,
 	hit_obj->sendTEUpdate();
 }
 
+#if LL_MESH_EANBLED
+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();
+}
+#endif
+
 /*
 void LLToolDragAndDrop::dropTextureOneFaceAvatar(LLVOAvatar* avatar, S32 hit_face, LLInventoryItem* item)
 {
@@ -1130,9 +1160,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)
@@ -1368,7 +1398,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;
 	}
@@ -1377,17 +1407,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;
 		}
@@ -1398,7 +1430,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;
@@ -1406,15 +1438,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;
 	}
@@ -1473,14 +1505,17 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_
 	case DAD_ANIMATION:
 	case DAD_GESTURE:
 	case DAD_CALLINGCARD:
+#if LL_MESH_ENABLED
+	case DAD_MESH:
+#endif
 	{
 		LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
-		if (gInventory.getItem(inv_item->getUUID())
+		if(gInventory.getItem(inv_item->getUUID())
 			&& LLGiveInventory::isInventoryGiveAcceptable(inv_item))
 		{
 			// *TODO: get multiple object transfers working
 			*accept = ACCEPT_YES_COPY_SINGLE;
-			if (drop)
+			if(drop)
 			{
 				LLIMModel::LLIMSession * session = LLIMModel::instance().findIMSession(session_id);
 				if (NULL == session)
@@ -1512,11 +1547,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)
 			{
 				LLGiveInventory::doGiveInventoryCategory(dest_agent, inv_cat, session_id);
 			}
@@ -1557,7 +1592,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;
 	}
@@ -1569,20 +1604,21 @@ EAcceptance LLToolDragAndDrop::dad3dRezAttachmentFromInv(
 
 	// 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(
@@ -1616,7 +1652,8 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnLand(
 	locateInventory(item, cat);
 	if (!item || !item->isFinished()) return ACCEPT_NO;
 
-	if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID()))
+	LLVOAvatarSelf* my_avatar = gAgentAvatarp;
+	if( !my_avatar || my_avatar->isWearingAttachment( item->getUUID() ) )
 	{
 		return ACCEPT_NO;
 	}
@@ -1641,7 +1678,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;
@@ -1649,13 +1686,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);
 	}
@@ -1677,22 +1714,23 @@ EAcceptance LLToolDragAndDrop::dad3dRezObjectOnObject(
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
 	if (!item || !item->isFinished()) return ACCEPT_NO;
-	if (!isAgentAvatarValid() || gAgentAvatarp->isWearingAttachment(item->getUUID()))
+	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);
 		}
@@ -1718,7 +1756,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;
@@ -1726,13 +1764,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);
 	}
@@ -1747,7 +1785,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;
 	}
@@ -1757,7 +1795,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezScript(
 	locateInventory(item, cat);
 	if (!item || !item->isFinished()) 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.
@@ -1778,14 +1816,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;
 	}
@@ -1795,33 +1833,46 @@ EAcceptance LLToolDragAndDrop::dad3dTextureObject(
 	locateInventory(item, cat);
 	if (!item || !item->isFinished()) 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);
+			}
 		}
+#if LL_MESH_ENABLED
+		else if (cargo_type == DAD_MESH)
+		{
+			dropMesh(obj, item, mSource, mSourceID);
+		}
+#endif
 		else
 		{
-			dropTextureOneFace(obj, face, item, mSource, mSourceID);
+			llwarns << "unsupported asset type" << llendl;
 		}
 		
 		// VEFFECT: SetTexture
@@ -1835,14 +1886,33 @@ 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);
+}
+
+#if LL_MESH_ENABLED
+EAcceptance LLToolDragAndDrop::dad3dMeshObject(
+	LLViewerObject* obj, S32 face, MASK mask, BOOL drop)
+{
+	return dad3dApplyToObject(obj, face, mask, drop, DAD_MESH);
+}
+#endif
+
+
+
+
 /*
 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);
 		}
@@ -1860,16 +1930,16 @@ EAcceptance LLToolDragAndDrop::dad3dWearItem(
 	locateInventory(item, cat);
 	if (!item || !item->isFinished()) 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.
@@ -1898,19 +1968,19 @@ EAcceptance LLToolDragAndDrop::dad3dActivateGesture(
 	locateInventory(item, cat);
 	if (!item || !item->isFinished()) 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.
@@ -1945,7 +2015,7 @@ EAcceptance LLToolDragAndDrop::dad3dWearCategory(
 	LLViewerInventoryItem* item;
 	LLViewerInventoryCategory* category;
 	locateInventory(item, category);
-	if (!category) return ACCEPT_NO;
+	if(!category) return ACCEPT_NO;
 
 	if (drop)
 	{
@@ -1958,24 +2028,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);
 		}
@@ -1996,7 +2066,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;
 	}
@@ -2016,7 +2086,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);
 	}
@@ -2060,7 +2130,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,
@@ -2089,7 +2159,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;
@@ -2157,26 +2227,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->isFinished()) return ACCEPT_NO;
-	if (!item->getPermissions().allowOperationBy(PERM_TRANSFER, gAgent.getID()))
+	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)
 		{
 			LLGiveInventory::doGiveInventoryItem(obj->getID(), item );
 		}
@@ -2193,7 +2264,7 @@ 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);
@@ -2215,12 +2286,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;
 		LLGiveInventory::doGiveInventoryCategory(obj->getID(), cat);
 	}
 	// *TODO: deal with all the issues surrounding multi-object
@@ -2238,12 +2309,12 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnLand(
 	locateInventory(item, cat);
 	if (!item || !item->isFinished()) 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);
 	}
@@ -2258,7 +2329,7 @@ EAcceptance LLToolDragAndDrop::dad3dRezFromObjectOnObject(
 	LLViewerInventoryCategory* cat;
 	locateInventory(item, cat);
 	if (!item || !item->isFinished()) 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.
@@ -2266,19 +2337,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);
 	}
@@ -2294,23 +2365,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;
@@ -2333,19 +2404,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);
 	}
@@ -2360,20 +2431,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]);
@@ -2384,16 +2455,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;
 }
 
@@ -2401,8 +2472,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++)
@@ -2419,13 +2490,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.
@@ -2451,17 +2522,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 36e69c1db3dff79e5a701c9cc80571688e6bf5d2..ceeaa8c82095c0f6c1a890a0ba78bc06887261c2 100644
--- a/indra/newview/lltooldraganddrop.h
+++ b/indra/newview/lltooldraganddrop.h
@@ -154,6 +154,10 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 							   MASK mask, BOOL drop);
 	EAcceptance dad3dTextureObject(LLViewerObject* obj, S32 face,
 								   MASK mask, BOOL drop);
+#if LL_MESH_ENABLED
+	EAcceptance dad3dMeshObject(LLViewerObject* obj, S32 face,
+								   MASK mask, BOOL drop);
+#endif
 //	EAcceptance dad3dTextureSelf(LLViewerObject* obj, S32 face,
 //								 MASK mask, BOOL drop);
 	EAcceptance dad3dWearItem(LLViewerObject* obj, S32 face,
@@ -185,6 +189,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 );
 
@@ -235,6 +244,13 @@ class LLToolDragAndDrop : public LLTool, public LLSingleton<LLToolDragAndDrop>
 									LLInventoryItem* item,
 									ESource source,
 									const LLUUID& src_id);
+#if LL_MESH_ENABLED
+	static void dropMesh(LLViewerObject* hit_obj,
+						 LLInventoryItem* item,
+						 ESource source,
+						 const LLUUID& src_id);
+#endif
+	
 	//static void	dropTextureOneFaceAvatar(LLVOAvatar* avatar,S32 hit_face,
 	//									 LLInventoryItem* item)
 
diff --git a/indra/newview/llviewerassettype.cpp b/indra/newview/llviewerassettype.cpp
index b382ff630699c4d3107a2a731ffe6cf9af6b3f13..370767002ae8caf7805dc7a2d583e9af66216218 100644
--- a/indra/newview/llviewerassettype.cpp
+++ b/indra/newview/llviewerassettype.cpp
@@ -85,6 +85,10 @@ LLViewerAssetDictionary::LLViewerAssetDictionary()
 	addEntry(LLViewerAssetType::AT_LINK, 				new ViewerAssetEntry(DAD_LINK));
 	addEntry(LLViewerAssetType::AT_LINK_FOLDER, 		new ViewerAssetEntry(DAD_LINK));
 
+#if LL_MESH_ENABLED
+	addEntry(LLViewerAssetType::AT_MESH, 				new ViewerAssetEntry(DAD_MESH));
+#endif
+
 	addEntry(LLViewerAssetType::AT_NONE, 				new ViewerAssetEntry(DAD_NONE));
 };
 
diff --git a/indra/newview/llviewercamera.cpp b/indra/newview/llviewercamera.cpp
index aa82c216d91e5fed05c0ac4ccb8cc4aaeb8bf92a..cef7c4abbbf06ee264f66fbdaeaafcc2f127e6fa 100644
--- a/indra/newview/llviewercamera.cpp
+++ b/indra/newview/llviewercamera.cpp
@@ -38,6 +38,7 @@
 // Viewer includes
 #include "llagent.h"
 #include "llagentcamera.h"
+#include "llmatrix4a.h"
 #include "llviewercontrol.h"
 #include "llviewerobjectlist.h"
 #include "llviewerregion.h"
@@ -787,21 +788,29 @@ BOOL LLViewerCamera::areVertsVisible(LLViewerObject* volumep, BOOL all_verts)
 	
 	LLMatrix4 render_mat(vo_volume->getRenderRotation(), LLVector4(vo_volume->getRenderPosition()));
 
+	LLMatrix4a render_mata;
+	render_mata.loadu(render_mat);
+	LLMatrix4a mata;
+	mata.loadu(mat);
+
 	num_faces = volume->getNumVolumeFaces();
 	for (i = 0; i < num_faces; i++)
 	{
 		const LLVolumeFace& face = volume->getVolumeFace(i);
 				
-		for (U32 v = 0; v < face.mVertices.size(); v++)
+		for (U32 v = 0; v < face.mNumVertices; v++)
 		{
-			LLVector4 vec = LLVector4(face.mVertices[v].mPosition) * mat;
+			const LLVector4a& src_vec = face.mPositions[v];
+			LLVector4a vec;
+			mata.affineTransform(src_vec, vec);
 
 			if (drawablep->isActive())
 			{
-				vec = vec * render_mat;	
+				LLVector4a t = vec;
+				render_mata.affineTransform(t, vec);
 			}
 
-			BOOL in_frustum = pointInFrustum(LLVector3(vec)) > 0;
+			BOOL in_frustum = pointInFrustum(LLVector3(vec.getF32())) > 0;
 
 			if (( !in_frustum && all_verts) ||
 				 (in_frustum && !all_verts))
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index f4b4954cbd48489da8b3176a04fac321be8a42a2..8c0c2bb45c676c11e4c879149e6526368fb3d806 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -43,6 +43,7 @@
 #include "llagent.h"
 #include "llagentcamera.h"
 #include "llconsole.h"
+#include "lldrawpoolbump.h"
 #include "lldrawpoolterrain.h"
 #include "llflexibleobject.h"
 #include "llfeaturemanager.h"
@@ -118,6 +119,10 @@ static bool handleTerrainDetailChanged(const LLSD& newvalue)
 
 static bool handleSetShaderChanged(const LLSD& newvalue)
 {
+	// changing shader level may invalidate existing cached bump maps, as the shader type determines the format of the bump map it expects - clear and repopulate the bump cache
+	gBumpImageList.destroyGL();
+	gBumpImageList.restoreGL();
+
 	LLViewerShaderMgr::instance()->setShaders();
 	return true;
 }
@@ -299,15 +304,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())
@@ -493,9 +489,15 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderTerrainDetail")->getSignal()->connect(boost::bind(&handleTerrainDetailChanged, _2));
 	gSavedSettings.getControl("RenderUseTriStrips")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderAnimateTrees")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+	gSavedSettings.getControl("RenderBakeSunlight")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+	gSavedSettings.getControl("RenderNoAlpha")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	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("RenderSpecularResX")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
+	gSavedSettings.getControl("RenderSpecularResY")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
+	gSavedSettings.getControl("RenderSpecularExponent")->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));
@@ -516,7 +518,8 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderMaxPartCount")->getSignal()->connect(boost::bind(&handleMaxPartCountChanged, _2));
 	gSavedSettings.getControl("RenderDynamicLOD")->getSignal()->connect(boost::bind(&handleRenderDynamicLODChanged, _2));
 	gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderFastAlpha")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+	gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+	gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderUseFBO")->getSignal()->connect(boost::bind(&handleRenderUseFBOChanged, _2));
@@ -526,7 +529,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));
@@ -551,8 +555,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 3482ac508ed9940035f47734e1e0317d78477bb4..d31b0f51fdc53d7e81c5e16946ca0154dca4414b 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -595,7 +595,8 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			LLPipeline::sUseOcclusion = 3;
 		}
 
-		LLPipeline::sFastAlpha = gSavedSettings.getBOOL("RenderFastAlpha");
+		LLPipeline::sAutoMaskAlphaDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaDeferred");
+		LLPipeline::sAutoMaskAlphaNonDeferred = gSavedSettings.getBOOL("RenderAutoMaskAlphaNonDeferred");
 		LLPipeline::sUseFarClip = gSavedSettings.getBOOL("RenderUseFarClip");
 		LLVOAvatar::sMaxVisible = gSavedSettings.getS32("RenderAvatarMaxVisible");
 		LLPipeline::sDelayVBUpdate = gSavedSettings.getBOOL("RenderDelayVBUpdate");
@@ -862,19 +863,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();
@@ -889,9 +900,11 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			render_ui();
 		}
 
-		gPipeline.rebuildGroups();
-
+		
 		LLSpatialGroup::sNoDelete = FALSE;
+		gPipeline.clearReferences();
+
+		gPipeline.rebuildGroups();
 	}
 
 	LLAppViewer::instance()->pingMainloopTimeout("Display:FrameStats");
@@ -936,9 +949,10 @@ void render_hud_attachments()
 		bool render_particles = gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES) && gSavedSettings.getBOOL("RenderHUDParticles");
 		
 		//only render hud objects
-		U32 mask = gPipeline.getRenderTypeMask();
+		gPipeline.pushRenderTypeMask();
+		
 		// turn off everything
-		gPipeline.setRenderTypeMask(0);
+		gPipeline.andRenderTypeMask(LLPipeline::END_RENDER_TYPES);
 		// turn on HUD
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
 		// turn on HUD particles
@@ -988,11 +1002,13 @@ void render_hud_attachments()
 		gPipeline.renderGeom(hud_cam);
 
 		LLSpatialGroup::sNoDelete = FALSE;
+		gPipeline.clearReferences();
 
 		render_hud_elements();
 
 		//restore type mask
-		gPipeline.setRenderTypeMask(mask);
+		gPipeline.popRenderTypeMask();
+
 		if (has_ui)
 		{
 			gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
@@ -1117,7 +1133,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 efe59744bca731e5b88e835a9c09186e502851e5..c953fb23e31fc14770c2c1180995fccbd1490562 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"
@@ -127,6 +128,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,9 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("hud", "floater_hud.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterHUD>);
 
 	LLFloaterReg::add("impanel", "floater_im_session.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLIMFloater>);
+#if LL_MESH_ENABLED
+	LLFloaterReg::add("import_collada", "floater_import_collada.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImportCollada>);
+#endif
 	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 +260,10 @@ 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");
-	
+#if LL_MESH_ENABLED
+	LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload");
+#endif
+
 	LLFloaterReg::add("voice_controls", "floater_voice_controls.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLCallFloater>);
 	LLFloaterReg::add("voice_effect", "floater_voice_effect.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterVoiceEffect>);
 
diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp
index 95f05b5f5f9c634052701b7fce45d5ef0b166dbe..8f2006b4319fd6c39734d20b6839e7371fa6abd2 100644
--- a/indra/newview/llviewerjoint.cpp
+++ b/indra/newview/llviewerjoint.cpp
@@ -440,13 +440,13 @@ void LLViewerJoint::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pix
 	}
 }
 
-void LLViewerJoint::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind)
+void LLViewerJoint::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update)
 {
 	for (child_list_t::iterator iter = mChildren.begin();
 		 iter != mChildren.end(); ++iter)
 	{
 		LLViewerJoint* joint = (LLViewerJoint*)(*iter);
-		joint->updateFaceData(face, pixel_area, damp_wind);
+		joint->updateFaceData(face, pixel_area, damp_wind, terse_update);
 	}
 }
 
diff --git a/indra/newview/llviewerjoint.h b/indra/newview/llviewerjoint.h
index 0d3092a0447e6fe976866bc4462452803b063060..67bd7786c3d85059b9cc7a873d73ecd16d53b0df 100644
--- a/indra/newview/llviewerjoint.h
+++ b/indra/newview/llviewerjoint.h
@@ -126,7 +126,7 @@ class LLViewerJoint :
 	PickName getPickName() { return mPickName; }
 
 	virtual void updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area);
-	virtual void updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind = FALSE);
+	virtual void updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind = FALSE, bool terse_update = false);
 	virtual BOOL updateLOD(F32 pixel_area, BOOL activate);
 	virtual void updateJointGeometry();
 	virtual void dump();
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 7225aa15238fc5c3cec5a12328fb65c35a435460..91605005e3f69406409d1766eb132ca1805330e9 100644
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -61,6 +61,7 @@
 #include "v4math.h"
 #include "m3math.h"
 #include "m4math.h"
+#include "llmatrix4a.h"
 
 #if !LL_DARWIN && !LL_LINUX && !LL_SOLARIS
 extern PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB;
@@ -382,6 +383,7 @@ const S32 NUM_AXES = 3;
 // pivot parent 0-n -- child = n+1
 
 static LLMatrix4	gJointMatUnaligned[32];
+static LLMatrix4a	gJointMatAligned[32];
 static LLMatrix3	gJointRotUnaligned[32];
 static LLVector4	gJointPivot[32];
 
@@ -467,6 +469,14 @@ void LLViewerJointMesh::uploadJointMatrices()
 		glUniform4fvARB(gAvatarMatrixParam, 45, mat);
 		stop_glerror();
 	}
+	else
+	{
+		//load gJointMatUnaligned into gJointMatAligned
+		for (joint_num = 0; joint_num < reference_mesh->mJointRenderData.count(); ++joint_num)
+		{
+			gJointMatAligned[joint_num].loadu(gJointMatUnaligned[joint_num]);
+		}
+	}
 }
 
 //--------------------------------------------------------------------
@@ -516,6 +526,8 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 
 	U32 triangle_count = 0;
 
+	S32 diffuse_channel = LLDrawPoolAvatar::sDiffuseChannel;
+
 	stop_glerror();
 	
 	//----------------------------------------------------------------
@@ -541,7 +553,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 	LLTexUnit::eTextureAddressMode old_mode = LLTexUnit::TAM_WRAP;
 	if (mTestImageName)
 	{
-		gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTestImageName);
+		gGL.getTexUnit(diffuse_channel)->bindManual(LLTexUnit::TT_TEXTURE, mTestImageName);
 
 		if (mIsTransparent)
 		{
@@ -550,24 +562,18 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 		else
 		{
 			glColor4f(0.7f, 0.6f, 0.3f, 1.f);
-			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
+			gGL.getTexUnit(diffuse_channel)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
 		}
 	}
 	else if( !is_dummy && mLayerSet )
 	{
 		if(	mLayerSet->hasComposite() )
 		{
-			gGL.getTexUnit(0)->bind(mLayerSet->getComposite());
+			gGL.getTexUnit(diffuse_channel)->bind(mLayerSet->getComposite());
 		}
 		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));
+			gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
 		}
 	}
 	else
@@ -577,25 +583,25 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 		{
 			old_mode = mTexture->getAddressMode();
 		}
-		gGL.getTexUnit(0)->bind(mTexture.get());
-		gGL.getTexUnit(0)->bind(mTexture);
-		gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+		gGL.getTexUnit(diffuse_channel)->bind(mTexture.get());
+		gGL.getTexUnit(diffuse_channel)->bind(mTexture);
+		gGL.getTexUnit(diffuse_channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 	}
 	else
 	{
-		gGL.getTexUnit(0)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
+		gGL.getTexUnit(diffuse_channel)->bind(LLViewerTextureManager::getFetchedTexture(IMG_DEFAULT));
 	}
 	
 	if (gRenderForSelect)
 	{
 		if (isTransparent())
 		{
-			gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
-			gGL.getTexUnit(0)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_CONST_ALPHA);
+			gGL.getTexUnit(diffuse_channel)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_PREV_COLOR);
+			gGL.getTexUnit(diffuse_channel)->setTextureAlphaBlend(LLTexUnit::TBO_MULT, LLTexUnit::TBS_TEX_ALPHA, LLTexUnit::TBS_CONST_ALPHA);
 		}
 		else
 		{
-			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
 		}
 	}
 	
@@ -632,13 +638,13 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 	
 	if (mTestImageName)
 	{
-		gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+		gGL.getTexUnit(diffuse_channel)->setTextureBlendType(LLTexUnit::TB_MULT);
 	}
 
 	if (mTexture.notNull() && !is_dummy)
 	{
-		gGL.getTexUnit(0)->bind(mTexture);
-		gGL.getTexUnit(0)->setTextureAddressMode(old_mode);
+		gGL.getTexUnit(diffuse_channel)->bind(mTexture);
+		gGL.getTexUnit(diffuse_channel)->setTextureAddressMode(old_mode);
 	}
 
 	return triangle_count;
@@ -649,6 +655,9 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 //-----------------------------------------------------------------------------
 void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area)
 {
+	//bump num_vertices to next multiple of 4
+	num_vertices = (num_vertices + 0x3) & ~0x3;
+
 	// Do a pre-alloc pass to determine sizes of data.
 	if (mMesh && mValid)
 	{
@@ -667,8 +676,12 @@ void LLViewerJointMesh::updateFaceSizes(U32 &num_vertices, U32& num_indices, F32
 //-----------------------------------------------------------------------------
 // updateFaceData()
 //-----------------------------------------------------------------------------
-void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind)
+static LLFastTimer::DeclareTimer FTM_AVATAR_FACE("Avatar Face");
+
+void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind, bool terse_update)
 {
+	//IF THIS FUNCTION BREAKS, SEE LLPOLYMESH CONSTRUCTOR AND CHECK ALIGNMENT OF INPUT ARRAYS
+
 	mFace = face;
 
 	if (mFace->mVertexBuffer.isNull())
@@ -676,6 +689,18 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w
 		return;
 	}
 
+	LLDrawPool *poolp = mFace->getPool();
+	BOOL hardware_skinning = (poolp && poolp->getVertexShaderLevel() > 0) ? TRUE : FALSE;
+
+	if (!hardware_skinning && terse_update)
+	{ //no need to do terse updates if we're doing software vertex skinning
+	 // since mMesh is being copied into mVertexBuffer every frame
+		return;
+	}
+
+
+	LLFastTimer t(FTM_AVATAR_FACE);
+
 	LLStrider<LLVector3> verticesp;
 	LLStrider<LLVector3> normalsp;
 	LLStrider<LLVector2> tex_coordsp;
@@ -686,37 +711,52 @@ void LLViewerJointMesh::updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_w
 	// Copy data into the faces from the polymesh data.
 	if (mMesh && mValid)
 	{
-		if (mMesh->getNumVertices())
+		const U32 num_verts = mMesh->getNumVertices();
+
+		if (num_verts)
 		{
-			stop_glerror();
 			face->getGeometryAvatar(verticesp, normalsp, tex_coordsp, vertex_weightsp, clothing_weightsp);
-			stop_glerror();
 			face->mVertexBuffer->getIndexStrider(indicesp);
-			stop_glerror();
 
-			for (U16 i = 0; i < mMesh->getNumVertices(); i++)
+			verticesp += mMesh->mFaceVertexOffset;
+			normalsp += mMesh->mFaceVertexOffset;
+			
+			F32* v = (F32*) verticesp.get();
+			F32* n = (F32*) normalsp.get();
+			
+			U32 words = num_verts*4;
+
+			LLVector4a::memcpyNonAliased16(v, (F32*) mMesh->getCoords(), words);
+			LLVector4a::memcpyNonAliased16(n, (F32*) mMesh->getNormals(), words);
+						
+			
+			if (!terse_update)
 			{
-				verticesp[mMesh->mFaceVertexOffset + i] = *(mMesh->getCoords() + i);
-				tex_coordsp[mMesh->mFaceVertexOffset + i] = *(mMesh->getTexCoords() + i);
-				normalsp[mMesh->mFaceVertexOffset + i] = *(mMesh->getNormals() + i);
-				vertex_weightsp[mMesh->mFaceVertexOffset + i] = *(mMesh->getWeights() + i);
-				if (damp_wind)
-				{
-					clothing_weightsp[mMesh->mFaceVertexOffset + i] = LLVector4(0,0,0,0);
-				}
-				else
-				{
-					clothing_weightsp[mMesh->mFaceVertexOffset + i] = (*(mMesh->getClothingWeights() + i));
-				}
+				vertex_weightsp += mMesh->mFaceVertexOffset;
+				clothing_weightsp += mMesh->mFaceVertexOffset;
+				tex_coordsp += mMesh->mFaceVertexOffset;
+		
+				F32* tc = (F32*) tex_coordsp.get();
+				F32* vw = (F32*) vertex_weightsp.get();
+				F32* cw = (F32*) clothing_weightsp.get();	
+
+				LLVector4a::memcpyNonAliased16(tc, (F32*) mMesh->getTexCoords(), num_verts*2);
+				LLVector4a::memcpyNonAliased16(vw, (F32*) mMesh->getWeights(), num_verts);	
+				LLVector4a::memcpyNonAliased16(cw, (F32*) mMesh->getClothingWeights(), num_verts*4);	
 			}
 
-			for (S32 i = 0; i < mMesh->getNumFaces(); i++)
+			const U32 idx_count = mMesh->getNumFaces()*3;
+
+			indicesp += mMesh->mFaceIndexOffset;
+
+			U16* __restrict idx = indicesp.get();
+			S32* __restrict src_idx = (S32*) mMesh->getFaces();	
+
+			const S32 offset = (S32) mMesh->mFaceVertexOffset;
+
+			for (S32 i = 0; i < idx_count; ++i)
 			{
-				for (U32 j = 0; j < 3; j++)
-				{
-					U32 k = i*3+j+mMesh->mFaceIndexOffset;
-					indicesp[k] = mMesh->getFaces()[i][j] + mMesh->mFaceVertexOffset;
-				}
+				*(idx++) = *(src_idx++)+offset;
 			}
 		}
 	}
@@ -739,89 +779,49 @@ void LLViewerJointMesh::updateGeometryOriginal(LLFace *mFace, LLPolyMesh *mMesh)
 	LLStrider<LLVector3> o_normals;
 
 	//get vertex and normal striders
-	LLVertexBuffer *buffer = mFace->mVertexBuffer;
+	LLVertexBuffer* buffer = mFace->mVertexBuffer;
 	buffer->getVertexStrider(o_vertices,  0);
 	buffer->getNormalStrider(o_normals,   0);
 
-	F32 last_weight = F32_MAX;
-	LLMatrix4 gBlendMat;
-	LLMatrix3 gBlendRotMat;
+	F32* __restrict vert = o_vertices[0].mV;
+	F32* __restrict norm = o_normals[0].mV;
+
+	const F32* __restrict weights = mMesh->getWeights();
+	const LLVector4a* __restrict coords = (LLVector4a*) mMesh->getCoords();
+	const LLVector4a* __restrict normals = (LLVector4a*) mMesh->getNormals();
+
+	U32 offset = mMesh->mFaceVertexOffset*4;
+	vert += offset;
+	norm += offset;
 
-	const F32* weights = mMesh->getWeights();
-	const LLVector3* coords = mMesh->getCoords();
-	const LLVector3* normals = mMesh->getNormals();
 	for (U32 index = 0; index < mMesh->getNumVertices(); index++)
 	{
-		U32 bidx = index + mMesh->mFaceVertexOffset;
-		
-		// blend by first matrix
-		F32 w = weights[index]; 
-		
-		// Maybe we don't have to change gBlendMat.
-		// Profiles of a single-avatar scene on a Mac show this to be a very
-		// common case.  JC
-		if (w == last_weight)
-		{
-			o_vertices[bidx] = coords[index] * gBlendMat;
-			o_normals[bidx] = normals[index] * gBlendRotMat;
-			continue;
-		}
-		
-		last_weight = w;
+		// equivalent to joint = floorf(weights[index]);
+		S32 joint = _mm_cvtt_ss2si(_mm_load_ss(weights+index));
+		F32 w = weights[index] - joint;		
 
-		S32 joint = llfloor(w);
-		w -= joint;
-		
-		// No lerp required in this case.
-		if (w == 1.0f)
+		LLMatrix4a gBlendMat;
+
+		if (w != 0.f)
 		{
-			gBlendMat = gJointMatUnaligned[joint+1];
-			o_vertices[bidx] = coords[index] * gBlendMat;
-			gBlendRotMat = gJointRotUnaligned[joint+1];
-			o_normals[bidx] = normals[index] * gBlendRotMat;
-			continue;
+			// blend between matrices and apply
+			gBlendMat.setLerp(gJointMatAligned[joint+0],
+							  gJointMatAligned[joint+1], w);
+
+			LLVector4a res;
+			gBlendMat.affineTransform(coords[index], res);
+			res.store4a(vert+index*4);
+			gBlendMat.rotate(normals[index], res);
+			res.store4a(norm+index*4);
+		}
+		else
+		{  // No lerp required in this case.
+			LLVector4a res;
+			gJointMatAligned[joint].affineTransform(coords[index], res);
+			res.store4a(vert+index*4);
+			gJointMatAligned[joint].rotate(normals[index], res);
+			res.store4a(norm+index*4);
 		}
-		
-		// Try to keep all the accesses to the matrix data as close
-		// together as possible.  This function is a hot spot on the
-		// Mac. JC
-		LLMatrix4 &m0 = gJointMatUnaligned[joint+1];
-		LLMatrix4 &m1 = gJointMatUnaligned[joint+0];
-		
-		gBlendMat.mMatrix[VX][VX] = lerp(m1.mMatrix[VX][VX], m0.mMatrix[VX][VX], w);
-		gBlendMat.mMatrix[VX][VY] = lerp(m1.mMatrix[VX][VY], m0.mMatrix[VX][VY], w);
-		gBlendMat.mMatrix[VX][VZ] = lerp(m1.mMatrix[VX][VZ], m0.mMatrix[VX][VZ], w);
-
-		gBlendMat.mMatrix[VY][VX] = lerp(m1.mMatrix[VY][VX], m0.mMatrix[VY][VX], w);
-		gBlendMat.mMatrix[VY][VY] = lerp(m1.mMatrix[VY][VY], m0.mMatrix[VY][VY], w);
-		gBlendMat.mMatrix[VY][VZ] = lerp(m1.mMatrix[VY][VZ], m0.mMatrix[VY][VZ], w);
-
-		gBlendMat.mMatrix[VZ][VX] = lerp(m1.mMatrix[VZ][VX], m0.mMatrix[VZ][VX], w);
-		gBlendMat.mMatrix[VZ][VY] = lerp(m1.mMatrix[VZ][VY], m0.mMatrix[VZ][VY], w);
-		gBlendMat.mMatrix[VZ][VZ] = lerp(m1.mMatrix[VZ][VZ], m0.mMatrix[VZ][VZ], w);
-
-		gBlendMat.mMatrix[VW][VX] = lerp(m1.mMatrix[VW][VX], m0.mMatrix[VW][VX], w);
-		gBlendMat.mMatrix[VW][VY] = lerp(m1.mMatrix[VW][VY], m0.mMatrix[VW][VY], w);
-		gBlendMat.mMatrix[VW][VZ] = lerp(m1.mMatrix[VW][VZ], m0.mMatrix[VW][VZ], w);
-
-		o_vertices[bidx] = coords[index] * gBlendMat;
-		
-		LLMatrix3 &n0 = gJointRotUnaligned[joint+1];
-		LLMatrix3 &n1 = gJointRotUnaligned[joint+0];
-		
-		gBlendRotMat.mMatrix[VX][VX] = lerp(n1.mMatrix[VX][VX], n0.mMatrix[VX][VX], w);
-		gBlendRotMat.mMatrix[VX][VY] = lerp(n1.mMatrix[VX][VY], n0.mMatrix[VX][VY], w);
-		gBlendRotMat.mMatrix[VX][VZ] = lerp(n1.mMatrix[VX][VZ], n0.mMatrix[VX][VZ], w);
-
-		gBlendRotMat.mMatrix[VY][VX] = lerp(n1.mMatrix[VY][VX], n0.mMatrix[VY][VX], w);
-		gBlendRotMat.mMatrix[VY][VY] = lerp(n1.mMatrix[VY][VY], n0.mMatrix[VY][VY], w);
-		gBlendRotMat.mMatrix[VY][VZ] = lerp(n1.mMatrix[VY][VZ], n0.mMatrix[VY][VZ], w);
-
-		gBlendRotMat.mMatrix[VZ][VX] = lerp(n1.mMatrix[VZ][VX], n0.mMatrix[VZ][VX], w);
-		gBlendRotMat.mMatrix[VZ][VY] = lerp(n1.mMatrix[VZ][VY], n0.mMatrix[VZ][VY], w);
-		gBlendRotMat.mMatrix[VZ][VZ] = lerp(n1.mMatrix[VZ][VZ], n0.mMatrix[VZ][VZ], w);
-		
-		o_normals[bidx] = normals[index] * gBlendRotMat;
 	}
 
 	buffer->setBuffer(0);
diff --git a/indra/newview/llviewerjointmesh.h b/indra/newview/llviewerjointmesh.h
index d62b0ada850874bc595ebd72111ee4908879959d..3b8d9c82b8017b0d70e1e33a38e667852a3ed3dc 100644
--- a/indra/newview/llviewerjointmesh.h
+++ b/indra/newview/llviewerjointmesh.h
@@ -140,7 +140,7 @@ class LLViewerJointMesh : public LLViewerJoint
 	/*virtual*/ U32 drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy );
 
 	/*virtual*/ void updateFaceSizes(U32 &num_vertices, U32& num_indices, F32 pixel_area);
-	/*virtual*/ void updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind = FALSE);
+	/*virtual*/ void updateFaceData(LLFace *face, F32 pixel_area, BOOL damp_wind = FALSE, bool terse_update = false);
 	/*virtual*/ BOOL updateLOD(F32 pixel_area, BOOL activate);
 	/*virtual*/ void updateJointGeometry();
 	/*virtual*/ void dump();
diff --git a/indra/newview/llviewerjointmesh_sse.cpp b/indra/newview/llviewerjointmesh_sse.cpp
index e586b910cd42208057e9ff81e666610068440149..4fb5fafad1228b96e339506deee3f2f9023c5604 100644
--- a/indra/newview/llviewerjointmesh_sse.cpp
+++ b/indra/newview/llviewerjointmesh_sse.cpp
@@ -94,8 +94,8 @@ void LLViewerJointMesh::updateGeometrySSE(LLFace *face, LLPolyMesh *mesh)
 	buffer->getNormalStrider(o_normals,   mesh->mFaceVertexOffset);
 
 	const F32*			weights			= mesh->getWeights();
-	const LLVector3*	coords			= mesh->getCoords();
-	const LLVector3*	normals			= mesh->getNormals();
+	const LLVector3*	coords			= (const LLVector3*)mesh->getCoords();
+	const LLVector3*	normals			= (const LLVector3*)mesh->getNormals();
 	for (U32 index = 0, index_end = mesh->getNumVertices(); index < index_end; ++index)
 	{
 		if( weight != weights[index])
diff --git a/indra/newview/llviewerjointmesh_sse2.cpp b/indra/newview/llviewerjointmesh_sse2.cpp
index 550044c321f0737dc7c3920ca31c973daa2ad98c..58cd75871d1699246e123762571f19ffb504dcaa 100644
--- a/indra/newview/llviewerjointmesh_sse2.cpp
+++ b/indra/newview/llviewerjointmesh_sse2.cpp
@@ -101,8 +101,8 @@ void LLViewerJointMesh::updateGeometrySSE2(LLFace *face, LLPolyMesh *mesh)
 	buffer->getNormalStrider(o_normals,   mesh->mFaceVertexOffset);
 
 	const F32*			weights			= mesh->getWeights();
-	const LLVector3*	coords			= mesh->getCoords();
-	const LLVector3*	normals			= mesh->getNormals();
+	const LLVector3*	coords			= (const LLVector3*)mesh->getCoords();
+	const LLVector3*	normals			= (const LLVector3*)mesh->getNormals();
 	for (U32 index = 0, index_end = mesh->getNumVertices(); index < index_end; ++index)
 	{
 		if( weight != weights[index])
diff --git a/indra/newview/llviewerjointmesh_vec.cpp b/indra/newview/llviewerjointmesh_vec.cpp
index 8fb9d1cf68fc745e78b37fe2e172c54fd28b6b08..a1225c9d1c93f7e8d7172105a8bbef246aeb71a4 100644
--- a/indra/newview/llviewerjointmesh_vec.cpp
+++ b/indra/newview/llviewerjointmesh_vec.cpp
@@ -52,6 +52,7 @@
 // static
 void LLViewerJointMesh::updateGeometryVectorized(LLFace *face, LLPolyMesh *mesh)
 {
+#if 0
 	static LLV4Matrix4	sJointMat[32];
 	LLDynamicArray<LLJointRenderData*>& joint_data = mesh->getReferenceMesh()->mJointRenderData;
 	S32 j, joint_num, joint_end = joint_data.count();
@@ -98,4 +99,5 @@ void LLViewerJointMesh::updateGeometryVectorized(LLFace *face, LLPolyMesh *mesh)
 	}
 
 	buffer->setBuffer(0);
+#endif
 }
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 2c7ae539ce7b5ce62869f658ba81e0ef4512e741..b4a10d709eb1ab0d8f5f21e87ddbd717e9e77b38 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -168,7 +168,6 @@ LLMenuItemCallGL* gBusyMenu = NULL;
 // Local prototypes
 
 // File Menu
-const char* upload_pick(void* data);
 void handle_compress_image(void*);
 
 
@@ -455,7 +454,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);
@@ -858,6 +857,10 @@ U32 info_display_from_string(std::string info_display)
 	{
 		return LLPipeline::RENDER_DEBUG_BBOXES;
 	}
+	else if ("normals" == info_display)
+	{
+		return LLPipeline::RENDER_DEBUG_NORMALS;
+	}
 	else if ("points" == info_display)
 	{
 		return LLPipeline::RENDER_DEBUG_POINTS;
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index 5570fe5fec76133dd3ba8fd2fc467a09d6c17214..af4549f7e13a36ab9f1c08dec21a1431f79f1bca 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -40,6 +40,8 @@
 #include "llfilepicker.h"
 #include "llfloaterreg.h"
 #include "llbuycurrencyhtml.h"
+#include "llfloaterimportcollada.h"
+#include "llfloatermodelpreview.h"
 #include "llfloatersnapshot.h"
 #include "llimage.h"
 #include "llimagebmp.h"
@@ -64,7 +66,8 @@
 #include "llappviewer.h"
 #include "lluploaddialog.h"
 #include "lltrans.h"
-
+#include "llfloaterbuycurrency.h"
+#include "llfloaterimportcollada.h"
 
 // linden libraries
 #include "llassetuploadresponders.h"
@@ -72,6 +75,7 @@
 #include "llhttpclient.h"
 #include "llnotificationsutil.h"
 #include "llsdserialize.h"
+#include "llsdutil.h"
 #include "llstring.h"
 #include "lltransactiontypes.h"
 #include "lluuid.h"
@@ -90,6 +94,89 @@ class LLFileEnableUpload : public view_listener_t
 	}
 };
 
+class LLFileEnableUploadModel : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		return true;
+	}
+};
+
+class LLMeshEnabled : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		return gSavedSettings.getBOOL("MeshEnabled");
+	}
+};
+
+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 +190,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 +205,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 +350,35 @@ class LLFileUploadImage : public view_listener_t
 	}
 };
 
+#if LL_MESH_ENABLED
+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;
+	}
+};
+#endif
+	
 class LLFileUploadSound : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -318,11 +437,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()
@@ -477,16 +609,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();
@@ -511,7 +647,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")
 	{
@@ -525,7 +661,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")
@@ -540,7 +676,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")
@@ -555,7 +691,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")
@@ -570,7 +706,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")
@@ -598,7 +734,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")	 	
@@ -638,7 +774,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)	 	
@@ -666,7 +802,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	 	
@@ -708,7 +844,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);	 	
@@ -722,7 +858,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
 	{
@@ -768,9 +904,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
 	{
@@ -784,9 +932,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;
@@ -889,98 +1043,330 @@ 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;
+
+#if LL_MESH_ENABLED
+	std::string url = gAgent.getRegion()->getCapability(
+		"NewFileAgentInventory");
+
+	if ( !url.empty() )
 	{
-		return ;
+		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
+#endif
+	{
+		// 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;
+			}
+		}
 
-	LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
-	
-	if( LLAssetType::AT_SOUND == asset_type )
+		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);
+	}
+}
+
+#if LL_MESH_ENABLED
+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)
+}
+#endif
+
+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 )
 	{
-		inv_type = LLInventoryType::defaultForAssetType(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 )
+	{
+		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");
+#if LL_MESH_ENABLED
+	view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
+	view_listener_t::addCommit(new LLFileUploadScene(), "File.UploadScene");
+#endif
 	view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
 	view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
 	view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
@@ -990,6 +1376,8 @@ 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");
+	view_listener_t::addMenu(new LLMeshEnabled(), "File.MeshEnabled");
+
 	// "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..bb7cfce86270ff12a444ceec08ff1eea266da1a9 100644
--- a/indra/newview/llviewermenufile.h
+++ b/indra/newview/llviewermenufile.h
@@ -34,35 +34,122 @@
 #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);
+
+#if LL_MESH_ENABLED
+// 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);
+#endif
+
+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 3d107555bf7ce886c58d924dec505e06c0c9cb3a..f9f5bed0a5cb3a550c0d5c673b89c2369ecac17f 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -3602,6 +3602,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)
 {
@@ -3760,6 +3761,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 ee89680fea62f4c10d35ce767ee974d6159f3fac..1e226ebb65cf3889d5ab48ad0ab50e1ad0970a21 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -53,6 +53,7 @@
 #include "llprimitive.h"
 #include "llquantize.h"
 #include "llregionhandle.h"
+#include "llsdserialize.h"
 #include "lltree_common.h"
 #include "llxfermanager.h"
 #include "message.h"
@@ -199,6 +200,7 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
 	mGLName(0),
 	mbCanSelect(TRUE),
 	mFlags(0),
+	mPhysicsShapeType(0),
 	mDrawable(),
 	mCreateSelected(FALSE),
 	mRenderMedia(FALSE),
@@ -2861,21 +2863,26 @@ void LLViewerObject::setScale(const LLVector3 &scale, BOOL damped)
 	}
 }
 
-void LLViewerObject::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax)
+void LLViewerObject::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
 {
-	LLVector3 center = getRenderPosition();
-	LLVector3 size = getScale();
-	newMin.setVec(center-size);
-	newMax.setVec(center+size);
-	mDrawable->setPositionGroup((newMin + newMax) * 0.5f);
+	LLVector4a center;
+	center.load3(getRenderPosition().mV);
+	LLVector4a size;
+	size.load3(getScale().mV);
+	newMin.setSub(center, size);
+	newMax.setAdd(center, size);
+	
+	mDrawable->setPositionGroup(center);
 }
 
 F32 LLViewerObject::getBinRadius()
 {
 	if (mDrawable.notNull())
 	{
-		const LLVector3* ext = mDrawable->getSpatialExtents();
-		return (ext[1]-ext[0]).magVec();
+		const LLVector4a* ext = mDrawable->getSpatialExtents();
+		LLVector4a diff;
+		diff.setSub(ext[1], ext[0]);
+		return diff.length3();
 	}
 	
 	return getScale().magVec();
@@ -2941,7 +2948,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();
@@ -3467,12 +3474,21 @@ BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVect
 		return FALSE;
 	}
 
-	const LLVector3* ext = mDrawable->getSpatialExtents();
+	const LLVector4a* ext = mDrawable->getSpatialExtents();
+
+	//VECTORIZE THIS
+	LLVector4a center;
+	center.setAdd(ext[1], ext[0]);
+	center.mul(0.5f);
+	LLVector4a size;
+	size.setSub(ext[1], ext[0]);
+	size.mul(0.5f);
 
-	LLVector3 center = (ext[1]+ext[0])*0.5f;
-	LLVector3 size = (ext[1]-ext[0])*0.5f;
+	LLVector4a starta, enda;
+	starta.load3(start.mV);
+	enda.load3(end.mV);
 
-	return LLLineSegmentBoxIntersect(start, end, center, size);
+	return LLLineSegmentBoxIntersect(starta, enda, center, size);
 }
 
 U8 LLViewerObject::getMediaType() const
@@ -4961,7 +4977,14 @@ void LLViewerObject::updateFlags()
 	gMessageSystem->addBOOL("IsTemporary", flagTemporaryOnRez() );
 	gMessageSystem->addBOOL("IsPhantom", flagPhantom() );
 	gMessageSystem->addBOOL("CastsShadows", flagCastShadows() );
+	gMessageSystem->nextBlock("ExtraPhysics");
+	gMessageSystem->addU8("PhysicsShapeType", getPhysicsShapeType() );
 	gMessageSystem->sendReliable( regionp->getHost() );
+
+	if (getPhysicsShapeType() != 0)
+	{
+		llwarns << "sent non default physics rep" << llendl;
+	}
 }
 
 BOOL LLViewerObject::setFlags(U32 flags, BOOL state)
@@ -4993,6 +5016,12 @@ BOOL LLViewerObject::setFlags(U32 flags, BOOL state)
 	return setit;
 }
 
+void LLViewerObject::setPhysicsShapeType(U8 type)
+{
+	mPhysicsShapeType = type;
+	updateFlags();
+}
+
 void LLViewerObject::applyAngularVelocity(F32 dt)
 {
 	//do target omega here
@@ -5204,3 +5233,67 @@ void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplif
 	return ;
 }
 
+//virtual
+LLVOAvatar* LLViewerObject::getAvatar() const
+{
+	if (isAttachment())
+	{
+		LLViewerObject* vobj = (LLViewerObject*) getParent();
+
+		while (vobj && !vobj->asAvatar())
+		{
+			vobj = (LLViewerObject*) vobj->getParent();
+		}
+
+		return (LLVOAvatar*) vobj;
+	}
+
+	return NULL;
+}
+
+
+class ObjectPhysicsProperties : public LLHTTPNode
+{
+public:
+	virtual void post(
+		ResponsePtr responder,
+		const LLSD& context,
+		const LLSD& input) const
+	{
+		LLSD objectData = input["body"]["ObjectData"];
+		S32 numEntries = objectData.size();
+		
+		for ( S32 i = 0; i < numEntries; i++ )
+		{
+			LLSD& currObjectData = objectData[i];
+			U32 localID = currObjectData["LocalID"].asInteger();
+
+			// Iterate through nodes at end, since it can be on both the regular AND hover list
+			struct f : public LLSelectedNodeFunctor
+			{
+				U32 mID;
+				f(const U32& id) : mID(id) {}
+				virtual bool apply(LLSelectNode* node)
+				{
+					return (node->getObject() && node->getObject()->mLocalID == mID );
+				}
+			} func(localID);
+
+			LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstNode(&func);
+
+			if (node)
+			{
+				// The LLSD message builder doesn't know how to handle U8, so we need to send as S8 and cast
+				U8 physicsShapeType = (U8)currObjectData["PhysicsShapeType"].asInteger();
+
+				node->getObject()->setPhysicsShapeType(physicsShapeType);
+			}	
+		}
+		
+		dialog_refresh_all();
+	};
+};
+
+LLHTTPRegistration<ObjectPhysicsProperties>
+	gHTTPRegistrationObjectPhysicsProperties("/message/ObjectPhysicsProperties");
+
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index be83fb7ef8a292fae89327b7238135388926543d..6ebd1cbe212ade436032b69456c0be9c976f2035 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -181,6 +181,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	void			setOnActiveList(BOOL on_active)		{ mOnActiveList = on_active; }
 
 	virtual BOOL	isAttachment() const { return FALSE; }
+	virtual LLVOAvatar* getAvatar() const;  //get the avatar this object is attached to, or NULL if object is not an attachment
 	virtual BOOL	isHUDAttachment() const { return FALSE; }
 	virtual void 	updateRadius() {};
 	virtual F32 	getVObjRadius() const; // default implemenation is mDrawable->getRadius()
@@ -229,6 +230,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
@@ -371,7 +373,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 
 	void markForUpdate(BOOL priority);
 	void updateVolume(const LLVolumeParams& volume_params);
-	virtual	void updateSpatialExtents(LLVector3& min, LLVector3& max);
+	virtual	void updateSpatialExtents(LLVector4a& min, LLVector4a& max);
 	virtual F32 getBinRadius();
 	
 	LLBBox				getBoundingBoxAgent() const;
@@ -384,7 +386,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	void clearDrawableState(U32 state, BOOL recursive = TRUE);
 
 	// Called when the drawable shifts
-	virtual void onShift(const LLVector3 &shift_vector)	{ }
+	virtual void onShift(const LLVector4a &shift_vector)	{ }
 		
 	//////////////////////////////////////
 	//
@@ -459,6 +461,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	inline BOOL		flagCameraDecoupled() const		{ return ((mFlags & FLAGS_CAMERA_DECOUPLED) != 0); }
 	inline BOOL		flagObjectMove() const			{ return ((mFlags & FLAGS_OBJECT_MOVE) != 0); }
 
+	inline U8       getPhysicsShapeType() const     { return mPhysicsShapeType; }
+	
 	bool getIncludeInSearch() const;
 	void setIncludeInSearch(bool include_in_search);
 
@@ -474,6 +478,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 
 	void updateFlags();
 	BOOL setFlags(U32 flag, BOOL state);
+	void setPhysicsShapeType(U8 type);
 	
 	virtual void dump() const;
 	static U32		getNumZombieObjects()			{ return sNumZombieObjects; }
@@ -553,6 +558,9 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	// Grabbed from UPDATE_FLAGS
 	U32				mFlags;
 
+	// Sent to sim in UPDATE_FLAGS, received in ObjectPhysicsProperties
+	U8              mPhysicsShapeType;
+
 	// Pipeline classes
 	LLPointer<LLDrawable> mDrawable;
 
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/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp
index 6b480ccf8e5aeff3299757effdf4fd7080c5ffc3..41848e8b7add89350b461f9c53405bc8b6fa1006 100644
--- a/indra/newview/llviewerpartsim.cpp
+++ b/indra/newview/llviewerpartsim.cpp
@@ -161,8 +161,8 @@ LLViewerPartGroup::LLViewerPartGroup(const LLVector3 &center_agent, const F32 bo
 
 	if (group != NULL)
 	{
-		LLVector3 center(group->mOctreeNode->getCenter());
-		LLVector3 size(group->mOctreeNode->getSize());
+		LLVector3 center(group->mOctreeNode->getCenter().getF32());
+		LLVector3 size(group->mOctreeNode->getSize().getF32());
 		size += LLVector3(0.01f, 0.01f, 0.01f);
 		mMinObjPos = center - size;
 		mMaxObjPos = center + size;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index da240cedbbd385c33218de9bf9103cd13be41ba4..ccec972c0d8acd58752cf2a89c3ca980a65ce74f 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -174,7 +174,7 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder
 				mRegion->showReleaseNotes();
 			}
 		}
-		
+
 		if (STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
 		{
 			LLStartUp::setStartupState( STATE_SEED_CAP_GRANTED );
@@ -1497,12 +1497,16 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("FetchLib");
 	capabilityNames.append("FetchLibDescendents");
 	capabilityNames.append("GetTexture");
+	capabilityNames.append("GetMesh");
+	capabilityNames.append("GetObjectCost");
 	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");
@@ -1517,6 +1521,7 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("SendUserReport");
 	capabilityNames.append("SendUserReportWithScreenshot");
 	capabilityNames.append("ServerReleaseNotes");
+	capabilityNames.append("SimulatorFeatures");
 	capabilityNames.append("StartGroupProposal");
 	capabilityNames.append("TextureStats");
 	capabilityNames.append("UntrustedSimulatorMessage");
@@ -1529,6 +1534,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");
@@ -1575,6 +1581,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..49eeffe22892d72d1f926cba307cbce206d3c9d9 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -77,6 +77,12 @@ LLGLSLShader		gObjectFullbrightShinyProgram;
 LLGLSLShader		gObjectShinyProgram;
 LLGLSLShader		gObjectShinyWaterProgram;
 
+//object hardware skinning shaders
+LLGLSLShader		gSkinnedObjectSimpleProgram;
+LLGLSLShader		gSkinnedObjectFullbrightProgram;
+LLGLSLShader		gSkinnedObjectFullbrightShinyProgram;
+LLGLSLShader		gSkinnedObjectShinySimpleProgram;
+
 //environment shaders
 LLGLSLShader		gTerrainProgram;
 LLGLSLShader		gTerrainWaterProgram;
@@ -107,6 +113,9 @@ LLGLSLShader			gDeferredImpostorProgram;
 LLGLSLShader			gDeferredEdgeProgram;
 LLGLSLShader			gDeferredWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
+LLGLSLShader			gDeferredSkinnedDiffuseProgram;
+LLGLSLShader			gDeferredSkinnedBumpProgram;
+LLGLSLShader			gDeferredSkinnedAlphaProgram;
 LLGLSLShader			gDeferredBumpProgram;
 LLGLSLShader			gDeferredTerrainProgram;
 LLGLSLShader			gDeferredTreeProgram;
@@ -121,6 +130,7 @@ LLGLSLShader			gDeferredBlurLightProgram;
 LLGLSLShader			gDeferredSoftenProgram;
 LLGLSLShader			gDeferredShadowProgram;
 LLGLSLShader			gDeferredAvatarShadowProgram;
+LLGLSLShader			gDeferredAttachmentShadowProgram;
 LLGLSLShader			gDeferredAlphaProgram;
 LLGLSLShader			gDeferredFullbrightProgram;
 LLGLSLShader			gDeferredGIProgram;
@@ -148,6 +158,10 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gObjectSimpleProgram);
 	mShaderList.push_back(&gObjectFullbrightProgram);
 	mShaderList.push_back(&gObjectFullbrightShinyProgram);
+	mShaderList.push_back(&gSkinnedObjectSimpleProgram);
+	mShaderList.push_back(&gSkinnedObjectFullbrightProgram);
+	mShaderList.push_back(&gSkinnedObjectFullbrightShinyProgram);
+	mShaderList.push_back(&gSkinnedObjectShinySimpleProgram);
 	mShaderList.push_back(&gTerrainProgram);
 	mShaderList.push_back(&gTerrainWaterProgram);
 	mShaderList.push_back(&gObjectSimpleWaterProgram);
@@ -161,6 +175,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gDeferredLightProgram);
 	mShaderList.push_back(&gDeferredMultiLightProgram);
 	mShaderList.push_back(&gDeferredAlphaProgram);
+	mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
 	mShaderList.push_back(&gDeferredPostGIProgram);
 	mShaderList.push_back(&gDeferredEdgeProgram);
@@ -195,6 +210,7 @@ void LLViewerShaderMgr::initAttribsAndUniforms(void)
 		mReservedAttribs.push_back("materialColor");
 		mReservedAttribs.push_back("specularColor");
 		mReservedAttribs.push_back("binormal");
+		mReservedAttribs.push_back("object_weight");
 
 		mAvatarAttribs.reserve(5);
 		mAvatarAttribs.push_back("weight");
@@ -317,10 +333,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 +390,11 @@ 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 (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
+		    gSavedSettings.getBOOL("RenderDeferred"))
 		{
-			if (gSavedSettings.getBOOL("RenderDeferredShadow"))
+			if (gSavedSettings.getS32("RenderShadowDetail") > 0)
 			{
 				if (gSavedSettings.getBOOL("RenderDeferredGI"))
 				{ //shadows + gi
@@ -393,6 +409,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"))
@@ -481,6 +515,9 @@ void LLViewerShaderMgr::setShaders()
 			if (!loadShadersDeferred())
 			{
 				gSavedSettings.setBOOL("RenderDeferred", FALSE);
+				reentrance = false;
+				setShaders();
+				return;
 			}
 #endif
 		}
@@ -517,6 +554,8 @@ void LLViewerShaderMgr::setShaders()
 		gViewerWindow->setCursor(UI_CURSOR_ARROW);
 	}
 	gPipeline.createGLBuffers();
+
+	reentrance = false;
 }
 
 void LLViewerShaderMgr::unloadShaders()
@@ -529,6 +568,13 @@ void LLViewerShaderMgr::unloadShaders()
 	gObjectShinyProgram.unload();
 	gObjectFullbrightShinyProgram.unload();
 	gObjectShinyWaterProgram.unload();
+
+	gSkinnedObjectSimpleProgram.unload();
+	gSkinnedObjectFullbrightProgram.unload();
+	gSkinnedObjectFullbrightShinyProgram.unload();
+	gSkinnedObjectShinySimpleProgram.unload();
+	
+
 	gWaterProgram.unload();
 	gUnderWaterProgram.unload();
 	gTerrainProgram.unload();
@@ -548,6 +594,9 @@ void LLViewerShaderMgr::unloadShaders()
 	gPostNightVisionProgram.unload();
 
 	gDeferredDiffuseProgram.unload();
+	gDeferredSkinnedDiffuseProgram.unload();
+	gDeferredSkinnedBumpProgram.unload();
+	gDeferredSkinnedAlphaProgram.unload();
 
 	mVertexShaderLevel[SHADER_LIGHTING] = 0;
 	mVertexShaderLevel[SHADER_OBJECT] = 0;
@@ -606,6 +655,7 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 	shaders.push_back( make_pair( "lighting/lightSpecularV.glsl",			mVertexShaderLevel[SHADER_LIGHTING] ) );
 	shaders.push_back( make_pair( "windlight/atmosphericsV.glsl",			mVertexShaderLevel[SHADER_WINDLIGHT] ) );
 	shaders.push_back( make_pair( "avatar/avatarSkinV.glsl",				1 ) );
+	shaders.push_back( make_pair( "avatar/objectSkinV.glsl",				1 ) );
 
 	// We no longer have to bind the shaders to global glhandles, they are automatically added to a map now.
 	for (U32 i = 0; i < shaders.size(); i++)
@@ -861,6 +911,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	{
 		gDeferredTreeProgram.unload();
 		gDeferredDiffuseProgram.unload();
+		gDeferredSkinnedDiffuseProgram.unload();
+		gDeferredSkinnedBumpProgram.unload();
+		gDeferredSkinnedAlphaProgram.unload();
 		gDeferredBumpProgram.unload();
 		gDeferredImpostorProgram.unload();
 		gDeferredTerrainProgram.unload();
@@ -873,6 +926,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSoftenProgram.unload();
 		gDeferredShadowProgram.unload();
 		gDeferredAvatarShadowProgram.unload();
+		gDeferredAttachmentShadowProgram.unload();
 		gDeferredAvatarProgram.unload();
 		gDeferredAvatarAlphaProgram.unload();
 		gDeferredAlphaProgram.unload();
@@ -884,7 +938,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredGIProgram.unload();
 		gDeferredGIFinalProgram.unload();
 		gDeferredWaterProgram.unload();
-		return FALSE;
+		return TRUE;
 	}
 
 	mVertexShaderLevel[SHADER_AVATAR] = 1;
@@ -901,6 +955,44 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredDiffuseProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredSkinnedDiffuseProgram.mName = "Deferred Skinned Diffuse Shader";
+		gDeferredSkinnedDiffuseProgram.mFeatures.hasObjectSkinning = true;
+		gDeferredSkinnedDiffuseProgram.mShaderFiles.clear();
+		gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSkinnedDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSkinnedDiffuseProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredSkinnedDiffuseProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredSkinnedBumpProgram.mName = "Deferred Skinned Bump Shader";
+		gDeferredSkinnedBumpProgram.mFeatures.hasObjectSkinning = true;
+		gDeferredSkinnedBumpProgram.mShaderFiles.clear();
+		gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSkinnedBumpProgram.mShaderFiles.push_back(make_pair("deferred/bumpF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSkinnedBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredSkinnedBumpProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredSkinnedAlphaProgram.mName = "Deferred Skinned Alpha Shader";
+		gDeferredSkinnedAlphaProgram.mFeatures.hasObjectSkinning = true;
+		gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = true;
+		gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true;
+		gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true;
+		gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = true;
+		gDeferredSkinnedAlphaProgram.mShaderFiles.clear();
+		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSkinnedAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDeferredBumpProgram.mName = "Deferred Bump Shader";
@@ -973,10 +1065,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);
 	}
@@ -1065,6 +1168,17 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredAvatarShadowProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
 	}
 
+	if (success)
+	{
+		gDeferredAttachmentShadowProgram.mName = "Deferred Attachment Shadow Shader";
+		gDeferredAttachmentShadowProgram.mFeatures.hasObjectSkinning = true;
+		gDeferredAttachmentShadowProgram.mShaderFiles.clear();
+		gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAttachmentShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredAttachmentShadowProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gTerrainProgram.mName = "Deferred Terrain Shader";
@@ -1097,7 +1211,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarAlphaProgram.mFeatures.hasLighting = true;
 		gDeferredAvatarAlphaProgram.mShaderFiles.clear();
 		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredAvatarAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredAvatarAlphaProgram.createShader(&mAvatarAttribs, &mAvatarUniforms);
 	}
@@ -1184,6 +1298,11 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectSimpleWaterProgram.unload();
 		gObjectFullbrightProgram.unload();
 		gObjectFullbrightWaterProgram.unload();
+		gSkinnedObjectSimpleProgram.unload();
+		gSkinnedObjectFullbrightProgram.unload();
+		gSkinnedObjectFullbrightShinyProgram.unload();
+		gSkinnedObjectShinySimpleProgram.unload();
+	
 		return FALSE;
 	}
 
@@ -1293,6 +1412,68 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
 	}
 
+	if (success)
+	{
+		gSkinnedObjectSimpleProgram.mName = "Skinned Simple Shader";
+		gSkinnedObjectSimpleProgram.mFeatures.calculatesLighting = true;
+		gSkinnedObjectSimpleProgram.mFeatures.calculatesAtmospherics = true;
+		gSkinnedObjectSimpleProgram.mFeatures.hasGamma = true;
+		gSkinnedObjectSimpleProgram.mFeatures.hasAtmospherics = true;
+		gSkinnedObjectSimpleProgram.mFeatures.hasLighting = true;
+		gSkinnedObjectSimpleProgram.mFeatures.hasObjectSkinning = true;
+		gSkinnedObjectSimpleProgram.mShaderFiles.clear();
+		gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gSkinnedObjectSimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gSkinnedObjectSimpleProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gSkinnedObjectFullbrightProgram.mName = "Skinned Fullbright Shader";
+		gSkinnedObjectFullbrightProgram.mFeatures.calculatesAtmospherics = true;
+		gSkinnedObjectFullbrightProgram.mFeatures.hasGamma = true;
+		gSkinnedObjectFullbrightProgram.mFeatures.hasTransport = true;
+		gSkinnedObjectFullbrightProgram.mFeatures.isFullbright = true;
+		gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true;
+		gSkinnedObjectFullbrightProgram.mShaderFiles.clear();
+		gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gSkinnedObjectFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gSkinnedObjectFullbrightProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gSkinnedObjectFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader";
+		gSkinnedObjectFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true;
+		gSkinnedObjectFullbrightShinyProgram.mFeatures.hasGamma = true;
+		gSkinnedObjectFullbrightShinyProgram.mFeatures.hasTransport = true;
+		gSkinnedObjectFullbrightShinyProgram.mFeatures.isShiny = true;
+		gSkinnedObjectFullbrightShinyProgram.mFeatures.isFullbright = true;
+		gSkinnedObjectFullbrightShinyProgram.mFeatures.hasObjectSkinning = true;
+		gSkinnedObjectFullbrightShinyProgram.mShaderFiles.clear();
+		gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gSkinnedObjectFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gSkinnedObjectFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
+	}
+
+	if (success)
+	{
+		gSkinnedObjectShinySimpleProgram.mName = "Skinned Shiny Simple Shader";
+		gSkinnedObjectShinySimpleProgram.mFeatures.calculatesLighting = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.calculatesAtmospherics = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.hasGamma = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true;
+		gSkinnedObjectShinySimpleProgram.mShaderFiles.clear();
+		gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gSkinnedObjectShinySimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gSkinnedObjectShinySimpleProgram.createShader(NULL, &mShinyUniforms);
+	}
 
 	if( !success )
 	{
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index ac2b4624e02ac019e70b959f35cbd5a7a91fee1d..da16a384279f525cd9863b8af852319eaabd041d 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -82,6 +82,7 @@ class LLViewerShaderMgr: public LLShaderMgr
 		MATERIAL_COLOR = 0,
 		SPECULAR_COLOR,
 		BINORMAL,
+		OBJECT_WEIGHT,
 		END_RESERVED_ATTRIBS
 	} eGLSLReservedAttribs;
 	
@@ -313,6 +314,11 @@ extern LLGLSLShader			gObjectFullbrightShinyProgram;
 extern LLGLSLShader			gObjectShinyProgram;
 extern LLGLSLShader			gObjectShinyWaterProgram;
 
+extern LLGLSLShader			gSkinnedObjectSimpleProgram;
+extern LLGLSLShader			gSkinnedObjectFullbrightProgram;
+extern LLGLSLShader			gSkinnedObjectFullbrightShinyProgram;
+extern LLGLSLShader			gSkinnedObjectShinySimpleProgram;
+
 //environment shaders
 extern LLGLSLShader			gTerrainProgram;
 extern LLGLSLShader			gTerrainWaterProgram;
@@ -343,6 +349,9 @@ extern LLGLSLShader			gDeferredImpostorProgram;
 extern LLGLSLShader			gDeferredEdgeProgram;
 extern LLGLSLShader			gDeferredWaterProgram;
 extern LLGLSLShader			gDeferredDiffuseProgram;
+extern LLGLSLShader			gDeferredSkinnedDiffuseProgram;
+extern LLGLSLShader			gDeferredSkinnedBumpProgram;
+extern LLGLSLShader			gDeferredSkinnedAlphaProgram;
 extern LLGLSLShader			gDeferredBumpProgram;
 extern LLGLSLShader			gDeferredTerrainProgram;
 extern LLGLSLShader			gDeferredTreeProgram;
@@ -360,6 +369,7 @@ extern LLGLSLShader			gDeferredShadowProgram;
 extern LLGLSLShader			gDeferredPostGIProgram;
 extern LLGLSLShader			gDeferredPostProgram;
 extern LLGLSLShader			gDeferredAvatarShadowProgram;
+extern LLGLSLShader			gDeferredAttachmentShadowProgram;
 extern LLGLSLShader			gDeferredAlphaProgram;
 extern LLGLSLShader			gDeferredFullbrightProgram;
 extern LLGLSLShader			gDeferredAvatarAlphaProgram;
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index bdc34d0f18dd310f20d69ca1d8dc5c745c85fd39..6ada122662812445b9676996a27b00a68c22432c 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 59efae4cb21aabc01bdfbb471239d659c5e9e0e5..697e8afa65e90ccf0e9f9df826051d39918bb0df 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -535,6 +535,9 @@ 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;
+#if LL_MESH_ENABLED
+			case LLAssetType::AT_MESH:          img_name = "Inv_Mesh";	    break;
+#endif
 			default: llassert(0);
 		}
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index 9b5b210bf7297abf99aae621d3287cf97179635a..b2c874e35558e17139783d849737fb4bf6f84f4b 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -802,7 +802,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() ;
@@ -1374,8 +1374,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();
@@ -2610,7 +2617,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 0a65cb7330f45ea77f9f91f38b52da0e0874a71b..5e5b0afab6ceed77316e3f03a06601c55d528ea6 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"
@@ -230,6 +230,8 @@ LLVector2       gDebugRaycastTexCoord;
 LLVector3       gDebugRaycastNormal;
 LLVector3       gDebugRaycastBinormal;
 S32				gDebugRaycastFaceHit;
+LLVector3		gDebugRaycastStart;
+LLVector3		gDebugRaycastEnd;
 
 // HUD display lines in lower right
 BOOL				gDisplayWindInfo = FALSE;
@@ -320,7 +322,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;
 
@@ -585,6 +587,54 @@ class LLDebugText
 				ypos += y_inc;
 			}
 		}
+
+
+		if (gSavedSettings.getBOOL("DebugShowUploadCost"))
+		{
+#if LL_MESH_ENABLED
+			addText(xpos, ypos, llformat("       Meshes: L$%d", gPipeline.mDebugMeshUploadCost));
+			ypos += y_inc/2;
+#endif
+			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;
+		}
+
+#if LL_MESH_ENABLED
+		//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;
+		}
+#endif
 	}
 
 	void draw()
@@ -1377,7 +1427,7 @@ LLViewerWindow::LLViewerWindow(
 		gSavedSettings.getBOOL("DisableVerticalSync"),
 		!gNoRender,
 		ignore_pixel_depth,
-		gSavedSettings.getU32("RenderFSAASamples"));
+		0); //gSavedSettings.getU32("RenderFSAASamples"));
 
 	if (!LLAppViewer::instance()->restoreErrorTrap())
 	{
@@ -2484,7 +2534,9 @@ void LLViewerWindow::updateUI()
 											  &gDebugRaycastIntersection,
 											  &gDebugRaycastTexCoord,
 											  &gDebugRaycastNormal,
-											  &gDebugRaycastBinormal);
+											  &gDebugRaycastBinormal,
+											  &gDebugRaycastStart,
+											  &gDebugRaycastEnd);
 	}
 
 	updateMouseDelta();
@@ -3429,7 +3481,9 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
 												LLVector3 *intersection,
 												LLVector2 *uv,
 												LLVector3 *normal,
-												LLVector3 *binormal)
+												LLVector3 *binormal,
+												LLVector3* start,
+												LLVector3* end)
 {
 	S32 x = mouse_x;
 	S32 y = mouse_y;
@@ -3461,7 +3515,16 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
 	LLVector3 mouse_world_start = mouse_point_global;
 	LLVector3 mouse_world_end   = mouse_point_global + mouse_direction_global * depth;
 
-	
+	if (start)
+	{
+		*start = mouse_world_start;
+	}
+
+	if (end)
+	{
+		*end = mouse_world_end;
+	}
+
 	LLViewerObject* found = NULL;
 
 	if (this_object)  // check only this object
@@ -3863,140 +3926,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.
@@ -4756,8 +4685,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)
 	{
@@ -4767,7 +4697,7 @@ BOOL LLViewerWindow::changeDisplaySettings(BOOL fullscreen, LLCoordScreen size,
 			mWindow->setSize(size);
 		}
 
-		if (fsaa == old_fsaa)
+		//if (fsaa == old_fsaa)
 		{
 			return TRUE;
 		}
@@ -4796,13 +4726,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/llviewerwindow.h b/indra/newview/llviewerwindow.h
index 410445d97fa9e53d2fcf73ddc615fbc87899982b..156a1ff8ad07879e6cbfa6a5e61b97739ee9bc07 100644
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -361,7 +361,9 @@ class LLViewerWindow : public LLWindowCallbacks
 									LLVector3 *intersection = NULL,
 									LLVector2 *uv = NULL,
 									LLVector3 *normal = NULL,
-									LLVector3 *binormal = NULL);
+									LLVector3 *binormal = NULL,
+									LLVector3* start = NULL,
+									LLVector3* end = NULL);
 	
 	
 	// Returns a pointer to the last object hit
@@ -507,6 +509,8 @@ extern LLVector2        gDebugRaycastTexCoord;
 extern LLVector3        gDebugRaycastNormal;
 extern LLVector3        gDebugRaycastBinormal;
 extern S32				gDebugRaycastFaceHit;
+extern LLVector3		gDebugRaycastStart;
+extern LLVector3		gDebugRaycastEnd;
 
 extern S32 CHAT_BAR_HEIGHT; 
 
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 3e93dc1a9027e79ed93ede69d7a8d758244db676..63c2ce87ca75e7cd8f8c5698b3f3d787778b85b9 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -64,6 +64,7 @@
 #include "llkeyframefallmotion.h"
 #include "llkeyframestandmotion.h"
 #include "llkeyframewalkmotion.h"
+#include "llmeshrepository.h"
 #include "llmutelist.h"
 #include "llmoveview.h"
 #include "llnotificationsutil.h"
@@ -81,6 +82,7 @@
 #include "llviewermenu.h"
 #include "llviewerobjectlist.h"
 #include "llviewerparcelmgr.h"
+#include "llviewershadermgr.h"
 #include "llviewerstats.h"
 #include "llvoavatarself.h"
 #include "llvovolume.h"
@@ -681,7 +683,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 {
 	LLMemType mt(LLMemType::MTYPE_AVATAR);
 	//VTResume();  // VTune
-	
+	mImpostorExtents = (LLVector4a*) ll_aligned_malloc_16(32);
+
 	// mVoiceVisualizer is created by the hud effects manager and uses the HUD Effects pipeline
 	const BOOL needsSendToSim = false; // currently, this HUD effect doesn't need to pack and unpack data to do its job
 	mVoiceVisualizer = ( LLVoiceVisualizer *)LLHUDManager::getInstance()->createViewerEffect( LLHUDObject::LL_HUD_EFFECT_VOICE_VISUALIZER, needsSendToSim );
@@ -701,10 +704,8 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 		mBakedTextureDatas[i].mTextureIndex = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)i);
 	}
 
-	mDirtyMesh = TRUE;	// Dirty geometry, need to regenerate.
+	mDirtyMesh = 2;	// Dirty geometry, need to regenerate.
 	mMeshTexturesDirty = FALSE;
-	mShadow0Facep = NULL;
-	mShadow1Facep = NULL;
 	mHeadp = NULL;
 
 	mIsBuilt = FALSE;
@@ -740,12 +741,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 
 	mRippleTimeLast = 0.f;
 
-	mShadowImagep = LLViewerTextureManager::getFetchedTextureFromFile("foot_shadow.j2c");
-	
-	// GL NOT ACTIVE HERE
-	//gGL.getTexUnit(0)->bind(mShadowImagep.get());
-	//mShadowImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
-	
 	mInAir = FALSE;
 
 	mStepOnLand = TRUE;
@@ -835,6 +830,9 @@ LLVOAvatar::~LLVOAvatar()
 	
 	mAnimationSources.clear();
 
+	ll_aligned_free_16(mImpostorExtents);
+	mImpostorExtents = NULL;
+
 	lldebugs << "LLVOAvatar Destructor end" << llendl;
 }
 
@@ -1342,41 +1340,46 @@ void LLVOAvatar::updateDrawable(BOOL force_damped)
 	clearChanged(SHIFTED);
 }
 
-void LLVOAvatar::onShift(const LLVector3& shift_vector)
+void LLVOAvatar::onShift(const LLVector4a& shift_vector)
 {
-	mLastAnimExtents[0] += shift_vector;
-	mLastAnimExtents[1] += shift_vector;
+	const LLVector3& shift = reinterpret_cast<const LLVector3&>(shift_vector);
+	mLastAnimExtents[0] += shift;
+	mLastAnimExtents[1] += shift;
 	mNeedsImpostorUpdate = TRUE;
 	mNeedsAnimUpdate = TRUE;
 }
 
-void LLVOAvatar::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax)
+void LLVOAvatar::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
 {
 	if (isImpostor() && !needsImpostorUpdate())
 	{
 		LLVector3 delta = getRenderPosition() -
-			((LLVector3(mDrawable->getPositionGroup())-mImpostorOffset));
+			((LLVector3(mDrawable->getPositionGroup().getF32())-mImpostorOffset));
 		
-		newMin = mLastAnimExtents[0] + delta;
-		newMax = mLastAnimExtents[1] + delta;
+		newMin.load3( (mLastAnimExtents[0] + delta).mV);
+		newMax.load3( (mLastAnimExtents[1] + delta).mV);
 	}
 	else
 	{
 		getSpatialExtents(newMin,newMax);
-		mLastAnimExtents[0] = newMin;
-		mLastAnimExtents[1] = newMax;
-		LLVector3 pos_group = (newMin+newMax)*0.5f;
-		mImpostorOffset = pos_group-getRenderPosition();
+		mLastAnimExtents[0].set(newMin.getF32());
+		mLastAnimExtents[1].set(newMax.getF32());
+		LLVector4a pos_group;
+		pos_group.setAdd(newMin,newMax);
+		pos_group.mul(0.5f);
+		mImpostorOffset = LLVector3(pos_group.getF32())-getRenderPosition();
 		mDrawable->setPositionGroup(pos_group);
 	}
 }
 
-void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+void LLVOAvatar::getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 {
-	LLVector3 buffer(0.25f, 0.25f, 0.25f);
-	LLVector3 pos = getRenderPosition();
-	newMin = pos - buffer;
-	newMax = pos + buffer;
+	LLVector4a buffer(0.25f);
+	LLVector4a pos;
+	pos.load3(getRenderPosition().mV);
+	newMin.setSub(pos, buffer);
+	newMax.setAdd(pos, buffer);
+
 	float max_attachment_span = DEFAULT_MAX_PRIM_SCALE * 5.0f;
 	
 	//stretch bounding box by joint positions
@@ -1385,12 +1388,20 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
 		LLPolyMesh* mesh = i->second;
 		for (S32 joint_num = 0; joint_num < mesh->mJointRenderData.count(); joint_num++)
 		{
-			update_min_max(newMin, newMax, 
-						   mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation());
+			LLVector4a trans;
+			trans.load3( mesh->mJointRenderData[joint_num]->mWorldMatrix->getTranslation().mV);
+			update_min_max(newMin, newMax, trans);
 		}
 	}
 
-	mPixelArea = LLPipeline::calcPixelArea((newMin+newMax)*0.5f, (newMax-newMin)*0.5f, *LLViewerCamera::getInstance());
+	LLVector4a center, size;
+	center.setAdd(newMin, newMax);
+	center.mul(0.5f);
+
+	size.setSub(newMax,newMin);
+	size.mul(0.5f);
+
+	mPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
 
 	//stretch bounding box by attachments
 	for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); 
@@ -1417,15 +1428,17 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
 					LLSpatialBridge* bridge = drawable->getSpatialBridge();
 					if (bridge)
 					{
-						const LLVector3* ext = bridge->getSpatialExtents();
-						LLVector3 distance = (ext[1] - ext[0]);
+						const LLVector4a* ext = bridge->getSpatialExtents();
+						LLVector4a distance;
+						distance.setSub(ext[1], ext[0]);
+						LLVector4a max_span(max_attachment_span);
+
+						S32 lt = distance.lessThan4(max_span).getComparisonMask() & 0x7;
 						
 						// Only add the prim to spatial extents calculations if it isn't a megaprim.
 						// max_attachment_span calculated at the start of the function 
 						// (currently 5 times our max prim size) 
-						if (distance.mV[0] < max_attachment_span 
-							&& distance.mV[1] < max_attachment_span
-							&& distance.mV[2] < max_attachment_span)
+						if (lt == 0x7)
 						{
 							update_min_max(newMin,newMax,ext[0]);
 							update_min_max(newMin,newMax,ext[1]);
@@ -1437,8 +1450,9 @@ void LLVOAvatar::getSpatialExtents(LLVector3& newMin, LLVector3& newMax)
 	}
 
 	//pad bounding box	
-	newMin -= buffer;
-	newMax += buffer;
+
+	newMin.sub(buffer);
+	newMax.add(buffer);
 }
 
 //-----------------------------------------------------------------------------
@@ -1972,7 +1986,7 @@ void LLVOAvatar::updateMeshData()
 			}
 			if(num_vertices < 1)//skip empty meshes
 			{
-				break ;
+				continue ;
 			}
 			if(last_v_num > 0)//put the last inserted part into next vertex buffer.
 			{
@@ -1994,6 +2008,8 @@ void LLVOAvatar::updateMeshData()
 			// resize immediately
 			facep->setSize(num_vertices, num_indices);
 
+			bool terse_update = false;
+
 			if(facep->mVertexBuffer.isNull())
 			{
 				facep->mVertexBuffer = new LLVertexBufferAvatar();
@@ -2001,7 +2017,15 @@ void LLVOAvatar::updateMeshData()
 			}
 			else
 			{
-				facep->mVertexBuffer->resizeBuffer(num_vertices, num_indices) ;
+				if (facep->mVertexBuffer->getRequestedIndices() == num_indices &&
+					facep->mVertexBuffer->getRequestedVerts() == num_vertices)
+				{
+					terse_update = true;
+				}
+				else
+				{
+					facep->mVertexBuffer->resizeBuffer(num_vertices, num_indices) ;
+				}
 			}
 		
 			facep->setGeomIndex(0);
@@ -2016,7 +2040,7 @@ void LLVOAvatar::updateMeshData()
 
 			for(S32 k = j ; k < part_index ; k++)
 			{
-				mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR);
+				mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR, terse_update);
 			}
 
 			stop_glerror();
@@ -2412,12 +2436,6 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 	LLJoint::sNumUpdates = 0;
 	LLJoint::sNumTouches = 0;
 
-	// *NOTE: this is necessary for the floating name text above your head.
-	if (mDrawable.notNull())
-	{
-		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_SHADOW, TRUE);
-	}
-
 	BOOL visible = isVisible() || mNeedsAnimUpdate;
 
 	// update attachments positions
@@ -2466,7 +2484,7 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 
 	if (isImpostor() && !mNeedsImpostorUpdate)
 	{
-		LLVector3 ext[2];
+		LLVector4a ext[2];
 		F32 distance;
 		LLVector3 angle;
 
@@ -2495,12 +2513,22 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 			}
 			else
 			{
+				//VECTORIZE THIS
 				getSpatialExtents(ext[0], ext[1]);
-				if ((ext[1]-mImpostorExtents[1]).length() > 0.05f ||
-					(ext[0]-mImpostorExtents[0]).length() > 0.05f)
+				LLVector4a diff;
+				diff.setSub(ext[1], mImpostorExtents[1]);
+				if (diff.length3() > 0.05f)
 				{
 					mNeedsImpostorUpdate = TRUE;
 				}
+				else
+				{
+					diff.setSub(ext[0], mImpostorExtents[0]);
+					if (diff.length3() > 0.05f)
+					{
+						mNeedsImpostorUpdate = TRUE;
+					}
+				}
 			}
 		}
 	}
@@ -3756,6 +3784,46 @@ bool LLVOAvatar::shouldAlphaMask()
 
 }
 
+U32 LLVOAvatar::renderSkinnedAttachments()
+{
+	/*U32 num_indices = 0;
+	
+	const U32 data_mask =	LLVertexBuffer::MAP_VERTEX | 
+							LLVertexBuffer::MAP_NORMAL | 
+							LLVertexBuffer::MAP_TEXCOORD0 |
+							LLVertexBuffer::MAP_COLOR |
+							LLVertexBuffer::MAP_WEIGHT4;
+
+	for (attachment_map_t::const_iterator iter = mAttachmentPoints.begin(); 
+		 iter != mAttachmentPoints.end();
+		 ++iter)
+	{
+		LLViewerJointAttachment* attachment = iter->second;
+		for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+			 attachment_iter != attachment->mAttachedObjects.end();
+			 ++attachment_iter)
+		{
+			const LLViewerObject* attached_object = (*attachment_iter);
+			if (attached_object && !attached_object->isHUDAttachment())
+			{
+				const LLDrawable* drawable = attached_object->mDrawable;
+				if (drawable)
+				{
+					for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+					{
+						LLFace* face = drawable->getFace(i);
+						if (face->isState(LLFace::RIGGED))
+						{
+							
+				}
+			}
+		}
+	}
+
+	return num_indices;*/
+	return 0;
+}
+
 //-----------------------------------------------------------------------------
 // renderSkinned()
 //-----------------------------------------------------------------------------
@@ -3768,12 +3836,19 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 		return num_indices;
 	}
 
-	if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY))
+	LLFace* face = mDrawable->getFace(0);
+
+	bool needs_rebuild = !face || face->mVertexBuffer.isNull() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY);
+
+	if (needs_rebuild || mDirtyMesh)
 	{	//LOD changed or new mesh created, allocate new vertex buffer if needed
-		updateMeshData();
-		mDirtyMesh = FALSE;
-		mNeedsSkin = TRUE;
-		mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
+		if (needs_rebuild || mDirtyMesh >= 2 || mVisibilityRank <= 4)
+		{
+			updateMeshData();
+			mDirtyMesh = 0;
+			mNeedsSkin = TRUE;
+			mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
+		}
 	}
 
 	if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0)
@@ -4021,54 +4096,6 @@ U32 LLVOAvatar::renderRigid()
 	return num_indices;
 }
 
-U32 LLVOAvatar::renderFootShadows()
-{
-	U32 num_indices = 0;
-
-	if (!mIsBuilt)
-	{
-		return 0;
-	}
-
-	if (isSelf() && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead()))
-	{
-		return 0;
-	}
-	
-	if (!mIsBuilt)
-	{
-		return 0;
-	}
-	
-	// Don't render foot shadows if your lower body is completely invisible.
-	// (non-humanoid avatars rule!)
-	if (!isTextureVisible(TEX_LOWER_BAKED))
-	{
-		return 0;
-	}
-
-	// Update the shadow, tractor, and text label geometry.
-	if (mDrawable->isState(LLDrawable::REBUILD_SHADOW) && !isImpostor())
-	{
-		updateShadowFaces();
-		mDrawable->clearState(LLDrawable::REBUILD_SHADOW);
-	}
-
-	U32 foot_mask = LLVertexBuffer::MAP_VERTEX |
-					LLVertexBuffer::MAP_TEXCOORD0;
-
-	LLGLDepthTest test(GL_TRUE, GL_FALSE);
-	//render foot shadows
-	LLGLEnable blend(GL_BLEND);
-	gGL.getTexUnit(0)->bind(mShadowImagep, TRUE);
-	glColor4fv(mShadow0Facep->getRenderColor().mV);
-	mShadow0Facep->renderIndexed(foot_mask);
-	glColor4fv(mShadow1Facep->getRenderColor().mV);
-	mShadow1Facep->renderIndexed(foot_mask);
-	
-	return num_indices;
-}
-
 U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
 {
 	if (!mImpostor.isComplete())
@@ -4189,11 +4216,6 @@ void LLVOAvatar::updateTextures()
 	{
 		setDebugText(llformat("%4.0f:%4.0f", fsqrtf(mMinPixelArea),fsqrtf(mMaxPixelArea)));
 	}	
-	
-	if( render_avatar )
-	{
-		mShadowImagep->addTextureStats(mPixelArea);
-	}
 }
 
 
@@ -5326,9 +5348,13 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent)
 		return;
 	}
 
-	const LLVector3* ext = mDrawable->getSpatialExtents();
-	LLVector3 center = (ext[1] + ext[0]) * 0.5f;
-	LLVector3 size = (ext[1]-ext[0])*0.5f;
+	const LLVector4a* ext = mDrawable->getSpatialExtents();
+	LLVector4a center;
+	center.setAdd(ext[1], ext[0]);
+	center.mul(0.5f);
+	LLVector4a size;
+	size.setSub(ext[1], ext[0]);
+	size.mul(0.5f);
 
 	mImpostorPixelArea = LLPipeline::calcPixelArea(center, size, *LLViewerCamera::getInstance());
 
@@ -5340,7 +5366,7 @@ void LLVOAvatar::setPixelAreaAndAngle(LLAgent &agent)
 	}
 	else
 	{
-		F32 radius = size.length();
+		F32 radius = size.length3();
 		mAppAngle = (F32) atan2( radius, range) * RAD_TO_DEG;
 	}
 
@@ -5389,7 +5415,7 @@ BOOL LLVOAvatar::updateJointLODs()
  		if (res)
 		{
 			sNumLODChangesThisFrame++;
-			dirtyMesh();
+			dirtyMesh(2);
 			return TRUE;
 		}
 	}
@@ -5413,18 +5439,9 @@ LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline)
 	mDrawable->addFace(poolp, NULL);
 	mDrawable->setRenderType(LLPipeline::RENDER_TYPE_AVATAR);
 	
-	LLFace *facep;
-
-	// Add faces for the foot shadows
-	facep = mDrawable->addFace((LLFacePool*) NULL, mShadowImagep);
-	mShadow0Facep = facep;
-
-	facep = mDrawable->addFace((LLFacePool*) NULL, mShadowImagep);
-	mShadow1Facep = facep;
-
 	mNumInitFaces = mDrawable->getNumFaces() ;
 
-	dirtyMesh();
+	dirtyMesh(2);
 	return mDrawable;
 }
 
@@ -5463,107 +5480,6 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
 	return TRUE;
 }
 
-//-----------------------------------------------------------------------------
-// updateShadowFaces()
-//-----------------------------------------------------------------------------
-void LLVOAvatar::updateShadowFaces()
-{
-	LLFace *face0p = mShadow0Facep;
-	LLFace *face1p = mShadow1Facep;
-
-	//
-	// render avatar shadows
-	//
-	if (mInAir || mUpdatePeriod >= IMPOSTOR_PERIOD)
-	{
-		face0p->setSize(0, 0);
-		face1p->setSize(0, 0);
-		return;
-	}
-
-	LLSprite sprite(mShadowImagep.notNull() ? mShadowImagep->getID() : LLUUID::null);
-	sprite.setFollow(FALSE);
-	const F32 cos_angle = gSky.getSunDirection().mV[2];
-	F32 cos_elev = sqrt(1 - cos_angle * cos_angle);
-	if (cos_angle < 0) cos_elev = -cos_elev;
-	sprite.setSize(0.4f + cos_elev * 0.8f, 0.3f);
-	LLVector3 sun_vec = gSky.mVOSkyp ? gSky.mVOSkyp->getToSun() : LLVector3(0.f, 0.f, 0.f);
-
-	if (mShadowImagep->hasGLTexture())
-	{
-		LLVector3 normal;
-		LLVector3d shadow_pos;
-		LLVector3 shadow_pos_agent;
-		F32 foot_height;
-
-		if (mFootLeftp)
-		{
-			LLVector3 joint_world_pos = mFootLeftp->getWorldPosition();
-			// this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now
-			// but we make an explicit ray trace call in expectation of future improvements
-			resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos), 
-									 gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal);
-			shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos);
-			foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ];
-
-			// Pull sprite in direction of surface normal
-			shadow_pos_agent += normal * SHADOW_OFFSET_AMT;
-
-			// Render sprite
-			sprite.setNormal(normal);
-			if (isSelf() && gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
-			{
-				sprite.setColor(0.f, 0.f, 0.f, 0.f);
-			}
-			else
-			{
-				sprite.setColor(0.f, 0.f, 0.f, clamp_rescale(foot_height, MIN_SHADOW_HEIGHT, MAX_SHADOW_HEIGHT, 0.5f, 0.f));
-			}
-			sprite.setPosition(shadow_pos_agent);
-
-			LLVector3 foot_to_knee = mKneeLeftp->getWorldPosition() - joint_world_pos;
-			//foot_to_knee.normalize();
-			foot_to_knee -= projected_vec(foot_to_knee, sun_vec);
-			sprite.setYaw(azimuth(sun_vec - foot_to_knee));
-		
-			sprite.updateFace(*face0p);
-		}
-
-		if (mFootRightp)
-		{
-			LLVector3 joint_world_pos = mFootRightp->getWorldPosition();
-			// this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now
-			// but we make an explicit ray trace call in expectation of future improvements
-			resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos), 
-									 gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal);
-			shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos);
-			foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ];
-
-			// Pull sprite in direction of surface normal
-			shadow_pos_agent += normal * SHADOW_OFFSET_AMT;
-
-			// Render sprite
-			sprite.setNormal(normal);
-			if (isSelf() && gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
-			{
-				sprite.setColor(0.f, 0.f, 0.f, 0.f);
-			}
-			else
-			{
-				sprite.setColor(0.f, 0.f, 0.f, clamp_rescale(foot_height, MIN_SHADOW_HEIGHT, MAX_SHADOW_HEIGHT, 0.5f, 0.f));
-			}
-			sprite.setPosition(shadow_pos_agent);
-
-			LLVector3 foot_to_knee = mKneeRightp->getWorldPosition() - joint_world_pos;
-			//foot_to_knee.normalize();
-			foot_to_knee -= projected_vec(foot_to_knee, sun_vec);
-			sprite.setYaw(azimuth(sun_vec - foot_to_knee));
-	
-			sprite.updateFace(*face1p);
-		}
-	}
-}
-
 //-----------------------------------------------------------------------------
 // updateSexDependentLayerSets()
 //-----------------------------------------------------------------------------
@@ -5579,9 +5495,12 @@ void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake )
 //-----------------------------------------------------------------------------
 void LLVOAvatar::dirtyMesh()
 {
-	mDirtyMesh = TRUE;
+	dirtyMesh(1);
+}
+void LLVOAvatar::dirtyMesh(S32 priority)
+{
+	mDirtyMesh = llmax(mDirtyMesh, priority);
 }
-
 //-----------------------------------------------------------------------------
 // hideSkirt()
 //-----------------------------------------------------------------------------
@@ -5643,8 +5562,7 @@ LLViewerJointAttachment* LLVOAvatar::getTargetAttachmentPoint(LLViewerObject* vi
 	// correctly, but putting this check in here to be safe.
 	if (attachmentID & ATTACHMENT_ADD)
 	{
-		llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl;
-		attachmentID &= ~ATTACHMENT_ADD;
+		llwarns << "Got an attachment with ATTACHMENT_ADD mask, removing ( attach pt:" << attachmentID << " )" << llendl;		attachmentID &= ~ATTACHMENT_ADD;
 	}
 	
 	LLViewerJointAttachment* attachment = get_if_there(mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
@@ -5765,6 +5683,14 @@ BOOL LLVOAvatar::detachObject(LLViewerObject *viewer_object)
 			return TRUE;
 		}
 	}
+
+	std::vector<LLPointer<LLViewerObject> >::iterator iter = std::find(mPendingAttachment.begin(), mPendingAttachment.end(), viewer_object);
+	if (iter != mPendingAttachment.end())
+	{
+		mPendingAttachment.erase(iter);
+		return TRUE;
+	}
+	
 	return FALSE;
 }
 
@@ -7826,18 +7752,15 @@ BOOL LLVOAvatar::updateLOD()
 	BOOL res = updateJointLODs();
 
 	LLFace* facep = mDrawable->getFace(0);
-	if (facep->mVertexBuffer.isNull() ||
-		(LLVertexBuffer::sEnableVBOs &&
-		((facep->mVertexBuffer->getUsage() == GL_STATIC_DRAW ? TRUE : FALSE) !=
-		 (facep->getPool()->getVertexShaderLevel() > 0 ? TRUE : FALSE))))
+	if (facep->mVertexBuffer.isNull())
 	{
-		mDirtyMesh = TRUE;
+		dirtyMesh(2);
 	}
 
-	if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY))
+	if (mDirtyMesh >= 2 || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY))
 	{	//LOD changed or new mesh created, allocate new vertex buffer if needed
 		updateMeshData();
-		mDirtyMesh = FALSE;
+		mDirtyMesh = 0;
 		mNeedsSkin = TRUE;
 		mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
 	}
@@ -7898,9 +7821,9 @@ void LLVOAvatar::cacheImpostorValues()
 	getImpostorValues(mImpostorExtents, mImpostorAngle, mImpostorDistance);
 }
 
-void LLVOAvatar::getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance) const
+void LLVOAvatar::getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const
 {
-	const LLVector3* ext = mDrawable->getSpatialExtents();
+	const LLVector4a* ext = mDrawable->getSpatialExtents();
 	extents[0] = ext[0];
 	extents[1] = ext[1];
 
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index b30cce09f65d3930194ac3a4cbafa3ac67304d7e..358a1c256f38ba156102b396fe9edf12fec3efff 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -128,7 +128,7 @@ class LLVOAvatar :
 	virtual BOOL   	 	 	isActive() const; // Whether this object needs to do an idleUpdate.
 	virtual void   	 	 	updateTextures();
 	virtual S32    	 	 	setTETexture(const U8 te, const LLUUID& uuid); // If setting a baked texture, need to request it from a non-local sim.
-	virtual void   	 	 	onShift(const LLVector3& shift_vector);
+	virtual void   	 	 	onShift(const LLVector4a& shift_vector);
 	virtual U32    	 	 	getPartitionType() const;
 	virtual const  	 	 	LLVector3 getRenderPosition() const;
 	virtual void   	 	 	updateDrawable(BOOL force_damped);
@@ -136,8 +136,8 @@ class LLVOAvatar :
 	virtual BOOL   	 	 	updateGeometry(LLDrawable *drawable);
 	virtual void   	 	 	setPixelAreaAndAngle(LLAgent &agent);
 	virtual void   	 	 	updateRegion(LLViewerRegion *regionp);
-	virtual void   	 	 	updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax);
-	virtual void   	 	 	getSpatialExtents(LLVector3& newMin, LLVector3& newMax);
+	virtual void   	 	 	updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax);
+	virtual void   	 	 	getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
 	virtual BOOL   	 	 	lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
 												 S32 face = -1,                    // which face to check, -1 = ALL_SIDES
 												 BOOL pick_transparent = FALSE,
@@ -340,10 +340,10 @@ class LLVOAvatar :
  **/
 
 public:
-	U32 		renderFootShadows();
 	U32 		renderImpostor(LLColor4U color = LLColor4U(255,255,255,255), S32 diffuse_channel = 0);
 	U32 		renderRigid();
 	U32 		renderSkinned(EAvatarRenderPass pass);
+	U32			renderSkinnedAttachments();
 	U32 		renderTransparent(BOOL first_pass);
 	void 		renderCollisionVolumes();
 	static void	deleteCachedImages(bool clearAll=true);
@@ -394,7 +394,7 @@ class LLVOAvatar :
 	BOOL 	    needsImpostorUpdate() const;
 	const LLVector3& getImpostorOffset() const;
 	const LLVector2& getImpostorDim() const;
-	void 		getImpostorValues(LLVector3* extents, LLVector3& angle, F32& distance) const;
+	void 		getImpostorValues(LLVector4a* extents, LLVector3& angle, F32& distance) const;
 	void 		cacheImpostorValues();
 	void 		setImpostorDim(const LLVector2& dim);
 	static void	resetImpostors();
@@ -405,7 +405,7 @@ class LLVOAvatar :
 	LLVector3	mImpostorOffset;
 	LLVector2	mImpostorDim;
 	BOOL		mNeedsAnimUpdate;
-	LLVector3	mImpostorExtents[2];
+	LLVector4a*	mImpostorExtents;
 	LLVector3	mImpostorAngle;
 	F32			mImpostorDistance;
 	F32			mImpostorPixelArea;
@@ -576,7 +576,8 @@ class LLVOAvatar :
 	void 			releaseMeshData();
 	virtual void restoreMeshData();
 private:
-	BOOL 			mDirtyMesh;
+	void 			dirtyMesh(S32 priority); // Dirty the avatar mesh, with priority
+	S32 			mDirtyMesh; // 0 -- not dirty, 1 -- morphed, 2 -- LOD
 	BOOL			mMeshTexturesDirty;
 
 	typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index a82afbeb76d1811eb9ea40a126719ac0f4a81196..fe1e36cbe8c93f873468246dc05c50eb3780e649 100644
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -594,7 +594,7 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 
 	LLVector2 tc[4];
 	LLVector3 v[4];
-	// LLVector3 n[4]; // unused!
+	//LLVector3 n[4];
 
 	F32 closest_t = 1.f;
 
@@ -640,7 +640,6 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 		position.mV[2] += blade_height;
 		v[3]    = v1 = position + mRegionp->getOriginAgent();
 	
-
 		F32 a,b,t;
 
 		BOOL hit = FALSE;
@@ -648,23 +647,23 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 
 		U32 idx0 = 0,idx1 = 0,idx2 = 0;
 
-		if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, &a, &b, &t, FALSE))
+		if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE))
 		{
 			hit = TRUE;
 			idx0 = 0; idx1 = 1; idx2 = 2;
 		}
-		else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, &a, &b, &t, FALSE))
+		else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, a, b, t, FALSE))
 		{
 			hit = TRUE;
 			idx0 = 1; idx1 = 3; idx2 = 2;
 		}
-		else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, &a, &b, &t, FALSE))
+		else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, a, b, t, FALSE))
 		{
 			normal1 = -normal1;
 			hit = TRUE;
 			idx0 = 2; idx1 = 1; idx2 = 0;
 		}
-		else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, &a, &b, &t, FALSE))
+		else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, a, b, t, FALSE))
 		{
 			normal1 = -normal1;
 			hit = TRUE;
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 3ba4ecad0ced9ab0a28d435c77135c76873c68ff..b5fd8182c601fe72566fbaa024dfbd58d7b2643b 100644
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -79,12 +79,14 @@ F32 LLVOPartGroup::getBinRadius()
 	return mScale.mV[0]*2.f;
 }
 
-void LLVOPartGroup::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+void LLVOPartGroup::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 {		
 	const LLVector3& pos_agent = getPositionAgent();
-	newMin = pos_agent - mScale;
-	newMax = pos_agent + mScale;
-	mDrawable->setPositionGroup(pos_agent);
+	newMin.load3( (pos_agent - mScale).mV);
+	newMax.load3( (pos_agent + mScale).mV);
+	LLVector4a pos;
+	pos.load3(pos_agent.mV);
+	mDrawable->setPositionGroup(pos);
 }
 
 BOOL LLVOPartGroup::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
diff --git a/indra/newview/llvopartgroup.h b/indra/newview/llvopartgroup.h
index 18583b4be9ae0b015979c811230e6dd2169eb484..771ae1c1eb9ac22fc81ff63cc2bcea35e5a0cb16 100644
--- a/indra/newview/llvopartgroup.h
+++ b/indra/newview/llvopartgroup.h
@@ -57,7 +57,7 @@ class LLVOPartGroup : public LLAlphaObject
 	BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
 
 	virtual F32 getBinRadius();
-	virtual void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
+	virtual void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
 	virtual U32 getPartitionType() const;
 	
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent);
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index ef7b16100361789cd5a138270d44081600ccc993..02e7e7e60fca3ef77d8c765e192e45eff74e2988 100644
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -60,27 +60,77 @@ class LLVertexBufferTerrain : public LLVertexBuffer
 		LLVertexBuffer(MAP_VERTEX | MAP_NORMAL | MAP_TEXCOORD0 | MAP_TEXCOORD1 | MAP_COLOR, GL_DYNAMIC_DRAW_ARB)
 	{
 		//texture coordinates 2 and 3 exist, but use the same data as texture coordinate 1
-		mOffsets[TYPE_TEXCOORD3] = mOffsets[TYPE_TEXCOORD2] = mOffsets[TYPE_TEXCOORD1];
-		mTypeMask |= MAP_TEXCOORD2 | MAP_TEXCOORD3;
 	};
 
-	/*// virtual
+	// virtual
 	void setupVertexBuffer(U32 data_mask) const
-	{		
-		if (LLDrawPoolTerrain::getDetailMode() == 0 || LLPipeline::sShadowRender)
+	{	
+		U8* base = useVBOs() ? (U8*) mAlignedOffset : mMappedData;
+
+		//assume tex coords 2 and 3 are present
+		U32 type_mask = mTypeMask | MAP_TEXCOORD2 | MAP_TEXCOORD3;
+
+		if ((data_mask & type_mask) != data_mask)
 		{
-			LLVertexBuffer::setupVertexBuffer(data_mask);
+			llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
+		}
+
+		if (data_mask & MAP_NORMAL)
+		{
+			glNormalPointer(GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_NORMAL], (void*)(base + mOffsets[TYPE_NORMAL]));
+		}
+		if (data_mask & MAP_TEXCOORD3)
+		{ //substitute tex coord 0 for tex coord 3
+			glClientActiveTextureARB(GL_TEXTURE3_ARB);
+			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+			glClientActiveTextureARB(GL_TEXTURE0_ARB);
+		}
+		if (data_mask & MAP_TEXCOORD2)
+		{ //substitute tex coord 0 for tex coord 2
+			glClientActiveTextureARB(GL_TEXTURE2_ARB);
+			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		}
-		else if (data_mask & LLVertexBuffer::MAP_TEXCOORD1)
+		if (data_mask & MAP_TEXCOORD1)
 		{
-			LLVertexBuffer::setupVertexBuffer(data_mask);
+			glClientActiveTextureARB(GL_TEXTURE1_ARB);
+			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
+			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		}
-		else
+		if (data_mask & MAP_BINORMAL)
 		{
-			LLVertexBuffer::setupVertexBuffer(data_mask);
+			glClientActiveTextureARB(GL_TEXTURE2_ARB);
+			glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		}
-		llglassertok();		
-	}*/
+		if (data_mask & MAP_TEXCOORD0)
+		{
+			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_TEXCOORD0], (void*)(base + mOffsets[TYPE_TEXCOORD0]));
+		}
+		if (data_mask & MAP_COLOR)
+		{
+			glColorPointer(4, GL_UNSIGNED_BYTE, LLVertexBuffer::sTypeOffsets[TYPE_COLOR], (void*)(base + mOffsets[TYPE_COLOR]));
+		}
+		
+		if (data_mask & MAP_WEIGHT)
+		{
+			glVertexAttribPointerARB(1, 1, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT], (void*)(base + mOffsets[TYPE_WEIGHT]));
+		}
+
+		if (data_mask & MAP_WEIGHT4 && sWeight4Loc != -1)
+		{
+			glVertexAttribPointerARB(sWeight4Loc, 4, GL_FLOAT, FALSE, LLVertexBuffer::sTypeOffsets[TYPE_WEIGHT4], (void*)(base+mOffsets[TYPE_WEIGHT4]));
+		}
+
+		if (data_mask & MAP_CLOTHWEIGHT)
+		{
+			glVertexAttribPointerARB(4, 4, GL_FLOAT, TRUE,  LLVertexBuffer::sTypeOffsets[TYPE_CLOTHWEIGHT], (void*)(base + mOffsets[TYPE_CLOTHWEIGHT]));
+		}
+		if (data_mask & MAP_VERTEX)
+		{
+			glVertexPointer(3,GL_FLOAT, LLVertexBuffer::sTypeOffsets[TYPE_VERTEX], (void*)(base + 0));
+		}
+	}
 };
 
 //============================================================================
@@ -945,7 +995,13 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect
 
 	//step one meter at a time until intersection point found
 
-	const LLVector3* ext = mDrawable->getSpatialExtents();
+	//VECTORIZE THIS
+	const LLVector4a* exta = mDrawable->getSpatialExtents();
+
+	LLVector3 ext[2];
+	ext[0].set(exta[0].getF32());
+	ext[1].set(exta[1].getF32());
+
 	F32 rad = (delta*tdelta).magVecSquared();
 
 	F32 t = 0.f;
@@ -1007,13 +1063,16 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect
 	return FALSE;
 }
 
-void LLVOSurfacePatch::updateSpatialExtents(LLVector3& newMin, LLVector3 &newMax)
+void LLVOSurfacePatch::updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax)
 {
 	LLVector3 posAgent = getPositionAgent();
 	LLVector3 scale = getScale();
-	newMin = posAgent-scale*0.5f; // Changing to 2.f makes the culling a -little- better, but still wrong
-	newMax = posAgent+scale*0.5f;
-	mDrawable->setPositionGroup((newMin+newMax)*0.5f);
+	newMin.load3( (posAgent-scale*0.5f).mV); // Changing to 2.f makes the culling a -little- better, but still wrong
+	newMax.load3( (posAgent+scale*0.5f).mV);
+	LLVector4a pos;
+	pos.setAdd(newMin,newMax);
+	pos.mul(0.5f);
+	mDrawable->setPositionGroup(pos);
 }
 
 U32 LLVOSurfacePatch::getPartitionType() const
diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h
index 10a5888526ca0a17dbdf44d651a0cd7aed241291..15442e1947d3d5bdf63afd70e6dd97e2a388abd8 100644
--- a/indra/newview/llvosurfacepatch.h
+++ b/indra/newview/llvosurfacepatch.h
@@ -78,7 +78,7 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 	/*virtual*/ void updateTextures();
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
 
-	/*virtual*/ void updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
+	/*virtual*/ void updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
 	/*virtual*/ BOOL isActive() const; // Whether this object needs to do an idleUpdate.
 
 	void setPatch(LLSurfacePatch *patchp);
diff --git a/indra/newview/llvotextbubble.cpp b/indra/newview/llvotextbubble.cpp
index 428ef2000648c59e85734a580b6f14ae84f35512..339da3c0bf982048baaf97981042fa913ce9a410 100644
--- a/indra/newview/llvotextbubble.cpp
+++ b/indra/newview/llvotextbubble.cpp
@@ -45,6 +45,7 @@
 #include "llviewertexturelist.h"
 #include "llvolume.h"
 #include "pipeline.h"
+#include "llvector4a.h"
 #include "llviewerregion.h"
 
 LLVOTextBubble::LLVOTextBubble(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
@@ -217,7 +218,7 @@ void LLVOTextBubble::updateFaceSize(S32 idx)
 	else
 	{
 		const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
-		face->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
+		face->setSize(vol_face.mNumVertices, vol_face.mNumIndices);
 	}
 }
 
@@ -235,19 +236,37 @@ void LLVOTextBubble::getGeometry(S32 idx,
 
 	const LLVolumeFace& face = getVolume()->getVolumeFace(idx);
 	
-	LLVector3 pos = getPositionAgent();
+	LLVector4a pos;
+	pos.load3(getPositionAgent().mV);
+
+	LLVector4a scale;
+	scale.load3(getScale().mV);
+
 	LLColor4U color = LLColor4U(getTE(idx)->getColor());
 	U32 offset = mDrawable->getFace(idx)->getGeomIndex();
 	
-	for (U32 i = 0; i < face.mVertices.size(); i++)
+	LLVector4a* dst_pos = (LLVector4a*) verticesp.get();
+	LLVector4a* src_pos = (LLVector4a*) face.mPositions;
+	
+	LLVector4a* dst_norm = (LLVector4a*) normalsp.get();
+	LLVector4a* src_norm  = (LLVector4a*) face.mNormals;
+	
+	LLVector2* dst_tc = (LLVector2*) texcoordsp.get();
+	LLVector2* src_tc = (LLVector2*) face.mTexCoords;
+
+	LLVector4a::memcpyNonAliased16((F32*) dst_norm, (F32*) src_norm, face.mNumVertices*4);
+	LLVector4a::memcpyNonAliased16((F32*) dst_tc, (F32*) src_tc, face.mNumVertices*2);
+	
+	
+	for (U32 i = 0; i < face.mNumVertices; i++)
 	{
-		*verticesp++ = face.mVertices[i].mPosition.scaledVec(getScale()) + pos;
-		*normalsp++ = face.mVertices[i].mNormal;
-		*texcoordsp++ = face.mVertices[i].mTexCoord;
+		LLVector4a t;
+		t.setMul(src_pos[i], scale);
+		dst_pos[i].setAdd(t, pos);
 		*colorsp++ = color;
 	}
 	
-	for (U32 i = 0; i < face.mIndices.size(); i++)
+	for (U32 i = 0; i < face.mNumIndices; i++)
 	{
 		*indicesp++ = face.mIndices[i] + offset;
 	}
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index eb5b6c6618dc6a86e86dacd82eb3cf353f73291d..c8a5138f8fdcbcdd8221c8bf37514d677f4343b9 100644
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -1244,7 +1244,7 @@ void LLVOTree::updateRadius()
 	mDrawable->setRadius(32.0f);
 }
 
-void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 {
 	F32 radius = getScale().length()*0.05f;
 	LLVector3 center = getRenderPosition();
@@ -1254,9 +1254,11 @@ void LLVOTree::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
 
 	center += LLVector3(0, 0, size.mV[2]) * getRotation();
 	
-	newMin.set(center-size);
-	newMax.set(center+size);
-	mDrawable->setPositionGroup(center);
+	newMin.load3((center-size).mV);
+	newMax.load3((center+size).mV);
+	LLVector4a pos;
+	pos.load3(center.mV);
+	mDrawable->setPositionGroup(pos);
 }
 
 BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
@@ -1269,8 +1271,13 @@ BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end
 		return FALSE;
 	}
 
-	const LLVector3* ext = mDrawable->getSpatialExtents();
+	const LLVector4a* exta = mDrawable->getSpatialExtents();
 
+	//VECTORIZE THIS
+	LLVector3 ext[2];
+	ext[0].set(exta[0].getF32());
+	ext[1].set(exta[1].getF32());
+	
 	LLVector3 center = (ext[1]+ext[0])*0.5f;
 	LLVector3 size = (ext[1]-ext[0]);
 
diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h
index 036ad692b1700b1db30361130f7feb07ec5b42f1..104226fcb6f14b97b3eb24e25d2952ada70bab51 100644
--- a/indra/newview/llvotree.h
+++ b/indra/newview/llvotree.h
@@ -73,7 +73,7 @@ class LLVOTree : public LLViewerObject
 
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
 	/*virtual*/ BOOL		updateGeometry(LLDrawable *drawable);
-	/*virtual*/ void		updateSpatialExtents(LLVector3 &min, LLVector3 &max);
+	/*virtual*/ void		updateSpatialExtents(LLVector4a &min, LLVector4a &max);
 
 	virtual U32 getPartitionType() const;
 
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index d6453111d7a47d5fed0ca95c331447a5c5781855..38e54342eadbf137755db060f578dcd5eaff52bb 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"
@@ -50,6 +52,7 @@
 #include "object_flags.h"
 #include "llagentconstants.h"
 #include "lldrawable.h"
+#include "lldrawpoolavatar.h"
 #include "lldrawpoolbump.h"
 #include "llface.h"
 #include "llspatialpartition.h"
@@ -57,8 +60,10 @@
 #include "llflexibleobject.h"
 #include "llsky.h"
 #include "lltexturefetch.h"
+#include "llvector4a.h"
 #include "llviewercamera.h"
 #include "llviewertexturelist.h"
+#include "llviewerobjectlist.h"
 #include "llviewerregion.h"
 #include "llviewertextureanim.h"
 #include "llworld.h"
@@ -67,8 +72,11 @@
 #include "llsdutil.h"
 #include "llmediaentry.h"
 #include "llmediadataclient.h"
+#include "llmeshrepository.h"
 #include "llagent.h"
 #include "llviewermediafocus.h"
+#include "llvoavatar.h"
+
 
 const S32 MIN_QUIET_FRAMES_COALESCE = 30;
 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -88,6 +96,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 +667,7 @@ void LLVOVolume::updateTextures()
 
 void LLVOVolume::updateTextureVirtualSize()
 {
+	LLFastTimer ftm(FTM_VOLUME_TEXTURES);
 	// Update the pixel area of all faces
 
 	if(mDrawable.isNull() || !mDrawable->isVisible())
@@ -686,7 +701,7 @@ void LLVOVolume::updateTextureVirtualSize()
 		const LLTextureEntry *te = face->getTextureEntry();
 		LLViewerTexture *imagep = face->getTexture();
 		if (!imagep || !te ||			
-			face->mExtents[0] == face->mExtents[1])
+			face->mExtents[0].equal3(face->mExtents[1]))
 		{
 			continue;
 		}
@@ -745,10 +760,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 +806,7 @@ void LLVOVolume::updateTextureVirtualSize()
 										  mSculptTexture->getHeight(), mSculptTexture->getWidth()));
 			}
 		}
+
 	}
 
 	if (getLightTextureID().notNull())
@@ -804,7 +822,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 +918,36 @@ 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 LL_MESH_ENABLED
+	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;
+			}
+		}
+	}
+#endif
+
 	// Check if we need to change implementations
 	bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
 	if (is_flexible)
@@ -929,24 +975,48 @@ 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();
 
+
 		if (isSculpted())
 		{
 			updateSculptTexture();
-
-			if (mSculptTexture.notNull())
+#if LL_MESH_ENABLED
+			// 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
+#endif
 			{
-				sculpt();
+				if (mSculptTexture.notNull())
+				{
+					sculpt();
+				}
 			}
 		}
 
@@ -959,7 +1029,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 +1057,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 +1252,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);
 
@@ -1252,13 +1336,17 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 {
 	BOOL res = TRUE;
 
-	LLVector3 min,max;
+	LLVector4a min,max;
 
 	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);
@@ -1272,17 +1360,8 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 			}
 			else
 			{
-				for (U32 i = 0; i < 3; i++)
-				{
-					if (face->mExtents[0].mV[i] < min.mV[i])
-					{
-						min.mV[i] = face->mExtents[0].mV[i];
-					}
-					if (face->mExtents[1].mV[i] > max.mV[i])
-					{
-						max.mV[i] = face->mExtents[1].mV[i];
-					}
-				}
+				min.setMin(face->mExtents[0]);
+				max.setMax(face->mExtents[1]);
 			}
 		}
 	}
@@ -1290,7 +1369,9 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 	if (rebuild)
 	{
 		mDrawable->setSpatialExtents(min,max);
-		mDrawable->setPositionGroup((min+max)*0.5f);	
+		min.add(max);
+		min.mul(0.5f);
+		mDrawable->setPositionGroup(min);	
 	}
 
 	updateRadius();
@@ -1518,14 +1599,9 @@ void LLVOVolume::updateFaceSize(S32 idx)
 	else
 	{
 		const LLVolumeFace& vol_face = getVolume()->getVolumeFace(idx);
-		if (LLPipeline::sUseTriStrips)
-		{
-			facep->setSize(vol_face.mVertices.size(), vol_face.mTriStrip.size());
-		}
-		else
-		{
-			facep->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
-		}
+		facep->setSize(vol_face.mNumVertices, vol_face.mNumIndices, 
+						true); // <--- volume faces should be padded for 16-byte alignment
+		
 	}
 }
 
@@ -1780,21 +1856,25 @@ bool LLVOVolume::hasMedia() const
 LLVector3 LLVOVolume::getApproximateFaceNormal(U8 face_id)
 {
 	LLVolume* volume = getVolume();
-	LLVector3 result;
+	LLVector4a result;
+	result.clear();
+
+	LLVector3 ret;
 
 	if (volume && face_id < volume->getNumVolumeFaces())
 	{
 		const LLVolumeFace& face = volume->getVolumeFace(face_id);
-		for (S32 i = 0; i < (S32)face.mVertices.size(); ++i)
+		for (S32 i = 0; i < (S32)face.mNumVertices; ++i)
 		{
-			result += face.mVertices[i].mNormal;
+			result.add(face.mNormals[i]);
 		}
 
-		result = volumeDirectionToAgent(result);
-		result.normVec();
+		LLVector3 ret((F32*) &result.mQ);
+		ret = volumeDirectionToAgent(ret);
+		ret.normVec();
 	}
 	
-	return result;
+	return ret;
 }
 
 void LLVOVolume::requestMediaDataUpdate(bool isNew)
@@ -2456,6 +2536,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();
@@ -2566,6 +2657,26 @@ BOOL LLVOVolume::isSculpted() const
 	return FALSE;
 }
 
+BOOL LLVOVolume::isMesh() const
+{
+#if LL_MESH_ENABLED
+	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;	
+		}
+	}
+#endif
+
+
+	return FALSE;
+}
+
 BOOL LLVOVolume::hasLightTexture() const
 {
 	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
@@ -2896,7 +3007,7 @@ void LLVOVolume::setSelected(BOOL sel)
 	}
 }
 
-void LLVOVolume::updateSpatialExtents(LLVector3& newMin, LLVector3& newMax)
+void LLVOVolume::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 {		
 }
 
@@ -2904,7 +3015,33 @@ F32 LLVOVolume::getBinRadius()
 {
 	F32 radius;
 	
-	const LLVector3* ext = mDrawable->getSpatialExtents();
+	F32 scale = 1.f;
+
+#if LL_MESH_ENABLED
+	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.mNumVertices;
+			}
+
+			scale = 1.f/llmax(vert_count/1024.f, 1.f);
+		}
+	}
+#endif
+
+	const LLVector4a* ext = mDrawable->getSpatialExtents();
 	
 	BOOL shrink_wrap = mDrawable->isAnimating();
 	BOOL alpha_wrap = FALSE;
@@ -2915,9 +3052,7 @@ F32 LLVOVolume::getBinRadius()
 		{
 			LLFace* face = mDrawable->getFace(i);
 			if (face->getPoolType() == LLDrawPool::POOL_ALPHA &&
-				(!LLPipeline::sFastAlpha || 
-				face->getFaceColor().mV[3] != 1.f ||
-				!face->getTexture()->getIsAlphaMask()))
+			    !face->canRenderAsMask())
 			{
 				alpha_wrap = TRUE;
 				break;
@@ -2938,7 +3073,10 @@ F32 LLVOVolume::getBinRadius()
 	}
 	else if (shrink_wrap)
 	{
-		radius = (ext[1]-ext[0]).length()*0.5f;
+		LLVector4a rad;
+		rad.setSub(ext[1], ext[0]);
+		
+		radius = rad.length3()*0.5f;
 	}
 	else if (mDrawable->isStatic())
 	{
@@ -2962,7 +3100,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
@@ -2974,7 +3112,7 @@ const LLVector3 LLVOVolume::getPivotPositionAgent() const
 	return LLViewerObject::getPivotPositionAgent();
 }
 
-void LLVOVolume::onShift(const LLVector3 &shift_vector)
+void LLVOVolume::onShift(const LLVector4a &shift_vector)
 {
 	if (mVolumeImpl)
 	{
@@ -3193,11 +3331,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;
@@ -3222,16 +3359,11 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		model_mat = &(drawable->getRegion()->mRenderMatrix);
 	}
 
-	U8 bump = (type == LLRenderPass::PASS_BUMP ? facep->getTextureEntry()->getBumpmap() : 0);
+	U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
 	
 	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())
 	{
@@ -3255,7 +3387,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_vec[idx]->mCount += facep->getIndicesCount();
 		draw_vec[idx]->mEnd += facep->getGeomCount();
 		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
-		validate_draw_info(*draw_vec[idx]);
+		draw_vec[idx]->validate();
 		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[0]);
 		update_min_max(draw_vec[idx]->mExtents[0], draw_vec[idx]->mExtents[1], facep->mExtents[1]);
 	}
@@ -3279,12 +3411,13 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		}
 		draw_info->mExtents[0] = facep->mExtents[0];
 		draw_info->mExtents[1] = facep->mExtents[1];
-		validate_draw_info(*draw_info);
 
 		if (LLPipeline::sUseTriStrips)
 		{
 			draw_info->mDrawMode = LLRender::TRIANGLE_STRIP;
 		}
+
+		draw_info->validate();
 	}
 }
 
@@ -3296,6 +3429,35 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
 static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume");
 static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
 
+#if LL_MESH_ENABLED
+static LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
+{
+	LLVOAvatar* avatar = vobj->getAvatar();
+					
+	if (avatar)
+	{
+		LLDrawable* drawable = avatar->mDrawable;
+		if (drawable && drawable->getNumFaces() > 0)
+		{
+			LLFace* face = drawable->getFace(0);
+			if (face)
+			{
+				LLDrawPool* drawpool = face->getPool();
+				if (drawpool)
+				{
+					if (drawpool->getType() == LLDrawPool::POOL_AVATAR)
+					{
+						return (LLDrawPoolAvatar*) drawpool;
+					}
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+#endif		
+
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
 	if (group->changeLOD())
@@ -3361,6 +3523,14 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 		drawablep->clearState(LLDrawable::HAS_ALPHA);
 
+#if LL_MESH_ENABLED
+		bool rigged = vobj->isAttachment() && 
+					vobj->isMesh() && 
+					gMeshRepo.getSkinInfo(vobj->getVolume()->getParams().getSculptID());
+#endif
+
+		bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
+
 		//for each face
 		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 		{
@@ -3368,6 +3538,105 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 			drawablep->updateFaceSize(i);
 			LLFace* facep = drawablep->getFace(i);
 
+#if LL_MESH_ENABLED
+			if (rigged) 
+			{
+				if (!facep->isState(LLFace::RIGGED))
+				{
+					facep->mVertexBuffer = NULL;
+					facep->mLastVertexBuffer = NULL;
+					facep->setState(LLFace::RIGGED);
+					
+					//get drawpool of avatar with rigged face
+					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+					
+					if (pool)
+					{
+						const LLTextureEntry* te = facep->getTextureEntry();
+
+						//remove face from old pool if it exists
+						LLDrawPool* old_pool = facep->getPool();
+						if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+						{
+							((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+						}
+
+						//add face to new pool
+						LLViewerTexture* tex = facep->getTexture();
+						U32 type = gPipeline.getPoolTypeFromTE(te, tex);
+
+						if (type == LLDrawPool::POOL_ALPHA)
+						{
+							if (te->getFullbright())
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+							}
+							else
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+							}
+						}
+						else if (te->getShiny())
+						{
+							if (te->getFullbright())
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
+							}
+							else
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+							}
+						}
+						else
+						{
+							if (te->getFullbright())
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
+							}
+							else
+							{
+								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+							}
+						}
+
+						if (te->getGlow())
+						{
+							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
+						}
+
+						if (LLPipeline::sRenderDeferred)
+						{
+							if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
+							{
+								if (te->getBumpmap())
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
+								}
+								else
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
+								}
+							}
+						}
+					}
+				}
+
+				continue;
+			}
+			else
+			{
+				if (facep->isState(LLFace::RIGGED))
+				{ //face is not rigged but used to be, remove from rigged face pool
+					LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
+					if (pool)
+					{
+						pool->removeRiggedFace(facep);
+					}
+					facep->clearState(LLFace::RIGGED);
+				}
+			}
+#endif
+
 			if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)
 			{
 				facep->mVertexBuffer = NULL;
@@ -3421,10 +3690,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 (facep->canRenderAsMask())
 					{ //can be treated as alpha mask
 						simple_faces.push_back(facep);
 					}
@@ -3465,7 +3731,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 							bump_faces.push_back(facep);
 						}
 						else if ((te->getShiny() && LLPipeline::sRenderBump) ||
-							!te->getFullbright())
+							!(te->getFullbright() || bake_sunlight))
 						{ //needs normal
 							simple_faces.push_back(facep);
 						}
@@ -3526,6 +3792,8 @@ 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)
 {
 	llassert(group);
@@ -3538,6 +3806,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) )
@@ -3558,6 +3827,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);
@@ -3667,6 +3941,8 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 			buffer_index = 0;
 		}
 
+		bool bake_sunlight = LLPipeline::sBakeSunlight && facep->getDrawable()->isStatic(); 
+
 		U32 index_count = facep->getIndicesCount();
 		U32 geom_count = facep->getGeomCount();
 
@@ -3765,17 +4041,14 @@ 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 (facep->canRenderAsMask())
 				{
-					if (te->getFullbright())
+					if (te->getFullbright() || LLPipeline::sNoAlpha)
 					{
 						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
 					}
@@ -3798,66 +4071,76 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				&& group->mSpatialPartition->mPartitionType != LLViewerRegion::PARTITION_HUD 
 				&& LLPipeline::sRenderBump 
 				&& te->getShiny())
-			{
+			{ //shiny
 				if (tex->getPrimaryFormat() == GL_ALPHA)
-				{
+				{ //invisiprim+shiny
 					registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY);
 					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
 				}
 				else if (LLPipeline::sRenderDeferred)
-				{
-					if (te->getBumpmap())
-					{
-						registerFace(group, facep, LLRenderPass::PASS_BUMP);
-					}
-					else if (te->getFullbright())
-					{
+				{ //deferred rendering
+					if (te->getFullbright())
+					{ //register in post deferred fullbright shiny pass
 						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
+						if (te->getBumpmap())
+						{ //register in post deferred bump pass
+							registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
+						}
+					}
+					else if (te->getBumpmap())
+					{ //register in deferred bump pass
+						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
 					else
-					{
+					{ //register in deferred simple pass (deferred simple includes shiny)
 						llassert(mask & LLVertexBuffer::MAP_NORMAL);
 						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
 					}
 				}
 				else if (fullbright)
-				{						
+				{	//not deferred, register in standard fullbright shiny pass					
 					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_SHINY);
 				}
 				else
-				{
+				{ //not deferred or fullbright, register in standard shiny pass
 					registerFace(group, facep, LLRenderPass::PASS_SHINY);
 				}
 			}
 			else
-			{
+			{ //not alpha and not shiny
 				if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA)
-				{
+				{ //invisiprim
 					registerFace(group, facep, LLRenderPass::PASS_INVISIBLE);
 				}
-				else if (fullbright)
-				{
+				else if (fullbright || bake_sunlight)
+				{ //fullbright
 					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
+					{ //if this is the deferred render and a bump map is present, register in post deferred bump
+						registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
+					}
 				}
 				else
 				{
-					if (LLPipeline::sRenderDeferred && te->getBumpmap())
-					{
+					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
+					{ //non-shiny or fullbright deferred bump
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
 					else
-					{
+					{ //all around simple
 						llassert(mask & LLVertexBuffer::MAP_NORMAL);
 						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
 					}
 				}
 				
+				//not sure why this is here -- shiny HUD attachments maybe?  -- davep 5/11/2010
 				if (!is_alpha && te->getShiny() && LLPipeline::sRenderBump)
 				{
 					registerFace(group, facep, LLRenderPass::PASS_SHINY);
 				}
 			}
 			
+			//not sure why this is here, and looks like it might cause bump mapped objects to get rendered redundantly -- davep 5/11/2010
 			if (!is_alpha && !LLPipeline::sRenderDeferred)
 			{
 				llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright);
@@ -3869,7 +4152,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);
 			}
@@ -3943,7 +4226,7 @@ LLHUDPartition::LLHUDPartition()
 	mLODPeriod = 1;
 }
 
-void LLHUDPartition::shift(const LLVector3 &offset)
+void LLHUDPartition::shift(const LLVector4a &offset)
 {
 	//HUD objects don't shift with region crossing.  That would be silly.
 }
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index a8bb597f93a2cf50203c98f3a030fe509b864055..d5606034d059fc2a9bf81b01bb4fa08b5f844a53 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -66,7 +66,7 @@ class LLVolumeInterface
 	virtual void onSetVolume(const LLVolumeParams &volume_params, const S32 detail) = 0;
 	virtual void onSetScale(const LLVector3 &scale, BOOL damped) = 0;
 	virtual void onParameterChanged(U16 param_type, LLNetworkData *data, BOOL in_use, bool local_origin) = 0;
-	virtual void onShift(const LLVector3 &shift_vector) = 0;
+	virtual void onShift(const LLVector4a &shift_vector) = 0;
 	virtual bool isVolumeUnique() const = 0; // Do we need a unique LLVolume instance?
 	virtual bool isVolumeGlobal() const = 0; // Are we in global space?
 	virtual bool isActive() const = 0; // Is this object currently active?
@@ -145,7 +145,7 @@ class LLVOVolume : public LLViewerObject
 
 				void	markForUpdate(BOOL priority)			{ LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; }
 
-	/*virtual*/ void	onShift(const LLVector3 &shift_vector); // Called when the drawable shifts
+	/*virtual*/ void	onShift(const LLVector4a &shift_vector); // Called when the drawable shifts
 
 	/*virtual*/ void	parameterChanged(U16 param_type, bool local_origin);
 	/*virtual*/ void	parameterChanged(U16 param_type, LLNetworkData* data, BOOL in_use, bool local_origin);
@@ -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);
@@ -196,7 +201,7 @@ class LLVOVolume : public LLViewerObject
 				void	regenFaces();
 				BOOL	genBBoxes(BOOL force_global);
 				void	preRebuild();
-	virtual		void	updateSpatialExtents(LLVector3& min, LLVector3& max);
+	virtual		void	updateSpatialExtents(LLVector4a& min, LLVector4a& max);
 	virtual		F32		getBinRadius();
 	
 	virtual U32 getPartitionType() const;
@@ -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/llvowater.cpp b/indra/newview/llvowater.cpp
index a8c4625f6ed8a5a58d738bc9478819d034351d17..7c1b22d43219696c2889c4ffe5a86beeabfcb1e4 100644
--- a/indra/newview/llvowater.cpp
+++ b/indra/newview/llvowater.cpp
@@ -258,15 +258,21 @@ void LLVOWater::setIsEdgePatch(const BOOL edge_patch)
 	mIsEdgePatch = edge_patch;
 }
 
-void LLVOWater::updateSpatialExtents(LLVector3 &newMin, LLVector3& newMax)
+void LLVOWater::updateSpatialExtents(LLVector4a &newMin, LLVector4a& newMax)
 {
-	LLVector3 pos = getPositionAgent();
-	LLVector3 scale = getScale();
-
-	newMin = pos - scale * 0.5f;
-	newMax = pos + scale * 0.5f;
+	LLVector4a pos;
+	pos.load3(getPositionAgent().mV);
+	LLVector4a scale;
+	scale.load3(getScale().mV);
+	scale.mul(0.5f);
+
+	newMin.setSub(pos, scale);
+	newMax.setAdd(pos, scale);
+	
+	pos.setAdd(newMin,newMax);
+	pos.mul(0.5f);
 
-	mDrawable->setPositionGroup((newMin + newMax) * 0.5f);
+	mDrawable->setPositionGroup(pos);
 }
 
 U32 LLVOWater::getPartitionType() const
diff --git a/indra/newview/llvowater.h b/indra/newview/llvowater.h
index 3cc031e589a63d530096d941d0dda2ef7a42439c..a868afe58b577bbc761c25b5125f51ea60343a3b 100644
--- a/indra/newview/llvowater.h
+++ b/indra/newview/llvowater.h
@@ -66,7 +66,7 @@ class LLVOWater : public LLStaticViewerObject
 	/*virtual*/ BOOL idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
 	/*virtual*/ LLDrawable* createDrawable(LLPipeline *pipeline);
 	/*virtual*/ BOOL        updateGeometry(LLDrawable *drawable);
-	/*virtual*/ void		updateSpatialExtents(LLVector3& newMin, LLVector3& newMax);
+	/*virtual*/ void		updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
 
 	/*virtual*/ void updateTextures();
 	/*virtual*/ void setPixelAreaAndAngle(LLAgent &agent); // generate accurate apparent angle and area
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index f30567f48162483ed78cf176bd3ca6d3475ba169..a1e4df8a66d4cb90620afbcd7c1490d6f33e9852 100644
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -1055,9 +1055,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 cc65b34a612e3eb6d4b7ed1312634457b54e2f7c..c5c727721127f6cd749aae6bd4a619f2a993a947 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
@@ -191,6 +193,7 @@ std::string gPoolNames[] =
 };
 
 void drawBox(const LLVector3& c, const LLVector3& r);
+void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
 
 U32 nhpo2(U32 v) 
 {
@@ -268,9 +271,12 @@ BOOL	LLPipeline::sRenderHighlight = TRUE;
 BOOL	LLPipeline::sForceOldBakedUpload = FALSE;
 S32		LLPipeline::sUseOcclusion = 0;
 BOOL	LLPipeline::sDelayVBUpdate = TRUE;
-BOOL	LLPipeline::sFastAlpha = TRUE;
+BOOL	LLPipeline::sAutoMaskAlphaDeferred = TRUE;
+BOOL	LLPipeline::sAutoMaskAlphaNonDeferred = FALSE;
 BOOL	LLPipeline::sDisableShaders = FALSE;
 BOOL	LLPipeline::sRenderBump = TRUE;
+BOOL	LLPipeline::sBakeSunlight = FALSE;
+BOOL	LLPipeline::sNoAlpha = FALSE;
 BOOL	LLPipeline::sUseTriStrips = TRUE;
 BOOL	LLPipeline::sUseFarClip = TRUE;
 BOOL	LLPipeline::sShadowRender = FALSE;
@@ -328,7 +334,6 @@ LLPipeline::LLPipeline() :
 	mInitialized(FALSE),
 	mVertexShadersEnabled(FALSE),
 	mVertexShadersLoaded(0),
-	mRenderTypeMask(0),
 	mRenderDebugFeatureMask(0),
 	mRenderDebugMask(0),
 	mOldRenderDebugMask(0),
@@ -362,6 +367,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");
 
@@ -381,7 +387,11 @@ void LLPipeline::init()
 	LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
 	resetFrameStats();
 
-	mRenderTypeMask = 0xffffffff;	// All render types start on
+	for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+	{
+		mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled
+	}
+
 	mRenderDebugFeatureMask = 0xffffffff; // All debugging features on
 	mRenderDebugMask = 0;	// All debug starts off
 
@@ -408,6 +418,8 @@ void LLPipeline::init()
 	{
 		mSpotLightFade[i] = 1.f;
 	}
+
+	setLightingDetail(-1);
 }
 
 LLPipeline::~LLPipeline()
@@ -510,6 +522,7 @@ void LLPipeline::destroyGL()
 }
 
 static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
+
 void LLPipeline::resizeScreenTexture()
 {
 	LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE);
@@ -566,9 +579,12 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
 
 		F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale");
 
+		//HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug)
+		U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0;
+
 		for (U32 i = 0; i < 4; i++)
 		{
-			mShadow[i].allocate(U32(resX*scale),U32(resY*scale), 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+			mShadow[i].allocate(U32(resX*scale),U32(resY*scale), shadow_fmt, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
 		}
 
 
@@ -577,11 +593,9 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
 
 		for (U32 i = 4; i < 6; i++)
 		{
-			mShadow[i].allocate(width, height, 0, TRUE, FALSE);
+			mShadow[i].allocate(width, height, shadow_fmt, TRUE, FALSE);
 		}
 
-
-
 		width = nhpo2(resX)/2;
 		height = nhpo2(resY)/2;
 		mLuminanceMap.allocate(width,height, GL_RGBA, FALSE, FALSE);
@@ -625,10 +639,11 @@ void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
 void LLPipeline::updateRenderDeferred()
 {
 	BOOL deferred = (gSavedSettings.getBOOL("RenderDeferred") && 
-		LLRenderTarget::sUseFBO &&
-		gSavedSettings.getBOOL("VertexShaderEnable") && 
-		gSavedSettings.getBOOL("RenderAvatarVP") &&
-		gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE;
+			 LLRenderTarget::sUseFBO &&
+			 LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
+			 gSavedSettings.getBOOL("VertexShaderEnable") && 
+			 gSavedSettings.getBOOL("RenderAvatarVP") &&
+			 gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE;
 	
 	sRenderDeferred = deferred;			
 }
@@ -1142,9 +1157,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();
 
@@ -1153,6 +1174,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())
 		{
@@ -1162,6 +1184,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
@@ -1172,18 +1195,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);
 
@@ -1480,11 +1508,214 @@ F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera
 	return radius*radius * F_PI;
 }
 
+//static
+F32 LLPipeline::calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera)
+{
+	LLVector4a origin;
+	origin.load3(camera.getOrigin().mV);
+
+	LLVector4a lookAt;
+	lookAt.setSub(center, origin);
+	F32 dist = lookAt.length3();
+
+	//ramp down distance for nearby objects
+	//shrink dist by dist/16.
+	if (dist < 16.f)
+	{
+		dist /= 16.f;
+		dist *= dist;
+		dist *= 16.f;
+	}
+
+	//get area of circle around node
+	F32 app_angle = atanf(size.length3()/dist);
+	F32 radius = app_angle*LLDrawable::sCurPixelAngle;
+	return radius*radius * F_PI;
+}
+
 void LLPipeline::grabReferences(LLCullResult& result)
 {
 	sCull = &result;
 }
 
+void LLPipeline::clearReferences()
+{
+	sCull = NULL;
+}
+
+void check_references(LLSpatialGroup* group, LLDrawable* drawable)
+{
+	for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+	{
+		if (drawable == *i)
+		{
+			llerrs << "LLDrawable deleted while actively reference by LLPipeline." << llendl;
+		}
+	}			
+}
+
+void check_references(LLDrawable* drawable, LLFace* face)
+{
+	for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+	{
+		if (drawable->getFace(i) == face)
+		{
+			llerrs << "LLFace deleted while actively referenced by LLPipeline." << llendl;
+		}
+	}
+}
+
+void check_references(LLSpatialGroup* group, LLFace* face)
+{
+	for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+	{
+		LLDrawable* drawable = *i;
+		check_references(drawable, face);
+	}			
+}
+
+void LLPipeline::checkReferences(LLFace* face)
+{
+#if 0
+	if (sCull)
+	{
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			check_references(group, face);
+		}
+
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			check_references(group, face);
+		}
+
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			check_references(group, face);
+		}
+
+		for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
+		{
+			LLDrawable* drawable = *iter;
+			check_references(drawable, face);	
+		}
+	}
+#endif
+}
+
+void LLPipeline::checkReferences(LLDrawable* drawable)
+{
+#if 0
+	if (sCull)
+	{
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			check_references(group, drawable);
+		}
+
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			check_references(group, drawable);
+		}
+
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			check_references(group, drawable);
+		}
+
+		for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList(); iter != sCull->endVisibleList(); ++iter)
+		{
+			if (drawable == *iter)
+			{
+				llerrs << "LLDrawable deleted while actively referenced by LLPipeline." << llendl;
+			}
+		}
+	}
+#endif
+}
+
+void check_references(LLSpatialGroup* group, LLDrawInfo* draw_info)
+{
+	for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+	{
+		LLSpatialGroup::drawmap_elem_t& draw_vec = i->second;
+		for (LLSpatialGroup::drawmap_elem_t::iterator j = draw_vec.begin(); j != draw_vec.end(); ++j)
+		{
+			LLDrawInfo* params = *j;
+			if (params == draw_info)
+			{
+				llerrs << "LLDrawInfo deleted while actively referenced by LLPipeline." << llendl;
+			}
+		}
+	}
+}
+
+
+void LLPipeline::checkReferences(LLDrawInfo* draw_info)
+{
+#if 0
+	if (sCull)
+	{
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			check_references(group, draw_info);
+		}
+
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			check_references(group, draw_info);
+		}
+
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+			check_references(group, draw_info);
+		}
+	}
+#endif
+}
+
+void LLPipeline::checkReferences(LLSpatialGroup* group)
+{
+#if 0
+	if (sCull)
+	{
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+		{
+			if (group == *iter)
+			{
+				llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
+			}
+		}
+
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginAlphaGroups(); iter != sCull->endAlphaGroups(); ++iter)
+		{
+			if (group == *iter)
+			{
+				llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
+			}
+		}
+
+		for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+		{
+			if (group == *iter)
+			{
+				llerrs << "LLSpatialGroup deleted while actively referenced by LLPipeline." << llendl;
+			}
+		}
+	}
+#endif
+}
+
+
 BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera)
 {
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
@@ -1513,8 +1744,10 @@ BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera)
 
 BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max)
 {
-	min = LLVector3(F32_MAX, F32_MAX, F32_MAX);
-	max = LLVector3(-F32_MAX, -F32_MAX, -F32_MAX);
+	const F32 X = 65536.f;
+
+	min = LLVector3(X,X,X);
+	max = LLVector3(-X,-X,-X);
 
 	U32 saved_camera_id = LLViewerCamera::sCurCameraID;
 	LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
@@ -1684,7 +1917,7 @@ void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
 	}
 
 	if (sMinRenderSize > 0.f && 
-			llmax(llmax(group->mBounds[1].mV[0], group->mBounds[1].mV[1]), group->mBounds[1].mV[2]) < sMinRenderSize)
+			llmax(llmax(group->mBounds[1][0], group->mBounds[1][1]), group->mBounds[1][2]) < sMinRenderSize)
 	{
 		return;
 	}
@@ -1792,6 +2025,10 @@ void LLPipeline::rebuildPriorityGroups()
 	
 	assertInitialized();
 
+#if LL_MESH_ENABLED
+	gMeshRepo.notifyLoadedMeshes();
+#endif
+
 	// Iterate through all drawables on the priority build queue,
 	for (LLSpatialGroup::sg_list_t::iterator iter = mGroupQ1.begin();
 		 iter != mGroupQ1.end(); ++iter)
@@ -1802,6 +2039,7 @@ void LLPipeline::rebuildPriorityGroups()
 	}
 
 	mGroupQ1.clear();
+
 }
 		
 void LLPipeline::rebuildGroups()
@@ -1953,31 +2191,40 @@ 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;
-	}
-	
-	if (drawablep->isSpatialBridge())
-	{
-		LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
 
-		if (root && root->getParent() && root->getVObj() && root->getVObj()->isAttachment())
+	if(drawablep && !drawablep->isDead())
+	{
+		if (drawablep->isSpatialBridge())
 		{
-			LLVOAvatar* av = root->getParent()->getVObj()->asAvatar();
-			if (av && av->isImpostor())
+			const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
+			llassert(root); // trying to catch a bad assumption
+			if (root && //  // this test may not be needed, see above
+			    root->getVObj()->isAttachment())
 			{
-				return;
+				LLDrawable* rootparent = root->getParent();
+				if (rootparent) // this IS sometimes NULL
+				{
+					LLViewerObject *vobj = rootparent->getVObj();
+					llassert(vobj); // trying to catch a bad assumption
+					if (vobj) // this test may not be needed, see above
+					{
+						const LLVOAvatar* av = vobj->asAvatar();
+						if (av && av->isImpostor())
+						{
+							return;
+						}
+					}
+				}
 			}
+			sCull->pushBridge((LLSpatialBridge*) drawablep);
+		}
+		else
+		{
+			sCull->pushDrawable(drawablep);
 		}
-		sCull->pushBridge((LLSpatialBridge*) drawablep);
-	}
-	else
-	{
-		sCull->pushDrawable(drawablep);
-	}
 
-	drawablep->setVisible(camera);
+		drawablep->setVisible(camera);
+	}
 }
 
 void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
@@ -2058,6 +2305,9 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
 	glClear(GL_DEPTH_BUFFER_BIT);
 	gDepthDirty = TRUE;
 		
+	LLVector4a offseta;
+	offseta.load3(offset.mV);
+
 	for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
 		 iter != mShiftList.end(); iter++)
 	{
@@ -2066,7 +2316,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
 		{
 			continue;
 		}	
-		drawablep->shiftPos(offset);	
+		drawablep->shiftPos(offseta);	
 		drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
 	}
 	mShiftList.resize(0);
@@ -2080,7 +2330,7 @@ void LLPipeline::shiftObjects(const LLVector3 &offset)
 			LLSpatialPartition* part = region->getSpatialPartition(i);
 			if (part)
 			{
-				part->shift(offset);
+				part->shift(offseta);
 			}
 		}
 	}
@@ -2187,14 +2437,13 @@ static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order");
 
 void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
 {
-	const U32 face_mask = (1 << LLPipeline::RENDER_TYPE_AVATAR) |
-						  (1 << LLPipeline::RENDER_TYPE_GROUND) |
-						  (1 << LLPipeline::RENDER_TYPE_TERRAIN) |
-						  (1 << LLPipeline::RENDER_TYPE_TREE) |
-						  (1 << LLPipeline::RENDER_TYPE_SKY) |
-						  (1 << LLPipeline::RENDER_TYPE_WATER);
-
-	if (mRenderTypeMask & face_mask)
+	if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
+					  LLPipeline::RENDER_TYPE_GROUND,
+					  LLPipeline::RENDER_TYPE_TERRAIN,
+					  LLPipeline::RENDER_TYPE_TREE,
+					  LLPipeline::RENDER_TYPE_SKY,
+					  LLPipeline::RENDER_TYPE_WATER,
+					  LLPipeline::END_RENDER_TYPES))
 	{
 		//clear faces from face pools
 		LLFastTimer t(FTM_RESET_DRAWORDER);
@@ -2618,8 +2867,10 @@ void LLPipeline::postSort(LLCamera& camera)
 			{
 				if (sMinRenderSize > 0.f)
 				{
-					LLVector3 bounds = (*k)->mExtents[1]-(*k)->mExtents[0];
-					if (llmax(llmax(bounds.mV[0], bounds.mV[1]), bounds.mV[2]) > sMinRenderSize)
+					LLVector4a bounds;
+					bounds.setSub((*k)->mExtents[1],(*k)->mExtents[0]);
+
+					if (llmax(llmax(bounds[0], bounds[1]), bounds[2]) > sMinRenderSize)
 					{
 						sCull->pushDrawInfo(j->first, *k);
 					}
@@ -3437,6 +3688,8 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 		gGLLastMatrix = NULL;
 		glLoadMatrixd(gGLModelView);
 		doOcclusion(camera);
+		gGLLastMatrix = NULL;
+		glLoadMatrixd(gGLModelView);
 	}
 }
 
@@ -3561,6 +3814,65 @@ 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;
+		
+#if LL_MESH_ENABLED
+		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;
+#endif
+	}
+
 	for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
 	{
 		LLSpatialBridge* bridge = *i;
@@ -3575,6 +3887,8 @@ void LLPipeline::renderDebug()
 
 	if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
 	{
+		LLVertexBuffer::unbind();
+
 		LLGLEnable blend(GL_BLEND);
 		LLGLDepthTest depth(TRUE, FALSE);
 		LLGLDisable cull(GL_CULL_FACE);
@@ -3599,12 +3913,17 @@ void LLPipeline::renderDebug()
 
 		for (U32 i = 0; i < 8; i++)
 		{
+			LLVector3* frust = mShadowCamera[i].mAgentFrustum;
+
 			if (i > 3)
-			{
+			{ //render shadow frusta as volumes
+				if (mShadowFrustPoints[i-4].empty())
+				{
+					continue;
+				}
+
 				gGL.color4fv(col+(i-4)*4);	
 			
-				LLVector3* frust = mShadowCamera[i].mAgentFrustum;
-
 				gGL.begin(LLRender::TRIANGLE_STRIP);
 				gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
 				gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
@@ -3632,31 +3951,49 @@ void LLPipeline::renderDebug()
 	
 			if (i < 4)
 			{
-				gGL.begin(LLRender::LINES);
-				
-				F32* c = col+i*4;
-				for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j)
+
+				//if (i == 0 || !mShadowFrustPoints[i].empty())
 				{
-					
-					gGL.color3fv(c);
+					//render visible point cloud
+					gGL.flush();
+					glPointSize(8.f);
+					gGL.begin(LLRender::POINTS);
 
-					for (U32 k = 0; k < mShadowFrustPoints[i].size(); ++k)
-					{
-						if (j != k)
-						{
-							gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
-							gGL.vertex3fv(mShadowFrustPoints[i][k].mV);
-						}
-					}
+					F32* c = col+i*4;
+					gGL.color3fv(c);
 
-					if (!mShadowFrustOrigin[i].isExactlyZero())
-					{
+					for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j)
+					{	
 						gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
-						gGL.color4f(1,1,1,1);
-						gGL.vertex3fv(mShadowFrustOrigin[i].mV);
+						
 					}
+					gGL.end();
+
+					gGL.flush();
+					glPointSize(1.f);
+
+					LLVector3* ext = mShadowExtents[i]; 
+					LLVector3 pos = (ext[0]+ext[1])*0.5f;
+					LLVector3 size = (ext[1]-ext[0])*0.5f;
+					drawBoxOutline(pos, size);
+
+					//render camera frustum splits as outlines
+					gGL.begin(LLRender::LINES);
+					gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV);
+					gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV);
+					gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV);
+					gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV);
+					gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV);
+					gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV);
+					gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV);
+					gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV);
+					gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+					gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
+					gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
+					gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+					gGL.end();
 				}
-				gGL.end();
+
 			}
 
 			/*for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
@@ -4280,7 +4617,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)
 	{
@@ -4374,7 +4711,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();
@@ -4568,32 +4905,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)
 			{
@@ -4609,8 +4955,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;
@@ -4620,13 +4965,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);
@@ -4634,8 +4976,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);
 	}
@@ -4756,16 +5098,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
 }
 
 //============================================================================
@@ -4955,8 +5297,7 @@ void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
 //static
 void LLPipeline::toggleRenderType(U32 type)
 {
-	U32 bit = (1<<type);
-	gPipeline.mRenderTypeMask ^= bit;
+	gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type];
 }
 
 //static
@@ -5368,6 +5709,9 @@ void LLPipeline::resetVertexBuffers()
 {
 	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
 	sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
+	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+	sBakeSunlight = gSavedSettings.getBOOL("RenderBakeSunlight");
+	sNoAlpha = gSavedSettings.getBOOL("RenderNoAlpha");
 
 	for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin(); 
 			iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
@@ -5503,6 +5847,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);
@@ -5825,6 +6170,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);
+		}
 	}
 	
 
@@ -5841,8 +6192,12 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 
 }
 
+static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred");
+
 void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRenderTarget* gi_source, LLRenderTarget* last_gi_post, U32 noise_map)
 {
+	LLFastTimer t(FTM_BIND_DEFERRED);
+
 	if (noise_map == 0xFFFFFFFF)
 	{
 		noise_map = mNoiseMap;
@@ -6180,11 +6535,16 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRen
 								matrix_nondiag, matrix_nondiag, matrix_diag};
 	shader.uniformMatrix3fv("ssao_effect_mat", 1, GL_FALSE, ssao_effect_mat);
 
+	F32 shadow_offset_error = 1.f + gSavedSettings.getF32("RenderShadowOffsetError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
+	F32 shadow_bias_error = 1.f + gSavedSettings.getF32("RenderShadowBiasError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
+
 	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 ("shadow_offset", gSavedSettings.getF32("RenderShadowOffset")*shadow_offset_error);
+	shader.uniform1f("shadow_bias", gSavedSettings.getF32("RenderShadowBias")*shadow_bias_error);
+	shader.uniform1f ("spot_shadow_offset", gSavedSettings.getF32("RenderSpotShadowOffset"));
+	shader.uniform1f("spot_shadow_bias", gSavedSettings.getF32("RenderSpotShadowBias"));	
+
 	shader.uniform1f("lum_scale", gSavedSettings.getF32("RenderLuminanceScale"));
 	shader.uniform1f("sun_lum_scale", gSavedSettings.getF32("RenderSunLuminanceScale"));
 	shader.uniform1f("sun_lum_offset", gSavedSettings.getF32("RenderSunLuminanceOffset"));
@@ -6278,16 +6638,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);
@@ -6328,18 +6688,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);
@@ -6436,79 +6800,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);
@@ -6557,15 +6921,16 @@ void LLPipeline::renderDeferredLighting()
 			LLGLDisable stencil(GL_STENCIL_TEST);
 			gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
-			U32 render_mask = mRenderTypeMask;
-			mRenderTypeMask =	mRenderTypeMask & 
-								((1 << LLPipeline::RENDER_TYPE_SKY) |
-								(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
-								(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+			gPipeline.pushRenderTypeMask();
+			
+			gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+										LLPipeline::RENDER_TYPE_CLOUDS,
+										LLPipeline::RENDER_TYPE_WL_SKY,
+										LLPipeline::END_RENDER_TYPES);
 								
 			
 			renderGeomPostDeferred(*LLViewerCamera::getInstance());
-			mRenderTypeMask = render_mask;
+			gPipeline.popRenderTypeMask();
 		}
 
 		BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
@@ -6610,8 +6975,18 @@ void LLPipeline::renderDeferredLighting()
 						continue;
 					}
 
-					LLVector3 center = drawablep->getPositionAgent();
-					F32* c = center.mV;
+					if (volume->isAttachment())
+					{
+						if (!sRenderAttachedLights)
+						{
+							continue;
+						}
+					}
+
+
+					LLVector4a center;
+					center.load3(drawablep->getPositionAgent().mV);
+					const F32* c = center.getF32();
 					F32 s = volume->getLightRadius()*1.5f;
 
 					LLColor3 col = volume->getLightColor();
@@ -6627,7 +7002,9 @@ void LLPipeline::renderDeferredLighting()
 						continue;
 					}
 
-					if (camera->AABBInFrustumNoFarClip(center, LLVector3(s,s,s)) == 0)
+					LLVector4a sa;
+					sa.splat(s);
+					if (camera->AABBInFrustumNoFarClip(center, sa) == 0)
 					{
 						continue;
 					}
@@ -6660,7 +7037,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);
@@ -6677,7 +7054,7 @@ void LLPipeline::renderDeferredLighting()
 					}
 					else if (render_fullscreen)
 					{	
-						if (volume->getLightTexture())
+						if (volume->isLightSpotlight())
 						{
 							drawablep->getVOVolume()->updateSpotLightPriority();
 							fullscreen_spot_lights.push_back(drawablep);
@@ -6705,8 +7082,9 @@ void LLPipeline::renderDeferredLighting()
 
 					LLVOVolume* volume = drawablep->getVOVolume();
 
-					LLVector3 center = drawablep->getPositionAgent();
-					F32* c = center.mV;
+					LLVector4a center;
+					center.load3(drawablep->getPositionAgent().mV);
+					const F32* c = center.getF32();
 					F32 s = volume->getLightRadius()*1.5f;
 
 					sVisibleLightCount++;
@@ -6878,29 +7256,47 @@ void LLPipeline::renderDeferredLighting()
 		LLGLDisable blend(GL_BLEND);
 		LLGLDisable stencil(GL_STENCIL_TEST);
 
-		U32 render_mask = mRenderTypeMask;
-		mRenderTypeMask =	mRenderTypeMask & 
-							((1 << LLPipeline::RENDER_TYPE_ALPHA) |
-							(1 << LLPipeline::RENDER_TYPE_FULLBRIGHT) |
-							(1 << LLPipeline::RENDER_TYPE_VOLUME) |
-							(1 << LLPipeline::RENDER_TYPE_GLOW) |
-							(1 << LLPipeline::RENDER_TYPE_BUMP) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_BUMP) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_GLOW) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_GRASS) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_SHINY) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_INVISIBLE) |
-							(1 << LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY) |
-							(1 << LLPipeline::RENDER_TYPE_AVATAR));
+		pushRenderTypeMask();
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+						 LLPipeline::RENDER_TYPE_FULLBRIGHT,
+						 LLPipeline::RENDER_TYPE_VOLUME,
+						 LLPipeline::RENDER_TYPE_GLOW,
+						 LLPipeline::RENDER_TYPE_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+						 LLPipeline::RENDER_TYPE_PASS_ALPHA,
+						 LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_PASS_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+						 LLPipeline::RENDER_TYPE_PASS_GLOW,
+						 LLPipeline::RENDER_TYPE_PASS_GRASS,
+						 LLPipeline::RENDER_TYPE_PASS_SHINY,
+						 LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+						 LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+						 LLPipeline::RENDER_TYPE_AVATAR,
+						 END_RENDER_TYPES);
 		
 		renderGeomPostDeferred(*LLViewerCamera::getInstance());
-		mRenderTypeMask = render_mask;
+		popRenderTypeMask();
+	}
+
+	{
+		//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();
@@ -7137,8 +7533,8 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
 		LLPipeline::sUseOcclusion = llmin(occlusion, 1);
 		
-		U32 type_mask = gPipeline.mRenderTypeMask;
-
+		gPipeline.pushRenderTypeMask();
+		
 		glh::matrix4f projection = glh_get_current_projection();
 		glh::matrix4f mat;
 
@@ -7206,44 +7602,48 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			glCullFace(GL_FRONT);
 
 			static LLCullResult ref_result;
-			U32 ref_mask = 0;
+		
 			if (LLDrawPoolWater::sNeedsDistortionUpdate)
 			{
 				//initial sky pass (no user clip plane)
 				{ //mask out everything but the sky
-					U32 tmp = mRenderTypeMask;
-					mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
-										(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+					gPipeline.pushRenderTypeMask();
+					gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+												LLPipeline::RENDER_TYPE_WL_SKY,
+												LLPipeline::END_RENDER_TYPES);
 					static LLCullResult result;
 					updateCull(camera, result);
 					llpushcallstacks ;
 					stateSort(camera, result);
-					mRenderTypeMask = tmp & ((1 << LLPipeline::RENDER_TYPE_SKY) |
-										(1 << LLPipeline::RENDER_TYPE_CLOUDS) |
-										(1 << LLPipeline::RENDER_TYPE_WL_SKY));
+					andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+										LLPipeline::RENDER_TYPE_CLOUDS,
+										LLPipeline::RENDER_TYPE_WL_SKY,
+										LLPipeline::END_RENDER_TYPES);
+
 					renderGeom(camera, TRUE);
-					mRenderTypeMask = tmp;
+					gPipeline.popRenderTypeMask();
 				}
 
-				U32 mask = mRenderTypeMask;
-				mRenderTypeMask &=	~((1<<LLPipeline::RENDER_TYPE_WATER) |
-									  (1<<LLPipeline::RENDER_TYPE_GROUND) |
-									  (1<<LLPipeline::RENDER_TYPE_SKY) |
-									  (1<<LLPipeline::RENDER_TYPE_CLOUDS));	
-
-				if (gSavedSettings.getBOOL("RenderWaterReflections"))
+				gPipeline.pushRenderTypeMask();
+				
+				clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+									LLPipeline::RENDER_TYPE_GROUND,
+									LLPipeline::RENDER_TYPE_SKY,
+									LLPipeline::RENDER_TYPE_CLOUDS,
+									LLPipeline::END_RENDER_TYPES);	
+
+				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)
+						clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES);
+						if (detail < 3)
 						{
-							mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_AVATAR);
-							if (detail < 1)
+							clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
+							if (detail < 2)
 							{
-								mRenderTypeMask &= ~(1 << LLPipeline::RENDER_TYPE_VOLUME);
+								clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);
 							}
 						}
 					}
@@ -7253,20 +7653,19 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 					updateCull(camera, ref_result, 1);
 					llpushcallstacks ;
 					stateSort(camera, ref_result);
-				}
+				}	
 				
-				ref_mask = mRenderTypeMask;
-				mRenderTypeMask = mask;
-			}
-			if (LLDrawPoolWater::sNeedsDistortionUpdate)
-			{
-				mRenderTypeMask = ref_mask;
-				if (gSavedSettings.getBOOL("RenderWaterReflections"))
+				if (LLDrawPoolWater::sNeedsDistortionUpdate)
 				{
-					gPipeline.grabReferences(ref_result);
-					LLGLUserClipPlane clip_plane(plane, mat, projection);
-					renderGeom(camera);
+					if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
+					{
+						gPipeline.grabReferences(ref_result);
+						LLGLUserClipPlane clip_plane(plane, mat, projection);
+						renderGeom(camera);
+					}
 				}
+
+				gPipeline.popRenderTypeMask();
 			}	
 			glCullFace(GL_BACK);
 			glPopMatrix();
@@ -7280,18 +7679,20 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 		if (last_update)
 		{
 			camera.setFar(camera_in.getFar());
-			mRenderTypeMask = type_mask & (~(1<<LLPipeline::RENDER_TYPE_WATER) |
-											(1<<LLPipeline::RENDER_TYPE_GROUND));	
+			clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+								LLPipeline::RENDER_TYPE_GROUND,
+								END_RENDER_TYPES);	
 			stop_glerror();
 
 			LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE;
 
 			if (LLPipeline::sUnderWaterRender)
 			{
-				mRenderTypeMask &=	~((1<<LLPipeline::RENDER_TYPE_GROUND) |
-									  (1<<LLPipeline::RENDER_TYPE_SKY) |
-									  (1<<LLPipeline::RENDER_TYPE_CLOUDS) |
-									  (1<<LLPipeline::RENDER_TYPE_WL_SKY));		
+				clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND,
+									LLPipeline::RENDER_TYPE_SKY,
+									LLPipeline::RENDER_TYPE_CLOUDS,
+									LLPipeline::RENDER_TYPE_WL_SKY,
+									END_RENDER_TYPES);		
 			}
 			LLViewerCamera::updateFrustumPlanes(camera);
 
@@ -7333,7 +7734,7 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 		}
 		glClearColor(0.f, 0.f, 0.f, 0.f);
 		gViewerWindow->setup3DViewport();
-		mRenderTypeMask = type_mask;
+		gPipeline.popRenderTypeMask();
 		LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
 		LLDrawPoolWater::sNeedsDistortionUpdate = FALSE;
 		LLViewerCamera::getInstance()->setUserClipPlane(LLPlane(-pnorm, -pd));
@@ -7525,115 +7926,172 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 	LLPipeline::sShadowRender = FALSE;
 }
 
-
+static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud");
 BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
 {
+	LLFastTimer t(FTM_VISIBLE_CLOUD);
 	//get point cloud of intersection of frust and min, max
 
-	//get set of planes
-	std::vector<LLPlane> ps;
-	
 	if (getVisibleExtents(camera, min, max))
 	{
 		return FALSE;
 	}
 
-	ps.push_back(LLPlane(min, LLVector3(-1,0,0)));
-	ps.push_back(LLPlane(min, LLVector3(0,-1,0)));
-	ps.push_back(LLPlane(min, LLVector3(0,0,-1)));
-	ps.push_back(LLPlane(max, LLVector3(1,0,0)));
-	ps.push_back(LLPlane(max, LLVector3(0,1,0)));
-	ps.push_back(LLPlane(max, LLVector3(0,0,1)));
+	//get set of planes on bounding box
+	std::vector<LLPlane> bp;
+		
+	bp.push_back(LLPlane(min, LLVector3(-1,0,0)));
+	bp.push_back(LLPlane(min, LLVector3(0,-1,0)));
+	bp.push_back(LLPlane(min, LLVector3(0,0,-1)));
+	bp.push_back(LLPlane(max, LLVector3(1,0,0)));
+	bp.push_back(LLPlane(max, LLVector3(0,1,0)));
+	bp.push_back(LLPlane(max, LLVector3(0,0,1)));
+	
+	//potential points
+	std::vector<LLVector3> pp;
+
+	//add corners of AABB
+	pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2]));
+	pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2]));
+	pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2]));
+	pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2]));
+	pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2]));
+	pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2]));
+	pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2]));
+	pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2]));
+
+	//add corners of camera frustum
+	for (U32 i = 0; i < 8; i++)
+	{
+		pp.push_back(camera.mAgentFrustum[i]);
+	}
+
 
-	/*if (!light_dir.isExactlyZero())
+	//bounding box line segments
+	U32 bs[] = 
 	{
-		LLPlane ucp;
-		LLPlane mcp;
+		0,1,
+		1,3,
+		3,2,
+		2,0,
 
-		F32 maxd = -1.f;
-		F32 mind = 1.f;
+		4,5,
+		5,7,
+		7,6,
+		6,4,
 
-		for (U32 i = 0; i < ps.size(); ++i)
-		{  //pick the plane most aligned to lightDir for user clip plane
-			LLVector3 n(ps[i].mV);
-			F32 da = n*light_dir;
-			if (da > maxd)
-			{
-				maxd = da;
-				ucp = ps[i];
-			}
+		0,4,
+		1,5,
+		3,7,
+		2,6
+	};
+
+	for (U32 i = 0; i < 12; i++)
+	{ //for each line segment in bounding box
+		for (U32 j = 0; j < 6; j++) 
+		{ //for each plane in camera frustum
+			const LLPlane& cp = camera.getAgentPlane(j);
+			const LLVector3& v1 = pp[bs[i*2+0]];
+			const LLVector3& v2 = pp[bs[i*2+1]];
+			const LLVector3 n(cp.mV);
+
+			LLVector3 line = v1-v2;
 
-			if (da < mind)
+			F32 d1 = line*n;
+			F32 d2 = -cp.dist(v2);
+
+			F32 t = d2/d1;
+
+			if (t > 0.f && t < 1.f)
 			{
-				mind = da;
-				mcp = ps[i];
+				LLVector3 intersect = v2+line*t;
+				pp.push_back(intersect);
 			}
 		}
-			
-		camera.setUserClipPlane(ucp);
+	}
 
-		ps.clear();
-		ps.push_back(ucp);
-		ps.push_back(mcp);
-	}*/
-	
-	for (U32 i = 0; i < 6; i++)
+	//camera frustum line segments
+	const U32 fs[] =
 	{
-		ps.push_back(camera.getAgentPlane(i));
-	}
+		0,1,
+		1,2,
+		2,3,
+		3,0,
 
-	//get set of points where planes intersect and points are not above any plane
-	fp.clear();
-	
-	for (U32 i = 0; i < ps.size(); ++i)
+		4,5,
+		5,6,
+		6,7,
+		7,4,
+
+		0,4,
+		1,5,
+		2,6,
+		3,7	
+	};
+
+	LLVector3 center = (max+min)*0.5f;
+	LLVector3 size = (max-min)*0.5f;
+
+	for (U32 i = 0; i < 12; i++)
 	{
-		for (U32 j = 0; j < ps.size(); ++j)
+		for (U32 j = 0; j < 6; ++j)
 		{
-			for (U32 k = 0; k < ps.size(); ++k)
-			{
-				if (i == j ||
-					i == k ||
-					k == j)
-				{
-					continue;
-				}
+			const LLVector3& v1 = pp[fs[i*2+0]+8];
+			const LLVector3& v2 = pp[fs[i*2+1]+8];
+			const LLPlane& cp = bp[j];
+			const LLVector3 n(cp.mV);
 
-				LLVector3 n1,n2,n3;
-				F32 d1,d2,d3;
+			LLVector3 line = v1-v2;
 
-				n1.setVec(ps[i].mV);
-				n2.setVec(ps[j].mV);
-				n3.setVec(ps[k].mV);
+			F32 d1 = line*n;
+			F32 d2 = -cp.dist(v2);
 
-				d1 = ps[i].mV[3];
-				d2 = ps[j].mV[3];
-				d3 = ps[k].mV[3];
-			
-				//get point of intersection of 3 planes "p"
-				LLVector3 p = (-d1*(n2%n3)-d2*(n3%n1)-d3*(n1%n2))/(n1*(n2%n3));
-				
-				if (llround(p*n1+d1, 0.0001f) == 0.f &&
-					llround(p*n2+d2, 0.0001f) == 0.f &&
-					llround(p*n3+d3, 0.0001f) == 0.f)
-				{ //point is on all three planes
-					BOOL found = TRUE;
-					for (U32 l = 0; l < ps.size() && found; ++l)
-					{
-						if (llround(ps[l].dist(p), 0.0001f) > 0.0f)
-						{ //point is above some plane, not contained
-							found = FALSE;	
-						}
-					}
+			F32 t = d2/d1;
 
-					if (found)
-					{
-						fp.push_back(p);
-					}
-				}
-			}
+			if (t > 0.f && t < 1.f)
+			{
+				LLVector3 intersect = v2+line*t;
+				pp.push_back(intersect);
+			}	
 		}
 	}
 	
+	LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f),
+		max+LLVector3(0.05f,0.05f,0.05f) };
+
+	for (U32 i = 0; i < pp.size(); ++i)
+	{
+		bool found = true;
+		
+		const F32* p = pp[i].mV;
+
+		for (U32 j = 0; j < 3; ++j)
+		{
+			if (p[j] < ext[0].mV[j] ||
+				p[j] > ext[1].mV[j])
+			{
+				found = false;
+				break;
+			}
+		}
+			
+		for (U32 j = 0; j < 6; ++j)
+		{
+			const LLPlane& cp = camera.getAgentPlane(j);
+			F32 dist = cp.dist(pp[i]);
+			if (dist > 0.05f) //point is above some plane, not contained
+			{
+				found = false;
+				break;
+			}
+		}
+
+		if (found)
+		{
+			fp.push_back(pp[i]);
+		}
+	}
+
 	if (fp.empty())
 	{
 		return FALSE;
@@ -7731,21 +8189,22 @@ void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<L
 	sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
 	static LLCullResult result;
 
-	U32 type_mask = mRenderTypeMask;
+	pushRenderTypeMask();
 
-	mRenderTypeMask = type_mask & ((1<<LLPipeline::RENDER_TYPE_SIMPLE) |
-								   (1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
-								   (1<<LLPipeline::RENDER_TYPE_BUMP) |
-								   (1<<LLPipeline::RENDER_TYPE_VOLUME) |
-								   (1<<LLPipeline::RENDER_TYPE_TREE) | 
-								   (1<<LLPipeline::RENDER_TYPE_TERRAIN) |
-								   (1<<LLPipeline::RENDER_TYPE_WATER) |
-								   (1<<LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW) |
-								   (1<<LLPipeline::RENDER_TYPE_AVATAR) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
-									(1 << LLPipeline::RENDER_TYPE_PASS_BUMP) |
-									(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
-									(1 << LLPipeline::RENDER_TYPE_PASS_SHINY));
+	andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
+								 LLPipeline::RENDER_TYPE_FULLBRIGHT,
+								 LLPipeline::RENDER_TYPE_BUMP,
+								 LLPipeline::RENDER_TYPE_VOLUME,
+								 LLPipeline::RENDER_TYPE_TREE, 
+								 LLPipeline::RENDER_TYPE_TERRAIN,
+								 LLPipeline::RENDER_TYPE_WATER,
+								 LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
+								 LLPipeline::RENDER_TYPE_AVATAR,
+								 LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+								 LLPipeline::RENDER_TYPE_PASS_BUMP,
+								 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+								 LLPipeline::RENDER_TYPE_PASS_SHINY,
+								 END_RENDER_TYPES);
 
 
 	
@@ -7814,7 +8273,7 @@ void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<L
 	LLPipeline::sShadowRender = FALSE;
 	sMinRenderSize = 0.f;
 
-	mRenderTypeMask = type_mask;
+	popRenderTypeMask();
 
 }
 
@@ -7898,30 +8357,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++)
@@ -7930,23 +8370,24 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		last_projection[i] = gGLLastProjection[i];
 	}
 
-	U32 type_mask = mRenderTypeMask;
-	mRenderTypeMask = type_mask & ((1<<LLPipeline::RENDER_TYPE_SIMPLE) |
-								   (1<<LLPipeline::RENDER_TYPE_ALPHA) |
-								   (1<<LLPipeline::RENDER_TYPE_GRASS) |
-								   (1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
-								   (1<<LLPipeline::RENDER_TYPE_BUMP) |
-								   (1<<LLPipeline::RENDER_TYPE_VOLUME) |
-								   (1<<LLPipeline::RENDER_TYPE_AVATAR) |
-								   (1<<LLPipeline::RENDER_TYPE_TREE) | 
-								   (1<<LLPipeline::RENDER_TYPE_TERRAIN) |
-								   (1<<LLPipeline::RENDER_TYPE_WATER) |
-								   (1<<LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_BUMP) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_SHINY) |
-								   (1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY));
+	pushRenderTypeMask();
+	andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
+					LLPipeline::RENDER_TYPE_ALPHA,
+					LLPipeline::RENDER_TYPE_GRASS,
+					LLPipeline::RENDER_TYPE_FULLBRIGHT,
+					LLPipeline::RENDER_TYPE_BUMP,
+					LLPipeline::RENDER_TYPE_VOLUME,
+					LLPipeline::RENDER_TYPE_AVATAR,
+					LLPipeline::RENDER_TYPE_TREE, 
+					LLPipeline::RENDER_TYPE_TERRAIN,
+					LLPipeline::RENDER_TYPE_WATER,
+					LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
+					LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+					LLPipeline::RENDER_TYPE_PASS_BUMP,
+					LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+					LLPipeline::RENDER_TYPE_PASS_SHINY,
+					LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+					END_RENDER_TYPES);
 
 	gGL.setColorMask(false, false);
 
@@ -7975,6 +8416,14 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 	LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist");
 	//F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
 
+	//put together a universal "near clip" plane for shadow frusta
+	LLPlane shadow_near_clip;
+	{
+		LLVector3 p = gAgent.getPositionAgent();
+		p += mSunDir * gSavedSettings.getF32("RenderFarClip")*2.f;
+		shadow_near_clip.setVec(p, mSunDir);
+	}
+
 	LLVector3 lightDir = -mSunDir;
 	lightDir.normVec();
 
@@ -7998,17 +8447,32 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 	at.normVec();
 	
 	
+	LLCamera main_camera = camera;
+	
 	F32 near_clip = 0.f;
 	{
 		//get visible point cloud
 		std::vector<LLVector3> fp;
 
+		main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum);
+		
 		LLVector3 min,max;
-		getVisiblePointCloud(camera,min,max,fp);
+		getVisiblePointCloud(main_camera,min,max,fp);
 
 		if (fp.empty())
 		{
-			mRenderTypeMask = type_mask;
+			if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
+			{
+				mShadowCamera[0] = main_camera;
+				mShadowExtents[0][0] = min;
+				mShadowExtents[0][1] = max;
+
+				mShadowFrustPoints[0].clear();
+				mShadowFrustPoints[1].clear();
+				mShadowFrustPoints[2].clear();
+				mShadowFrustPoints[3].clear();
+			}
+			popRenderTypeMask();
 			return;
 		}
 
@@ -8082,7 +8546,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		shadow_cam = camera;
 		shadow_cam.setFar(16.f);
 	
-		LLViewerCamera::updateFrustumPlanes(shadow_cam);
+		LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
 
 		LLVector3* frust = shadow_cam.mAgentFrustum;
 
@@ -8094,10 +8558,11 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		for (U32 i = 0; i < 4; i++)
 		{
 			LLVector3 delta = frust[i+4]-eye;
+			delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f;
 			delta.normVec();
 			F32 dp = delta*pn;
-			frust[i] = eye + (delta*dist[j])/dp;
-			frust[i+4] = eye + (delta*dist[j+1])/dp;
+			frust[i] = eye + (delta*dist[j]*0.95f)/dp;
+			frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp;
 		}
 						
 		shadow_cam.calcAgentFrustumPlanes(frust);
@@ -8393,7 +8858,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 
 		LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
 
-		shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
+		//shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
+		shadow_cam.getAgentPlane(LLCamera::AGENT_PLANE_NEAR).set(shadow_near_clip);
 
 		//translate and scale to from [-1, 1] to [0, 1]
 		glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
@@ -8437,135 +8903,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"))
 	{
@@ -8589,7 +9075,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 		gGLLastProjection[i] = last_projection[i];
 	}
 
-	mRenderTypeMask = type_mask;
+	popRenderTypeMask();
 }
 
 void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
@@ -8625,38 +9111,36 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 
 	assertInitialized();
 
-	U32 mask;
 	BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID());
 
+	pushRenderTypeMask();
+	
 	if (muted)
 	{
-		mask  = 1 << LLPipeline::RENDER_TYPE_AVATAR;
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
 	}
 	else
 	{
-		mask  = (1<<LLPipeline::RENDER_TYPE_VOLUME) |
-				(1<<LLPipeline::RENDER_TYPE_AVATAR) |
-				(1<<LLPipeline::RENDER_TYPE_BUMP) |
-				(1<<LLPipeline::RENDER_TYPE_GRASS) |
-				(1<<LLPipeline::RENDER_TYPE_SIMPLE) |
-				(1<<LLPipeline::RENDER_TYPE_FULLBRIGHT) |
-				(1<<LLPipeline::RENDER_TYPE_ALPHA) | 
-				(1<<LLPipeline::RENDER_TYPE_INVISIBLE) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_SIMPLE) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_SHINY) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_INVISIBLE) |
-				(1 << LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY);
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
+						LLPipeline::RENDER_TYPE_AVATAR,
+						LLPipeline::RENDER_TYPE_BUMP,
+						LLPipeline::RENDER_TYPE_GRASS,
+						LLPipeline::RENDER_TYPE_SIMPLE,
+						LLPipeline::RENDER_TYPE_FULLBRIGHT,
+						LLPipeline::RENDER_TYPE_ALPHA, 
+						LLPipeline::RENDER_TYPE_INVISIBLE,
+						LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+						LLPipeline::RENDER_TYPE_PASS_ALPHA,
+						LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+						LLPipeline::RENDER_TYPE_PASS_SHINY,
+						LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+						LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+						END_RENDER_TYPES);
 	}
 	
-	mask = mask & gPipeline.getRenderTypeMask();
-	U32 saved_mask = gPipeline.mRenderTypeMask;
-	gPipeline.mRenderTypeMask = mask;
-
 	S32 occlusion = sUseOcclusion;
 	sUseOcclusion = 0;
 	sReflectionRender = sRenderDeferred ? FALSE : TRUE;
@@ -8686,7 +9170,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 
 	stateSort(*LLViewerCamera::getInstance(), result);
 	
-	const LLVector3* ext = avatar->mDrawable->getSpatialExtents();
+	const LLVector4a* ext = avatar->mDrawable->getSpatialExtents();
 	LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
 
 	LLCamera camera = *viewer_camera;
@@ -8695,18 +9179,23 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	
 	LLVector2 tdim;
 
-	LLVector3 half_height = (ext[1]-ext[0])*0.5f;
 
-	LLVector3 left = camera.getLeftAxis();
-	left *= left;
-	left.normalize();
+	LLVector4a half_height;
+	half_height.setSub(ext[1], ext[0]);
+	half_height.mul(0.5f);
+
+	LLVector4a left;
+	left.load3(camera.getLeftAxis().mV);
+	left.mul(left);
+	left.normalize3fast();
 
-	LLVector3 up = camera.getUpAxis();
-	up *= up;
-	up.normalize();
+	LLVector4a up;
+	up.load3(camera.getUpAxis().mV);
+	up.mul(up);
+	up.normalize3fast();
 
-	tdim.mV[0] = fabsf(half_height * left);
-	tdim.mV[1] = fabsf(half_height * up);
+	tdim.mV[0] = fabsf(half_height.dot3(left));
+	tdim.mV[1] = fabsf(half_height.dot3(up));
 
 	glMatrixMode(GL_PROJECTION);
 	glPushMatrix();
@@ -8830,7 +9319,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	sReflectionRender = FALSE;
 	sImpostorRender = FALSE;
 	sShadowRender = FALSE;
-	gPipeline.mRenderTypeMask = saved_mask;
+	popRenderTypeMask();
 
 	glMatrixMode(GL_PROJECTION);
 	glPopMatrix();
@@ -8871,4 +9360,121 @@ LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
 	return sCull->endAlphaGroups();
 }
 
+BOOL LLPipeline::hasRenderType(const U32 type) const
+{
+	return mRenderTypeEnabled[type];
+}
+
+void LLPipeline::setRenderTypeMask(U32 type, ...)
+{
+	va_list args;
+
+	va_start(args, type);
+	while (type < END_RENDER_TYPES)
+	{
+		mRenderTypeEnabled[type] = TRUE;
+		type = va_arg(args, U32);
+	}
+	va_end(args);
+
+	if (type > END_RENDER_TYPES)
+	{
+		llerrs << "Invalid render type." << llendl;
+	}
+}
+
+BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const
+{
+	va_list args;
+
+	va_start(args, type);
+	while (type < END_RENDER_TYPES)
+	{
+		if (mRenderTypeEnabled[type])
+		{
+			return TRUE;
+		}
+		type = va_arg(args, U32);
+	}
+	va_end(args);
+
+	if (type > END_RENDER_TYPES)
+	{
+		llerrs << "Invalid render type." << llendl;
+	}
+
+	return FALSE;
+}
+
+void LLPipeline::pushRenderTypeMask()
+{
+	std::string cur_mask;
+	cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled));
+	mRenderTypeEnableStack.push(cur_mask);
+}
+
+void LLPipeline::popRenderTypeMask()
+{
+	if (mRenderTypeEnableStack.empty())
+	{
+		llerrs << "Depleted render type stack." << llendl;
+	}
+
+	memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled));
+	mRenderTypeEnableStack.pop();
+}
+
+void LLPipeline::andRenderTypeMask(U32 type, ...)
+{
+	va_list args;
+
+	BOOL tmp[NUM_RENDER_TYPES];
+	for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+	{
+		tmp[i] = FALSE;
+	}
+
+	va_start(args, type);
+	while (type < END_RENDER_TYPES)
+	{
+		if (mRenderTypeEnabled[type]) 
+		{
+			tmp[type] = TRUE;
+		}
+
+		type = va_arg(args, U32);
+	}
+	va_end(args);
+
+	if (type > END_RENDER_TYPES)
+	{
+		llerrs << "Invalid render type." << llendl;
+	}
+
+	for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i)
+	{
+		mRenderTypeEnabled[i] = tmp[i];
+	}
+
+}
+
+void LLPipeline::clearRenderTypeMask(U32 type, ...)
+{
+	va_list args;
+
+	va_start(args, type);
+	while (type < END_RENDER_TYPES)
+	{
+		mRenderTypeEnabled[type] = FALSE;
+		
+		type = va_arg(args, U32);
+	}
+	va_end(args);
+
+	if (type > END_RENDER_TYPES)
+	{
+		llerrs << "Invalid render type." << llendl;
+	}
+}
+
 
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index 89649a0682440914e07b5d3f8cfd7bad1fd9d129..95f951b393e7d1fe21e002052eec4325f7d76200 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -45,6 +45,9 @@
 #include "llgl.h"
 #include "lldrawable.h"
 #include "llrendertarget.h"
+#include "llmodel.h" //for LL_MESH_ENaBLED
+
+#include <stack>
 
 class LLViewerTexture;
 class LLEdge;
@@ -58,6 +61,11 @@ class LLCubeMap;
 class LLCullResult;
 class LLVOAvatar;
 class LLGLSLShader;
+class LLCurlRequest;
+
+#if LL_MESH_ENABLED
+class LLMeshResponder;
+#endif
 
 typedef enum e_avatar_skinning_method
 {
@@ -213,6 +221,7 @@ class LLPipeline
 
 	//calculate pixel area of given box from vantage point of given camera
 	static F32 calcPixelArea(LLVector3 center, LLVector3 size, LLCamera& camera);
+	static F32 calcPixelArea(const LLVector4a& center, const LLVector4a& size, LLCamera &camera);
 
 	void stateSort(LLCamera& camera, LLCullResult& result);
 	void stateSort(LLSpatialGroup* group, LLCamera& camera);
@@ -225,6 +234,14 @@ class LLPipeline
 	void renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture);
 
 	void grabReferences(LLCullResult& result);
+	void clearReferences();
+
+	//check references will assert that there are no references in sCullResult to the provided data
+	void checkReferences(LLFace* face);
+	void checkReferences(LLDrawable* drawable);
+	void checkReferences(LLDrawInfo* draw_info);
+	void checkReferences(LLSpatialGroup* group);
+
 
 	void renderGeom(LLCamera& camera, BOOL forceVBOUpdate = FALSE);
 	void renderGeomDeferred(LLCamera& camera);
@@ -277,12 +294,25 @@ class LLPipeline
 	LLCullResult::sg_list_t::iterator beginAlphaGroups();
 	LLCullResult::sg_list_t::iterator endAlphaGroups();
 	
+
 	void addTrianglesDrawn(S32 index_count, U32 render_type = LLRender::TRIANGLES);
-	BOOL hasRenderType(const U32 type) const				{ return (type && (mRenderTypeMask & (1<<type))) ? TRUE : FALSE; }
+
 	BOOL hasRenderDebugFeatureMask(const U32 mask) const	{ return (mRenderDebugFeatureMask & mask) ? TRUE : FALSE; }
 	BOOL hasRenderDebugMask(const U32 mask) const			{ return (mRenderDebugMask & mask) ? TRUE : FALSE; }
-	void setRenderTypeMask(const U32 mask)					{ mRenderTypeMask = mask; }
-	U32  getRenderTypeMask() const							{ return mRenderTypeMask; }
+	
+
+
+	BOOL hasRenderType(const U32 type) const;
+	BOOL hasAnyRenderType(const U32 type, ...) const;
+
+	void setRenderTypeMask(U32 type, ...);
+	void orRenderTypeMask(U32 type, ...);
+	void andRenderTypeMask(U32 type, ...);
+	void clearRenderTypeMask(U32 type, ...);
+	
+	void pushRenderTypeMask();
+	void popRenderTypeMask();
+
 	static void toggleRenderType(U32 type);
 
 	// For UI control of render features
@@ -360,6 +390,7 @@ class LLPipeline
 		RENDER_TYPE_PASS_FULLBRIGHT_SHINY		= LLRenderPass::PASS_FULLBRIGHT_SHINY,
 		RENDER_TYPE_PASS_SHINY					= LLRenderPass::PASS_SHINY,
 		RENDER_TYPE_PASS_BUMP					= LLRenderPass::PASS_BUMP,
+		RENDER_TYPE_PASS_POST_BUMP				= LLRenderPass::PASS_POST_BUMP,
 		RENDER_TYPE_PASS_GLOW					= LLRenderPass::PASS_GLOW,
 		RENDER_TYPE_PASS_ALPHA					= LLRenderPass::PASS_ALPHA,
 		RENDER_TYPE_PASS_ALPHA_MASK				= LLRenderPass::PASS_ALPHA_MASK,
@@ -370,7 +401,9 @@ class LLPipeline
 		RENDER_TYPE_VOLUME,
 		RENDER_TYPE_PARTICLES,
 		RENDER_TYPE_CLOUDS,
-		RENDER_TYPE_HUD_PARTICLES
+		RENDER_TYPE_HUD_PARTICLES,
+		NUM_RENDER_TYPES,
+		END_RENDER_TYPES = NUM_RENDER_TYPES
 	};
 
 	enum LLRenderDebugFeatureMask
@@ -411,6 +444,7 @@ class LLPipeline
 		RENDER_DEBUG_AVATAR_VOLUME      = 0x0100000,
 		RENDER_DEBUG_BUILD_QUEUE		= 0x0200000,
 		RENDER_DEBUG_AGENT_TARGET       = 0x0400000,
+		RENDER_DEBUG_NORMALS	        = 0x0800000,
 	};
 
 public:
@@ -433,6 +467,12 @@ class LLPipeline
 	S32						 mNumVisibleNodes;
 	S32						 mVerticesRelit;
 
+	S32						 mDebugTextureUploadCost;
+	S32						 mDebugSculptUploadCost;
+#if LL_MESH_ENABLED
+	S32						 mDebugMeshUploadCost;
+#endif
+
 	S32						 mLightingChanges;
 	S32						 mGeometryChanges;
 
@@ -444,9 +484,12 @@ class LLPipeline
 	static BOOL				sForceOldBakedUpload; // If true will not use capabilities to upload baked textures.
 	static S32				sUseOcclusion;  // 0 = no occlusion, 1 = read only, 2 = read/write
 	static BOOL				sDelayVBUpdate;
-	static BOOL				sFastAlpha;
+	static BOOL				sAutoMaskAlphaDeferred;
+	static BOOL				sAutoMaskAlphaNonDeferred;
 	static BOOL				sDisableShaders; // if TRUE, rendering will be done without shaders
 	static BOOL				sRenderBump;
+	static BOOL				sBakeSunlight;
+	static BOOL				sNoAlpha;
 	static BOOL				sUseTriStrips;
 	static BOOL				sUseFarClip;
 	static BOOL				sShadowRender;
@@ -533,7 +576,9 @@ class LLPipeline
 	S32						mVertexShadersLoaded; // 0 = no, 1 = yes, -1 = failed
 
 protected:
-	U32						mRenderTypeMask;
+	BOOL					mRenderTypeEnabled[NUM_RENDER_TYPES];
+	std::stack<std::string> mRenderTypeEnableStack;
+
 	U32						mRenderDebugFeatureMask;
 	U32						mRenderDebugMask;
 
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index c02bf5741efa4bebe827d45c6acd72c9e2147867..ae7f149d69605608b806012924e640b127c15abf 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -208,6 +208,7 @@ with the same filename but different name
   <texture name="Inv_LostClosed" file_name="icons/Inv_LostClosed.png" preload="false" />
   <texture name="Inv_LostOpen" file_name="icons/Inv_LostOpen.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" />
@@ -603,6 +604,8 @@ with the same filename but different name
   <texture name="icon_for_sale.tga" file_name="icons/Icon_For_Sale.png" />
   <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 b5be03346e2b46ea91d8fe95f8f2610c322d3b98..294a68255d845e866c0bcb877eabb19b53c730ce 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -139,17 +139,20 @@ Thank you to the following Residents for helping to ensure that this is the best
        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 efc1a66d95b0d4bed745c279ef7e06c822f6c7ac..b83ac3282b6d5332594ebac3e20bafa883237810 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -1432,6 +1432,39 @@ even though the user gets a free copy.
              text_enabled_color="1 1 1 1"
              top_pad="3"
              width="87" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left_delta="0"
+             name="label physicsshapetype"
+             top_pad="10"
+             width="121">
+                Physics Shape Type:
+            </text>
+			<combo_box
+			   height="23"
+			   layout="topleft"
+			   follows="left|top"
+			   name="Physics Shape Type Combo Ctrl"
+			   tool_tip="Choose the physics shape type"
+			   left_pad="0"
+			   width="108">
+			  <combo_box.item
+				 label="Prim"
+				 name="Prim"
+				 value="Prim" />
+			  <combo_box.item
+				 label="None"
+				 name="None"
+				 value="None" />
+			  <combo_box.item
+				 label="Convex Hull"
+				 name="Convex Hull"
+				 value="Convex Hull" />
+			</combo_box>
 
  <!--           <text
              type="string"
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..936ef4e5394c4f5b450c6635117539248db7126b 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,18 @@
                      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.on_visible
+                function="File.MeshEnabled"/>
                 </menu_item_call>
                 <menu_item_call
                  label="Bulk (L$[COST] per file)..."
@@ -226,4 +238,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 2641ce4ee4de2ca1074a441c9ef7e657bee3d847..d512293305f8b058b89bd17ea96fa828c606b7d2 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -1823,6 +1823,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"
              name="Show Render Info">
@@ -1981,6 +1992,16 @@
          function="Advanced.ToggleInfoDisplay"
          parameter="bboxes" />
         </menu_item_check>
+        <menu_item_check
+         label="Normals"
+         name="Normals">
+          <menu_item_check.on_check
+           function="Advanced.CheckInfoDisplay"
+           parameter="normals" />
+          <menu_item_check.on_click
+           function="Advanced.ToggleInfoDisplay"
+           parameter="normals" />
+        </menu_item_check>
         <menu_item_check
          label="Octree"
          name="Octree">
@@ -2205,14 +2226,24 @@
                  parameter="RenderDebugPipeline" />
             </menu_item_check>
             <menu_item_check
-             label="Fast Alpha"
-             name="Fast Alpha">
+             label="Automatic Alpha Masks (deferred)"
+             name="Automatic Alpha Masks (deferred)">
                 <menu_item_check.on_check
                  function="CheckControl"
-                 parameter="RenderFastAlpha" />
+                 parameter="RenderAutoMaskAlphaDeferred" />
                 <menu_item_check.on_click
                  function="ToggleControl"
-                 parameter="RenderFastAlpha" />
+                 parameter="RenderAutoMaskAlphaDeferred" />
+            </menu_item_check>
+            <menu_item_check
+             label="Automatic Alpha Masks (non-deferred)"
+             name="Automatic Alpha Masks (non-deferred)">
+                <menu_item_check.on_check
+                 function="CheckControl"
+                 parameter="RenderAutoMaskAlphaNonDeferred" />
+                <menu_item_check.on_click
+                 function="ToggleControl"
+                 parameter="RenderAutoMaskAlphaNonDeferred" />
             </menu_item_check>
             <menu_item_check
              label="Animation Textures"
@@ -2938,6 +2969,16 @@
          shortcut="control|alt|shift|G">
             <menu_item_call.on_click
              function="Advanced.LeaveAdminStatus" />
+        </menu_item_call>
+		<menu_item_call
+           label="HACK Upload 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>
     <menu
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index aca3b750c8dfa44b4e3cef13826a54e1bbae4414..39457b7e190ba4833ebdcc70616d2242f82acceb 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6154,7 +6154,7 @@ Attachment has been saved.
 Unable to find the help topic for this element.
   </notification>
 
-    <notification
+     <notification
  icon="alertmodal.tga"
  name="ObjectMediaFailure"
  type="alertmodal">
@@ -6184,6 +6184,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"
@@ -6210,6 +6221,14 @@ The button will be shown when there is enough space for it.
    type="notifytip">
 Select residents to share with.
   </notification>
+
+  <notification
+    name="MeshUploadError"
+    icon="alert.tga"
+    type="alert">
+    [LABEL] failed to upload: [MESSAGE] [IDENTIFIER] [INVALIDITY_IDENTIFIER]
+  </notification>
+   
   <notification
    icon="notifytip.tga"
    name="ShareItemsConfirmation"
@@ -6384,7 +6403,6 @@ Mute everyone?
      notext="Cancel"/>
     <unique/>
   </notification>
-
   <global name="UnsupportedCPU">
 - Your CPU speed does not meet the minimum requirements.
   </global>
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 266fd6cb5e7e49393bbe871e9a19c9d2e4969acc..b54bad98d074201501c86b0044bf2274ce13247e 100644
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -155,7 +155,7 @@
 	 visiblity_control="ShowAdvancedGraphicsSettings"
      border="false"
 	 follows="top|left"
-     height="260"
+     height="283"
      label="CustomGraphics"
      layout="topleft"
      left="5"
@@ -211,119 +211,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="158">
-			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"
@@ -627,49 +619,58 @@
         width="128">
            Low
         </text>
+      <text
+      type="string"
+      length="1"
+      follows="left|top"
+      height="12"
+      layout="topleft"
+      left="200"
+      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"
         follows="left|top"
         height="12"
         layout="topleft"
-        left="200"
-        name="LightingDetailText"
-        top_pad="18"
-        width="140">
-           Lighting detail:
-        </text>
-        <radio_group
-        control_name="RenderLightingDetail"
-        draw_border="false"
-        height="38"
-        layout="topleft"
-        name="LightingDetailRadio"
-        top_pad="5"
-        width="200">
-           <radio_item
-            height="16"
-            label="Sun and moon only"
-            layout="topleft"
-            name="SunMoon"
-            value="0"
-            top="3"
-            width="156" />
-           <radio_item
-            height="16"
-            label="Nearby local lights"
-            layout="topleft"
-            name="LocalLights"
-            value="1"
-            top_delta="16"
-            width="156" />
-        </radio_group>
-        <text
-        type="string"
-        length="1"
-        follows="left|top"
-        height="12"
-        layout="topleft"
+        left="358"
         left_pad="-30"
         name="TerrainDetailText"
         top="226"
@@ -699,7 +700,7 @@
             name="2"
             top_delta="16"
             width="50" />
-        </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 294267d43b2864ce6b43d400e7e1f14c32e031f7..d270e14914ac7809680f458b2cdbe85d8a34e33b 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -1941,6 +1941,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 8d2525dd2643de6d14293e01f63bf941c318644a..06050db6275fa05231d58b93f6442fe6e3c6881b 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -270,12 +270,21 @@ 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
+            try:
+                self.path("libcollada14dom21.dll")
+                self.path("glod.dll")
+            except RuntimeError, err:
+                print err.message
+                print "Skipping COLLADA and GLOD libraries (assumming linked statically)"
+
             # For textures
             if self.args['configuration'].lower() == 'debug':
                 self.path("openjpegd.dll")
@@ -321,9 +330,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 1f3e74a27ab62fb259aaa6e15ecc42710abdfc6a..ae3f930a1d6669bd5cfe4910b90382259799d1d2 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>
@@ -1252,6 +1318,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>
@@ -1532,6 +1624,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>
@@ -1857,6 +2018,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>
diff --git a/scripts/messages/message_template.msg b/scripts/messages/message_template.msg
index d4f791c202b655e53139c80a6c3689dd1e914d43..6043542877aea5b4a150df4680b71170e00f23a6 100644
--- a/scripts/messages/message_template.msg
+++ b/scripts/messages/message_template.msg
@@ -2061,6 +2061,10 @@ version 2.0
 		{	IsPhantom		BOOL	}
 		{	CastsShadows	BOOL	}
 	}
+    {
+		ExtraPhysics        Variable
+		{   PhysicsShapeType U8     }
+	}
 }