diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index 173e650961d179e6066d346e1bfe07da6df08a37..3bd10ea9ee91f475153244af235a4b149b5b70c7 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -49,11 +49,12 @@ if (WINDOWS)
 
   add_definitions(
       /DLL_WINDOWS=1
+      /DDOM_DYNAMIC
       /DUNICODE
       /D_UNICODE 
       /GS
       /TP
-      /W3
+      /W2
       /c
       /Zc:forScope
       /nologo
@@ -195,7 +196,7 @@ endif (DARWIN)
 
 
 if (LINUX OR DARWIN)
-  set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor -Woverloaded-virtual")
+  set(GCC_WARNINGS "-Wall -Wno-sign-compare -Wno-trigraphs -Wno-non-virtual-dtor")
 
   if (NOT GCC_DISABLE_FATAL_WARNINGS)
     set(GCC_WARNINGS "${GCC_WARNINGS} -Werror")
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/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp
index 0b016b81fbee089a205cefb7cadc4cb86e8c09f2..d57494b444ce1a60a9fe404df5176f662ceeb5e5 100644
--- a/indra/llcommon/llassettype.cpp
+++ b/indra/llcommon/llassettype.cpp
@@ -107,6 +107,7 @@ LLAssetDictionary::LLAssetDictionary()
 
 	addEntry(LLAssetType::AT_LINK, 				new AssetEntry("LINK",				"link",		"symbolic link",	"Link", 			DAD_LINK,		FALSE,		TRUE));
 	addEntry(LLAssetType::AT_LINK_FOLDER, 		new AssetEntry("FOLDER_LINK",		"link_f", 	"symbolic folder link", "New Folder", 	DAD_LINK,		FALSE,		TRUE));
+	addEntry(LLAssetType::AT_MESH,              new AssetEntry("MESH",              "mesh",     "mesh",             "Meshes",           DAD_MESH,       FALSE,		TRUE));
 
 	for (S32 ensemble_num = S32(LLAssetType::AT_FOLDER_ENSEMBLE_START); 
 		 ensemble_num <= S32(LLAssetType::AT_FOLDER_ENSEMBLE_END); 
diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h
index 5e5118854161f3348244f712e0a81cae2f8fb1ba..a1154d16e3fb34436389f6c7133d794cf5886dbe 100644
--- a/indra/llcommon/llassettype.h
+++ b/indra/llcommon/llassettype.h
@@ -147,9 +147,11 @@ class LLAssetType
 
 		AT_MY_OUTFITS = 48,
 			// Folder that holds your outfits.
+			
+		AT_MESH = 49,
+		    // Mesh data in our proprietary SLM format
 
-		
-		AT_COUNT = 49,
+		AT_COUNT = 50,
 			// +*********************************************************+
 			// |  TO ADD AN ELEMENT TO THIS ENUM:                        |
 			// +*********************************************************+
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 920d8c09777d0b0c148150e01216b5db443b7a41..e3906bc86e39992ae17f02eb9411279b00f14b98 100644
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -75,7 +75,7 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
 	// 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;
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/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp
index a445466b26aea80e3ced71b4eb9fe221008ba4b0..ae3cb2697b73cb931d4776136a50a98f677dee8f 100644
--- a/indra/llinventory/llinventorytype.cpp
+++ b/indra/llinventory/llinventorytype.cpp
@@ -96,7 +96,9 @@ LLInventoryDictionary::LLInventoryDictionary()
 	addEntry(LLInventoryType::IT_WEARABLE,            new InventoryEntry("wearable",  "wearable",      2, LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART));
 	addEntry(LLInventoryType::IT_ANIMATION,           new InventoryEntry("animation", "animation",     1, LLAssetType::AT_ANIMATION));  
 	addEntry(LLInventoryType::IT_GESTURE,             new InventoryEntry("gesture",   "gesture",       1, LLAssetType::AT_GESTURE)); 
-	addEntry(LLInventoryType::IT_FAVORITE,            new InventoryEntry("favorite",  "favorite",      1, LLAssetType::AT_FAVORITE)); 
+	addEntry(LLInventoryType::IT_FAVORITE,            new InventoryEntry("favorite",  "favorite",      1, LLAssetType::AT_FAVORITE));
+	addEntry(LLInventoryType::IT_MESH,                new InventoryEntry("mesh",      "mesh",          1, LLAssetType::AT_MESH));
+
 }
 
 
@@ -132,7 +134,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
 
 	LLInventoryType::IT_NONE,			// AT_LINK
 	LLInventoryType::IT_NONE,			// AT_LINK_FOLDER
-
+	
 	LLInventoryType::IT_CATEGORY,		// AT_ENSEMBLE
 	LLInventoryType::IT_CATEGORY,		// AT_ENSEMBLE
 	LLInventoryType::IT_CATEGORY,		// AT_ENSEMBLE
@@ -157,6 +159,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
 	LLInventoryType::IT_CATEGORY,		// AT_CURRENT_OUTFIT
 	LLInventoryType::IT_CATEGORY,		// AT_OUTFIT
 	LLInventoryType::IT_CATEGORY,		// AT_MY_OUTFITS
+	LLInventoryType::IT_MESH,           // AT_MESH
 };
 
 // static
diff --git a/indra/llinventory/llinventorytype.h b/indra/llinventory/llinventorytype.h
index 14b28bfe4b8ea583bd70531821fc03440f366904..0d580d300054742211977449a4ecf98002139cb6 100644
--- a/indra/llinventory/llinventorytype.h
+++ b/indra/llinventory/llinventorytype.h
@@ -68,7 +68,8 @@ class LLInventoryType
 		IT_ANIMATION = 19,
 		IT_GESTURE = 20,
 		IT_FAVORITE = 21,
-		IT_COUNT = 22,
+		IT_MESH = 22,
+		IT_COUNT = 23,
 
 		IT_NONE = -1
 	};
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index b8ef92f9a989df96f04c4e1a088ac63f5db62d59..afa82ed39959e388e88965d53f8512bc4dd9a6f2 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -46,6 +46,9 @@
 #include "lldarray.h"
 #include "llvolume.h"
 #include "llstl.h"
+#include "llsdserialize.h"
+#include "zlib/zlib.h"
+
 
 #define DEBUG_SILHOUETTE_BINORMALS 0
 #define DEBUG_SILHOUETTE_NORMALS 0 // TomY: Use this to display normals using the silhouette
@@ -1688,7 +1691,7 @@ LLVolume::LLVolume(const LLVolumeParams &params, const F32 detail, const BOOL ge
 	mGenerateSingleFace = generate_single_face;
 
 	generate();
-	if (mParams.getSculptID().isNull())
+	if (mParams.getSculptID().isNull() && params.getSculptType() == LL_SCULPT_TYPE_NONE)
 	{
 		createVolumeFaces();
 	}
@@ -1839,6 +1842,295 @@ BOOL LLVolume::generate()
 	return FALSE;
 }
 
+bool LLVolumeFace::VertexData::operator<(const LLVolumeFace::VertexData& rhs)const
+{
+	const U8* l = (const U8*) this;
+	const U8* r = (const U8*) &rhs;
+
+	for (U32 i = 0; i < sizeof(VertexData); ++i)
+	{
+		if (l[i] != r[i])
+		{
+			return r[i] < l[i];
+		}
+	}
+	
+	return false;
+}
+
+bool LLVolumeFace::VertexData::operator==(const LLVolumeFace::VertexData& rhs)const
+{
+	const U8* l = (const U8*) this;
+	const U8* r = (const U8*) &rhs;
+
+	for (U32 i = 0; i < sizeof(VertexData); ++i)
+	{
+		if (l[i] != r[i])
+		{
+			return false;
+		}
+	}
+	
+	return true;
+}
+
+
+BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name)
+{
+	std::ifstream is;
+	
+	is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary);
+
+	BOOL success = createVolumeFacesFromStream(is);
+	
+	is.close();
+
+	return success;
+}
+
+BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
+{
+	mSculptLevel = -1;  // default is an error occured
+	
+	LLSD header;
+	{
+		if (!LLSDSerialize::deserialize(header, is, 1024*1024*1024))
+		{
+			llwarns << "not a valid mesh asset!" << llendl;
+			return FALSE;
+		}
+	}
+	
+	std::string nm[] = 
+	{
+		"impostor",
+		"low_lod",
+		"medium_lod",
+		"high_lod"
+	};
+
+	S32 lod = llclamp((S32) mDetail, 0, 3);
+
+	while (lod < 4 && header[nm[lod]]["offset"].asInteger() == -1)
+	{
+		++lod;
+	}
+
+	if (lod >= 4)
+	{
+		llwarns << "Couldn't load model for given lod" << llendl;
+		return FALSE;
+	}
+
+	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+	
+
+	U8* result = NULL;
+	U32 cur_size = 0;
+
+	{
+		//input stream is now pointing at a zlib compressed block of LLSD
+		//decompress block
+		z_stream strm;
+		
+		const U32 CHUNK = 65536;
+
+		S32 size = header[nm[lod]]["size"].asInteger();
+		U8 *in = new U8[size];
+		is.read((char*) in, size); 
+
+		U8 out[CHUNK];
+			
+		strm.zalloc = Z_NULL;
+		strm.zfree = Z_NULL;
+		strm.opaque = Z_NULL;
+		strm.avail_in = size;
+		strm.next_in = in;
+
+		S32 ret = inflateInit(&strm);
+
+		if (ret != Z_OK)
+		{
+			llerrs << "WTF?" << llendl;
+		}
+		
+		do
+		{
+			strm.avail_out = CHUNK;
+			strm.next_out = out;
+			ret = inflate(&strm, Z_NO_FLUSH);
+			if (ret == Z_STREAM_ERROR)
+			{
+				inflateEnd(&strm);
+				free(result);
+				delete [] in;
+				return FALSE;
+			}
+			
+			switch (ret)
+			{
+			case Z_NEED_DICT:
+				ret = Z_DATA_ERROR;
+			case Z_DATA_ERROR:
+			case Z_MEM_ERROR:
+				inflateEnd(&strm);
+				free(result);
+				delete [] in;
+				return FALSE;
+				break;
+			}
+
+			U32 have = CHUNK-strm.avail_out;
+
+			result = (U8*) realloc(result, cur_size + have);
+			memcpy(result+cur_size, out, have);
+			cur_size += have;
+
+		} while (strm.avail_out == 0);
+
+		inflateEnd(&strm);
+		delete [] in;
+
+		if (ret != Z_STREAM_END)
+		{
+			free(result);
+			return FALSE;
+		}
+	}
+
+	//result now points to the decompressed LLSD block
+
+	LLSD mdl;
+
+	{
+		std::string res_str((char*) result, cur_size);
+		std::istringstream istr(res_str);
+
+		if (!LLSDSerialize::deserialize(mdl, istr, cur_size))
+		{
+			llwarns << "not a valid mesh asset!" << llendl;
+			return FALSE;
+		}
+	}
+
+
+	free(result);
+
+
+	{
+		U32 face_count = mdl.size();
+
+		mVolumeFaces.resize(face_count);
+
+		for (U32 i = 0; i < face_count; ++i)
+		{
+			LLSD::Binary pos = mdl[i]["Position"];
+			LLSD::Binary norm = mdl[i]["Normal"];
+			LLSD::Binary tc = mdl[i]["TexCoord0"];
+			LLSD::Binary idx = mdl[i]["TriangleList"];
+
+			LLVolumeFace& face = mVolumeFaces[i];
+
+			face.mHasBinormals = FALSE;
+
+			//copy out indices
+			face.mIndices.resize(idx.size()/2);
+			if (idx.empty())
+			{ //why is there an empty index list?
+				continue;
+			}
+
+			U16* indices = (U16*) &(idx[0]);
+			for (U32 j = 0; j < idx.size()/2; ++j)
+			{
+				face.mIndices[j] = indices[j];
+			}
+
+			//copy out vertices
+			U32 num_verts = pos.size()/(3*2);
+			face.mVertices.resize(num_verts);
+
+			LLVector3 min_pos;
+			LLVector3 max_pos;
+			LLVector2 min_tc; 
+			LLVector2 max_tc; 
+
+			min_pos.setValue(mdl[i]["PositionDomain"]["Min"]);
+			max_pos.setValue(mdl[i]["PositionDomain"]["Max"]);
+			min_tc.setValue(mdl[i]["TexCoord0Domain"]["Min"]);
+			max_tc.setValue(mdl[i]["TexCoord0Domain"]["Max"]);
+
+			F32 scale = llclamp((F32) mdl[i]["Scale"].asReal(), 1.f, 10.f);
+
+			LLVector3 pos_range = max_pos - min_pos;
+			LLVector2 tc_range = max_tc - min_tc;
+
+			LLVector3& min = face.mExtents[0];
+			LLVector3& max = face.mExtents[1];
+
+			min = max = LLVector3(0,0,0);
+
+			for (U32 j = 0; j < num_verts; ++j)
+			{
+				U16* v = (U16*) &(pos[j*3*2]);
+
+				face.mVertices[j].mPosition.setVec(
+					(F32) v[0] / 65535.f * pos_range.mV[0] + min_pos.mV[0],
+					(F32) v[1] / 65535.f * pos_range.mV[1] + min_pos.mV[1],
+					(F32) v[2] / 65535.f * pos_range.mV[2] + min_pos.mV[2]);
+
+				face.mVertices[j].mPosition *= scale;
+
+				if (j == 0)
+				{
+					min = max = face.mVertices[j].mPosition;
+				}
+				else
+				{
+					update_min_max(min,max,face.mVertices[j].mPosition);
+				}
+
+				U16* n = (U16*) &(norm[j*3*2]);
+
+				face.mVertices[j].mNormal.setVec(
+					(F32) n[0] / 65535.f * 2.f - 1.f,
+					(F32) n[1] / 65535.f * 2.f - 1.f,
+					(F32) n[2] / 65535.f * 2.f - 1.f);
+
+				U16* t = (U16*) &(tc[j*2*2]);
+
+				face.mVertices[j].mTexCoord.setVec(
+					(F32) t[0] / 65535.f * tc_range.mV[0] + min_tc.mV[0],
+					(F32) t[1] / 65535.f * tc_range.mV[1] + min_tc.mV[1]);
+			}
+
+		}
+	}
+
+	mSculptLevel = 0;  // success!
+	return TRUE;
+}
+
+void LLVolume::copyVolumeFaces(LLVolume* volume)
+{
+	mVolumeFaces = volume->mVolumeFaces;
+	mSculptLevel = 0;
+}
+
+S32 const LL_SCULPT_MESH_MAX_FACES = 8;
+
+S32	LLVolume::getNumFaces() const
+{
+	U8 sculpt_type = (mParams.getSculptType() & LL_SCULPT_TYPE_MASK);
+
+	if (sculpt_type == LL_SCULPT_TYPE_MESH)
+	{
+		return LL_SCULPT_MESH_MAX_FACES;
+	}
+
+	return (S32)mProfilep->mFaces.size();
+}
+
 
 void LLVolume::createVolumeFaces()
 {
@@ -1864,6 +2156,11 @@ void LLVolume::createVolumeFaces()
 			LLProfile::Face& face = mProfilep->mFaces[i];
 			vf.mBeginS = face.mIndex;
 			vf.mNumS = face.mCount;
+			if (vf.mNumS < 0)
+			{
+				llerrs << "Volume face corruption detected." << llendl;
+			}
+
 			vf.mBeginT = 0;
 			vf.mNumT= getPath().mPath.size();
 			vf.mID = i;
@@ -1907,6 +2204,10 @@ void LLVolume::createVolumeFaces()
 					if (face.mFlat && vf.mNumS > 2)
 					{ //flat inner faces have to copy vert normals
 						vf.mNumS = vf.mNumS*2;
+						if (vf.mNumS < 0)
+						{
+							llerrs << "Volume face corruption detected." << llendl;
+						}
 					}
 				}
 				else
@@ -2309,7 +2610,6 @@ bool LLVolumeParams::operator<(const LLVolumeParams &params) const
 		return mSculptID < params.mSculptID;
 	}
 
-
 	return mSculptType < params.mSculptType;
 
 
@@ -3379,22 +3679,29 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 										  S32 face_mask)
 {
 	LLMemType m1(LLMemType::MTYPE_VOLUME);
-	
+
 	vertices.clear();
 	normals.clear();
 	segments.clear();
 
+	if (mParams.getSculptType() == LL_SCULPT_TYPE_MESH)
+	{
+		return;
+	}
+	
 	S32 cur_index = 0;
 	//for each face
 	for (face_list_t::iterator iter = mVolumeFaces.begin();
 		 iter != mVolumeFaces.end(); ++iter)
 	{
-		const LLVolumeFace& face = *iter;
+		LLVolumeFace& face = *iter;
 	
-		if (!(face_mask & (0x1 << cur_index++)))
+		if (!(face_mask & (0x1 << cur_index++)) ||
+		     face.mIndices.empty() || face.mEdge.empty())
 		{
 			continue;
 		}
+
 		if (face.mTypeMask & (LLVolumeFace::CAP_MASK)) {
 	
 		}
@@ -3594,6 +3901,8 @@ S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
 
 	F32 closest_t = 2.f; // must be larger than 1
 	
+	end_face = llmin(end_face, getNumVolumeFaces()-1);
+
 	for (S32 i = start_face; i <= end_face; i++)
 	{
 		const LLVolumeFace &face = getVolumeFace((U32)i);
@@ -4103,11 +4412,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;
 }
 
@@ -4115,6 +4441,8 @@ bool LLVolumeParams::fromLLSD(LLSD& sd)
 {
 	mPathParams.fromLLSD(sd["path"]);
 	mProfileParams.fromLLSD(sd["profile"]);
+	sculptFromLLSD(sd["sculpt"]);
+		
 	return true;
 }
 
@@ -4157,6 +4485,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();
 	 
@@ -5011,7 +5345,11 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 	if (!partial_build)
 	{
 		mIndices.resize(num_indices);
-		mEdge.resize(num_indices);
+
+		if (volume->getParams().getSculptType() != LL_SCULPT_TYPE_MESH)
+		{
+			mEdge.resize(num_indices);
+		}
 	}
 	else
 	{
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 871b334452180ca76160900b6961b015eb4874dd..9f595ccbc4a75f483604ed25240f3c62024b59f5 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -186,6 +186,9 @@ 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;
 
+// need to change this (these) names
+const U8 LL_SCULPT_TYPE_MESH      = 5;
+
 const U8 LL_SCULPT_FLAG_INVERT    = 64;
 const U8 LL_SCULPT_FLAG_MIRROR    = 128;
 
@@ -575,6 +578,9 @@ class LLVolumeParams
 	BOOL importLegacyStream(std::istream& input_stream);
 	BOOL exportLegacyStream(std::ostream& output_stream) const;
 
+	LLSD sculptAsLLSD() const;
+	bool sculptFromLLSD(LLSD& sd);
+	
 	LLSD asLLSD() const;
 	operator LLSD() const { return asLLSD(); }
 	bool fromLLSD(LLSD& sd);
@@ -634,7 +640,6 @@ class LLVolumeParams
 	const F32&  getSkew() const			{ return mPathParams.getSkew();			}
 	const LLUUID& getSculptID() const	{ return mSculptID;						}
 	const U8& getSculptType() const     { return mSculptType;                   }
-
 	BOOL isConvex() const;
 
 	// 'begin' and 'end' should be in range [0, 1] (they will be clamped)
@@ -798,7 +803,7 @@ class LLVolumeFace
 
 	BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
 	void createBinormals();
-
+	
 	class VertexData
 	{
 	public:
@@ -806,6 +811,9 @@ class LLVolumeFace
 		LLVector3 mNormal;
 		LLVector3 mBinormal;
 		LLVector2 mTexCoord;
+
+		bool operator<(const VertexData& rhs) const;
+		bool operator==(const VertexData& rhs) const;
 	};
 
 	enum
@@ -851,8 +859,7 @@ class LLVolume : public LLRefCount
 {
 	friend class LLVolumeLODGroup;
 
-private:
-	LLVolume(const LLVolume&);  // Don't implement
+protected:
 	~LLVolume(); // use unref
 
 public:
@@ -874,7 +881,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; }
@@ -946,6 +953,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();
@@ -956,6 +965,9 @@ class LLVolume : public LLRefCount
 protected:
 	BOOL generate();
 	void createVolumeFaces();
+public:
+	virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
+	virtual BOOL createVolumeFacesFromStream(std::istream& is);
 
  protected:
 	BOOL mUnique;
diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index 53641fceab1eec1076bb411787b9d8d47c5a0321..61c5a0adc90bd187030ffc7f03c4eb863bbf1aee 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;
diff --git a/indra/llmath/m4math.cpp b/indra/llmath/m4math.cpp
index d8e7b4aaf9c4f917bf6213c8c3b142a7e060cc59..7c7f60154dad028db27298acd917f39e626fe662 100644
--- a/indra/llmath/m4math.cpp
+++ b/indra/llmath/m4math.cpp
@@ -428,6 +428,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;
diff --git a/indra/llmath/m4math.h b/indra/llmath/m4math.h
index e74b7afe9bd9bf99befc4992c58b0440bf198123..de981b764668d638daf64a7720b73f091c538eb0 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);	
diff --git a/indra/llmath/v2math.cpp b/indra/llmath/v2math.cpp
index 555e1f92bbb7a1a31e910c501ab0e5e64e233046..220336e0c2a5f82d8d5a3146db6fd6be381c1a4a 100644
--- a/indra/llmath/v2math.cpp
+++ b/indra/llmath/v2math.cpp
@@ -115,3 +115,18 @@ LLVector2 lerp(const LLVector2 &a, const LLVector2 &b, F32 u)
 		a.mV[VX] + (b.mV[VX] - a.mV[VX]) * u,
 		a.mV[VY] + (b.mV[VY] - a.mV[VY]) * u );
 }
+
+LLSD LLVector2::getValue() const
+{
+	LLSD ret;
+	ret[0] = mV[0];
+	ret[1] = mV[1];
+	return ret;
+}
+
+void LLVector2::setValue(LLSD& sd)
+{
+	mV[0] = (F32) sd[0].asReal();
+	mV[1] = (F32) sd[1].asReal();
+}
+
diff --git a/indra/llmath/v2math.h b/indra/llmath/v2math.h
index 9fef8851cc6bd3ab952d64c6422e0c939c65730d..f9f1c024f2a9ab162cd74a7d65d68344e15b1e55 100644
--- a/indra/llmath/v2math.h
+++ b/indra/llmath/v2math.h
@@ -66,6 +66,9 @@ class LLVector2
 		void	set(const LLVector2 &vec);	// Sets LLVector2 to vec
 		void	set(const F32 *vec);			// Sets LLVector2 to vec
 
+		LLSD	getValue() const;
+		void	setValue(LLSD& sd);
+
 		void	setVec(F32 x, F32 y);	        // deprecated
 		void	setVec(const LLVector2 &vec);	// deprecated
 		void	setVec(const F32 *vec);			// deprecated
diff --git a/indra/llmessage/llassetstorage.cpp b/indra/llmessage/llassetstorage.cpp
index b3087bcc3f80883972c895bc542ac8512d94519e..eeb903de6aec79d302ae93d0a9b0356dc8424bb8 100644
--- a/indra/llmessage/llassetstorage.cpp
+++ b/indra/llmessage/llassetstorage.cpp
@@ -502,7 +502,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/lltransfermanager.cpp b/indra/llmessage/lltransfermanager.cpp
index d67911e8e2a3c414b010c687695e77f2b9074703..72662bb782e5e57a6d8b5f055daa724e4429c6f4 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 5a1cd95ffcd54183a95618dbd321b145d6e96952..f255a2cf7ec8b4d052f0cb57983476bf77b1858b 100644
--- a/indra/llmessage/lltransfersourceasset.cpp
+++ b/indra/llmessage/lltransfersourceasset.cpp
@@ -271,6 +271,7 @@ bool is_asset_fetch_by_id_allowed(LLAssetType::EType type)
 		case LLAssetType::AT_ANIMATION:
 		case LLAssetType::AT_GESTURE:
 		case LLAssetType::AT_FAVORITE:
+		case LLAssetType::AT_MESH:
 			rv = true;
 			break;
 		default:
@@ -296,6 +297,7 @@ bool is_asset_id_knowable(LLAssetType::EType type)
 		case LLAssetType::AT_FAVORITE:
 		case LLAssetType::AT_LINK:
 		case LLAssetType::AT_LINK_FOLDER:
+	    case LLAssetType::AT_MESH:
 			rv = true;
 			break;
 		default:
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index d13051363786911a36c461251f67f0a0360497cf..f9392a2b75f9ec6642f5a1a29dbf2f3593db934c 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
@@ -33,6 +36,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 b102254b62fb81d48a3b25080eef6e09e982571e..2675a27c08eee2c0c6ee0582df853142d4730049 100644
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -744,18 +744,11 @@ BOOL LLPrimitive::setVolume(const LLVolumeParams &volume_params, const S32 detai
 		return TRUE;
 	}
 
-	U32 old_face_mask = mVolumep->mFaceMask;
-
 	// build the new object
 	sVolumeManager->unrefVolume(mVolumep);
 	mVolumep = volumep;
-	
-	U32 new_face_mask = mVolumep->mFaceMask;
-	if (old_face_mask != new_face_mask) 
-	{
-		setNumTEs(mVolumep->getNumFaces());
-	}
-
+	setNumTEs(mVolumep->getNumFaces());
+		
 	return TRUE;
 }
 
@@ -898,7 +891,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)
 	{
@@ -1179,7 +1172,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..4db7aa7261d3bcc1b1f9ad6fe69abb7ea339ad44 100644
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -328,7 +328,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/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp
index 5fdf41188d46faf90bff83d9b85f5e486e81ec4c..e0e282d7afad628a56a98ac4b2a565bce11947ad 100644
--- a/indra/llvfs/llvfile.cpp
+++ b/indra/llvfs/llvfile.cpp
@@ -428,7 +428,7 @@ bool LLVFile::isLocked(EVFSLock lock)
 
 void LLVFile::waitForLock(EVFSLock lock)
 {
-	LLFastTimer t(FTM_VFILE_WAIT);
+	//LLFastTimer t(FTM_VFILE_WAIT);
 	// spin until the lock clears
 	while (isLocked(lock))
 	{
diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp
index 9ce1e75d06f501ade52c7f9a5645afa63c7d0873..ddb76fb2ba159175009420ff17c9a80cb15479a5 100644
--- a/indra/llvfs/llvfs.cpp
+++ b/indra/llvfs/llvfs.cpp
@@ -2041,6 +2041,9 @@ std::string get_extension(LLAssetType::EType type)
 	case LLAssetType::AT_ANIMATION:
 		extension = ".lla";
 		break;
+	case LLAssetType::AT_MESH:
+		extension = ".slm";
+		break;
 	default:
 		// Just use the asset server filename extension in most cases
 		extension += ".";
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 26170d171375176ad12c1b1ca6fd284a29323bed..3cee6394e036dc8ea12d03b9c56f532767e46110 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -36,6 +36,7 @@ include(UI)
 include(UnixInstall)
 include(LLKDU)
 include(ViewerMiscLibs)
+include(GLOD)
 
 if (WINDOWS)
     include(CopyWinLibs)
@@ -44,6 +45,7 @@ endif (WINDOWS)
 include_directories(
     ${DBUSGLIB_INCLUDE_DIRS}
     ${ELFIO_INCLUDE_DIR}
+    ${GLOD_INCLUDE_DIR}
     ${LLAUDIO_INCLUDE_DIRS}
     ${LLCHARACTER_INCLUDE_DIRS}
     ${LLCOMMON_INCLUDE_DIRS}
@@ -61,6 +63,8 @@ include_directories(
     ${LLXUIXML_INCLUDE_DIRS}
     ${LSCRIPT_INCLUDE_DIRS}
     ${LSCRIPT_INCLUDE_DIRS}/lscript_compile
+    ${LIBS_PREBUILT_DIR}/include/collada
+    ${LIBS_PREBUILT_DIR}/include/collada/1.4
     )
 
 set(viewer_SOURCE_FILES
@@ -175,6 +179,7 @@ set(viewer_SOURCE_FILES
     llfloatermediasettings.cpp
     llfloaterhud.cpp
     llfloaterimagepreview.cpp
+    llfloaterimportcollada.cpp
     llfloaterinspect.cpp
     llfloaterinventory.cpp
     llfloaterjoystick.cpp
@@ -183,6 +188,7 @@ set(viewer_SOURCE_FILES
     llfloaterlandholdings.cpp
     llfloatermap.cpp
     llfloatermemleak.cpp
+    llfloatermodelpreview.cpp
     llfloaternamedesc.cpp
     llfloaternotificationsconsole.cpp
     llfloateropenobject.cpp
@@ -647,6 +653,7 @@ set(viewer_HEADER_FILES
     llfloatermediasettings.h
     llfloaterhud.h
     llfloaterimagepreview.h
+    llfloaterimportcollada.h
     llfloaterinspect.h
     llfloaterinventory.h
     llfloaterjoystick.h
@@ -655,6 +662,7 @@ set(viewer_HEADER_FILES
     llfloaterlandholdings.h
     llfloatermap.h
     llfloatermemleak.h
+    llfloatermodelpreview.h
     llfloaternamedesc.h
     llfloaternotificationsconsole.h
     llfloateropenobject.h
@@ -1139,6 +1147,7 @@ if (WINDOWS)
         ${DXGUID_LIBRARY}
         fmodvc
         kernel32
+        libboost_system
         odbc32
         odbccp32
         ole32
@@ -1405,6 +1414,7 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${DBUSGLIB_LIBRARIES}
     ${OPENGL_LIBRARIES}
     ${FMODWRAPPER_LIBRARY}
+    ${GLOD_LIBRARIES}
     ${OPENGL_LIBRARIES}
     ${SDL_LIBRARY}
     ${SMARTHEAP_LIBRARY}
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 7e368b0c9c80308dfcfa1d6ea6b0d79c27963b14..073ea766fe787b5dded722adb63bf7cc979713b8 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -7252,7 +7252,19 @@
       <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>SafeMode</key>
     <map>
       <key>Comment</key>
       <string>Reset preferences, run in safe mode.</string>
diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
index 651959413cd06cad296bf3dfd2a4e3a89babe51e..45884d573240e1b51d1b195739b3aa164ff09f73 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
@@ -137,7 +137,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 = texture2DLod(projectionMap, proj_tc.xy, proj_lod);
 							
 		amb_da += (da*da*0.5+0.5)*proj_ambiance;
 				
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
index a0026edcd2186c76264351f698cad8a60371bf46..4333cc64a7876df1fc2c81dcb919b79c65396c0b 100644
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
@@ -224,11 +224,11 @@ void main()
 	
 	//spotlight shadow 1
 	vec4 lpos = shadow_matrix[4]*spos;
-	gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.1).x; 
+	gl_FragColor[2] = pcfShadow(shadowMap4, lpos, 0.8).x; 
 	
 	//spotlight shadow 2
 	lpos = shadow_matrix[5]*spos;
-	gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.1).x; 
+	gl_FragColor[3] = pcfShadow(shadowMap5, lpos, 0.8).x; 
 
 	//gl_FragColor.rgb = pos.xyz;
 	//gl_FragColor.b = shadow;
diff --git a/indra/newview/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/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp
index cd3963050f68c8ec87c98459debfce897ce14c4b..cb03379b23decb879cb577a1197393bfa91641fa 100644
--- a/indra/newview/llassetuploadresponders.cpp
+++ b/indra/newview/llassetuploadresponders.cpp
@@ -64,6 +64,7 @@
 #include "llfocusmgr.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.
@@ -71,6 +72,120 @@ 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);
+		LLNotifications::instance().add("UploadPayment", args);
+	}
+
+	// Actually add the upload to viewer inventory
+	llinfos << "Adding " << server_response["new_inventory_item"].asUUID()
+			<< " " << server_response["new_asset"].asUUID()
+			<< " to inventory." << llendl;
+
+	if( item_folder_id.notNull() )
+	{
+		U32 everyone_perms = PERM_NONE;
+		U32 group_perms = PERM_NONE;
+		U32 next_owner_perms = PERM_ALL;
+		if( server_response.has("new_next_owner_mask") )
+		{
+			// The server provided creation perms so use them.
+			// Do not assume we got the perms we asked for in
+			// since the server may not have granted them all.
+			everyone_perms = server_response["new_everyone_mask"].asInteger();
+			group_perms = server_response["new_group_mask"].asInteger();
+			next_owner_perms = server_response["new_next_owner_mask"].asInteger();
+		}
+		else 
+		{
+			// The server doesn't provide creation perms
+			// so use old assumption-based perms.
+			if( inventory_type_string != "snapshot")
+			{
+				next_owner_perms = PERM_MOVE | PERM_TRANSFER;
+			}
+		}
+
+		LLPermissions new_perms;
+		new_perms.init(
+			gAgent.getID(),
+			gAgent.getID(),
+			LLUUID::null,
+			LLUUID::null);
+
+		new_perms.initMasks(
+			PERM_ALL,
+			PERM_ALL,
+			everyone_perms,
+			group_perms,
+			next_owner_perms);
+
+		S32 creation_date_now = time_corrected();
+		LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(
+			server_response["new_inventory_item"].asUUID(),
+			item_folder_id,
+			new_perms,
+			server_response["new_asset"].asUUID(),
+			asset_type,
+			inventory_type,
+			item_name,
+			item_description,
+			LLSaleInfo::DEFAULT,
+			LLInventoryItem::II_FLAGS_NONE,
+			creation_date_now);
+
+		gInventory.updateItem(item);
+		gInventory.notifyObservers();
+
+		// Show the preview panel for textures and sounds to let
+		// user know that the image (or snapshot) arrived intact.
+		LLFloaterInventory* view = LLFloaterInventory::getActiveInventory();
+		if ( view )
+		{
+			LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
+
+			view->getPanel()->setSelection(
+				server_response["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) )
+			{
+				view->getPanel()->openSelected();
+			}
+
+			// 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)
@@ -88,9 +203,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),
@@ -196,15 +312,19 @@ void LLAssetUploadResponder::uploadComplete(const LLSD& content)
 {
 }
 
-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 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)
+LLNewAgentInventoryResponder::LLNewAgentInventoryResponder(
+	const LLSD& post_data,
+	const std::string& file_name,
+	LLAssetType::EType asset_type)
+	: LLAssetUploadResponder(post_data, file_name, asset_type)
 {
 }
 
@@ -219,96 +339,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);
-		LLNotifications::instance().add("UploadPayment", args);
+		expected_upload_cost = 
+			LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
 	}
 
-	// Actually add the upload to viewer inventory
-	llinfos << "Adding " << content["new_inventory_item"].asUUID() << " "
-			<< content["new_asset"].asUUID() << " to inventory." << llendl;
-	if(mPostData["folder_id"].asUUID().notNull())
-	{
-		//std::ostringstream out;
-		//LLSDXMLFormatter *formatter = new LLSDXMLFormatter;
-		//formatter->format(mPostData, out, LLSDFormatter::OPTIONS_PRETTY);
-		//llinfos << "Post Data: " << out.str() << llendl;
-
-		U32 everyone_perms = PERM_NONE;
-		U32 group_perms = PERM_NONE;
-		U32 next_owner_perms = PERM_ALL;
-		if(content.has("new_next_owner_mask"))
-		{
-			// This is a new sim that provides creation perms so use them.
-			// Do not assume we got the perms we asked for in mPostData 
-			// since the sim may not have granted them all.
-			everyone_perms = content["new_everyone_mask"].asInteger();
-			group_perms = content["new_group_mask"].asInteger();
-			next_owner_perms = content["new_next_owner_mask"].asInteger();
-		}
-		else 
-		{
-			// This old sim doesn't provide creation perms so use old assumption-based perms.
-			if(mPostData["inventory_type"].asString() != "snapshot")
-			{
-				next_owner_perms = PERM_MOVE | PERM_TRANSFER;
-			}
-		}
-		LLPermissions new_perms;
-		new_perms.init(gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null);
-		new_perms.initMasks(PERM_ALL, PERM_ALL, everyone_perms, group_perms, next_owner_perms);
-		S32 creation_date_now = time_corrected();
-		LLPointer<LLViewerInventoryItem> item
-			= new LLViewerInventoryItem(content["new_inventory_item"].asUUID(),
-										mPostData["folder_id"].asUUID(),
-										new_perms,
-										content["new_asset"].asUUID(),
-										asset_type,
-										inventory_type,
-										mPostData["name"].asString(),
-										mPostData["description"].asString(),
-										LLSaleInfo::DEFAULT,
-										LLInventoryItem::II_FLAGS_NONE,
-										creation_date_now);
-		gInventory.updateItem(item);
-		gInventory.notifyObservers();
-
-		// Show the preview panel for textures and sounds to let
-		// user know that the image (or snapshot) arrived intact.
-		LLFloaterInventory* view = LLFloaterInventory::getActiveInventory();
-		if(view)
-		{
-			LLFocusableElement* focus = gFocusMgr.getKeyboardFocus();
+	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);
 
-			view->getPanel()->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)
-			{
-				view->getPanel()->openSelected();
-			}
-			//LLFloaterInventory::dumpSelectionInformation((void*)view);
-			// restore keyboard focus
-			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.
@@ -325,18 +380,39 @@ 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;
 		LLAssetStorage::LLStoreAssetCallback callback = NULL;
 		void *userdata = NULL;
-		upload_new_resource(next_file, asset_name, asset_name,
-				    0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE,
-				    next_owner_perms, group_perms,
-				    everyone_perms, display_name,
-				    callback, expected_upload_cost, userdata);
+
+		upload_new_resource(
+			next_file,
+			asset_name,
+			asset_name,
+			0,
+			LLAssetType::AT_NONE,
+			LLInventoryType::IT_NONE,
+			next_owner_perms,
+			group_perms,
+			everyone_perms,
+			display_name,
+			callback,
+			LLGlobalEconomy::Singleton::getInstance()->getPriceUpload(),
+			userdata);
 	}
 }
 
@@ -383,17 +459,19 @@ void LLSendTexLayerResponder::uploadComplete(const LLSD& content)
 }
 
 
-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)
 {
 }
 
@@ -576,3 +654,374 @@ void LLUpdateTaskInventoryResponder::uploadComplete(const LLSD& content)
 		break;
 	}
 }
+
+
+/////////////////////////////////////////////////////
+// LLNewAgentInventoryVariablePriceResponder::Impl //
+/////////////////////////////////////////////////////
+class LLNewAgentInventoryVariablePriceResponder::Impl
+{
+public:
+	Impl(
+		const LLUUID& vfile_id,
+		const LLSD& inventory_data) :
+		mVFileID(vfile_id),
+		mInventoryData(inventory_data)
+	{
+	}
+
+	Impl(
+		const std::string& file_name,
+		const LLSD& inventory_data) :
+		mFileName(file_name),
+		mInventoryData(inventory_data)
+	{
+	}
+
+	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 LLAssetType::lookup(
+			mInventoryData["asset_type"].asString());
+	}
+
+	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;
+
+
+		LLNotifications::instance().add("CannotUploadReason", args);
+		LLUploadDialog::modalUploadFinished();
+	}
+
+	void onApplicationLevelError(const std::string& error_identifier)
+	{
+		// TODO*: Pull these user visible strings from an xml file
+		// to be localized
+		static const std::string _INSUFFICIENT_FUNDS =
+			"NewAgentInventory_InsufficientLindenDollarBalance";
+
+
+		if ( _INSUFFICIENT_FUNDS == error_identifier )
+		{
+			displayCannotUploadReason("You do not have a sufficient L$ balance to complete this upload.");
+		}
+		else
+		{
+			displayCannotUploadReason("Unknown Error");
+
+		}
+	}
+
+	void onTransportError()
+	{
+		displayCannotUploadReason(
+				"The server is experiencing unexpected difficulties.");
+	}
+
+	void onTransportError(const std::string& error_identifier)
+	{
+		// TODO*: Pull these user visible strings from an xml file
+		// to be localized
+
+		static const std::string _SERVER_ERROR_AFTER_CHARGE =
+			"NewAgentInventory_ServerErrorAfterCharge";
+
+		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 = LLNotification::getSelectedOption(
+			notification,
+			response);
+
+		confirmation_url =
+			notification["payload"]["confirmation_url"].asString();
+
+		// Yay!  We are confirming or cancelling our upload
+		LLSD body;
+
+		body["confirm_upload"] = false;
+
+		switch(option)
+		{
+		case 0:
+		    {
+				body["confirm_upload"] = true;
+				body["expected_upload_price"] =
+					notification["payload"]["expected_upload_price"];
+			}
+			break;
+		case 1:
+		default:
+			break;
+		}
+
+		LLHTTPClient::post(confirmation_url, body, responder);
+
+		return false;
+	}
+	
+private:
+	std::string mFileName;
+
+	LLSD mInventoryData;
+	LLUUID mVFileID;
+};
+
+///////////////////////////////////////////////
+// LLNewAgentInventoryVariablePriceResponder //
+///////////////////////////////////////////////
+LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
+	const LLUUID& vfile_id,
+	const LLSD& inventory_info)
+{
+	mImpl = new Impl(
+		vfile_id,
+		inventory_info);
+}
+
+LLNewAgentInventoryVariablePriceResponder::LLNewAgentInventoryVariablePriceResponder(
+	const std::string& file_name,
+	const LLSD& inventory_info)
+{
+	mImpl = new Impl(
+		file_name,
+		inventory_info);
+}
+
+LLNewAgentInventoryVariablePriceResponder::~LLNewAgentInventoryVariablePriceResponder()
+{
+	delete mImpl;
+}
+
+void LLNewAgentInventoryVariablePriceResponder::errorWithContent(
+	U32 statusNum,
+	const std::string& reason,
+	const LLSD& content)
+{
+	llinfos << "LLNewAgentInventoryVariablePrice::error " << statusNum 
+			<< " reason: " << reason << llendl;
+
+	if ( content.has("error") )
+	{
+		static const std::string _ERROR = "error";
+		static const std::string _IDENTIFIER = "identifier";
+
+		mImpl->onTransportError(content[_ERROR][_IDENTIFIER].asString());
+	}
+	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 _IDENTIFIER = "identifier";
+	static const std::string _STATE = "state";
+
+	static const std::string _COMPLETE = "complete";
+	static const std::string _COST_ANALYSIS = "cost_analysis";
+	static const std::string _NEEDS_CONFIRMATION = "needs_confirmation";
+	static const std::string _CANCEL = "cancel";
+
+	static const std::string _RESOURCE_COST = "resource_cost";
+	static const std::string _UPLOAD_PRICE = "upload_price";
+
+	static const std::string _ANALYZER = "analyzer";
+	static const std::string _RSVP = "rsvp";
+
+	// Check for application level errors
+	if ( content.has(_ERROR) )
+	{
+		onApplicationLevelError(content[_ERROR][_IDENTIFIER].asString());
+		return;
+	}
+
+	std::string state = content[_STATE];
+	LLAssetType::EType asset_type = mImpl->getAssetType();
+
+	if ( _COST_ANALYSIS == state )
+	{
+		std::string analyzer_url = content[_ANALYZER];
+
+		if ( mImpl->getFilename().empty() )
+		{
+			// we have no filename, use virtual file ID instead
+			LLHTTPClient::postFile(
+				analyzer_url,
+				mImpl->getVFileID(),
+				asset_type,
+				this);
+		}
+		else
+		{
+			LLHTTPClient::postFile(
+				analyzer_url,
+				mImpl->getFilename(),
+				this);
+		}
+	}
+	else 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 ( _NEEDS_CONFIRMATION == state )
+	{
+		showConfirmationDialog(
+			content[_UPLOAD_PRICE].asInteger(),
+			content[_RESOURCE_COST].asInteger(),
+			content[_RSVP].asString());
+	}
+	else if ( _CANCEL == state )
+	{
+		// cancelled, do nothing
+	}
+	else
+	{
+		onApplicationLevelError("");
+	}
+}
+
+void LLNewAgentInventoryVariablePriceResponder::onApplicationLevelError(
+	const std::string& error_identifier)
+{
+	mImpl->onApplicationLevelError(error_identifier);
+}
+
+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!
+		LLSD body;
+		body["confirm_upload"] = true;
+		body["expected_upload_price"] = upload_price;
+
+		LLHTTPClient::post(confirmation_url, body, this);
+	}
+	else
+	{
+		LLSD substitutions;
+		LLSD payload;
+
+		substitutions["PRICE"] = upload_price;
+
+		payload["confirmation_url"] = confirmation_url;
+		payload["expected_upload_price"] = upload_price;
+
+		// 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.
+		LLNotifications::instance().add(
+			"UploadCostConfirmation",
+			substitutions,
+			payload,
+			boost::bind(
+				&LLNewAgentInventoryVariablePriceResponder::Impl::uploadConfirmationCallback,
+				mImpl,
+				_1,
+				_2,
+				boost::intrusive_ptr<LLNewAgentInventoryVariablePriceResponder>(this)));
+	}
+}
diff --git a/indra/newview/llassetuploadresponders.h b/indra/newview/llassetuploadresponders.h
index a08d70213c3f8d5f6eb6e5a6c31837cee0c0873e..adbf13519b8c564f108a8c08391a4f9f237010f5 100644
--- a/indra/newview/llassetuploadresponders.h
+++ b/indra/newview/llassetuploadresponders.h
@@ -61,17 +61,58 @@ class LLAssetUploadResponder : public LLHTTPClient::Responder
 	std::string mFileName;
 };
 
+
+// TODO*: Remove this once deprecated
 class LLNewAgentInventoryResponder : public LLAssetUploadResponder
 {
 public:
-	LLNewAgentInventoryResponder(const LLSD& post_data,
-								const LLUUID& vfile_id,
-								LLAssetType::EType asset_type);
-	LLNewAgentInventoryResponder(const LLSD& post_data, const std::string& file_name,
-											   LLAssetType::EType asset_type);
+	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 uploadComplete(const LLSD& content);
 };
 
+// A base class which goes through and performs some default
+// actions for variable price uploads.  If more specific actions
+// are needed (such as different confirmation messages, etc.)
+// the functions onApplicationLevelError and showConfirmationDialog.
+class LLNewAgentInventoryVariablePriceResponder :
+	public LLHTTPClient::Responder
+{
+public:
+	LLNewAgentInventoryVariablePriceResponder(
+		const LLUUID& vfile_id,
+		const LLSD& inventory_info);
+
+	LLNewAgentInventoryVariablePriceResponder(
+		const std::string& file_name,
+		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 std::string& error_identifier);
+	virtual void showConfirmationDialog(
+		S32 upload_price,
+		S32 resource_cost,
+		const std::string& confirmation_url);
+
+private:
+	class Impl;
+	Impl* mImpl;
+};
+
 class LLBakedUploadData;
 class LLSendTexLayerResponder : public LLAssetUploadResponder
 {
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 5a10b688da4290e6f2d81d0a28b8fd58b8617fce..27c9ab319a8130658ba44db1912181a1bcac8c44 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -314,8 +314,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/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index e087feeaecf4c13ff55318b8604e968e4b351ec1..e74b488be9689c8a1a3032ec62115ff818e91f4f 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -701,6 +701,18 @@ void LLDrawPoolBump::endBump()
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 }
 
+S32 LLDrawPoolBump::getNumDeferredPasses()
+{ 
+	if (gSavedSettings.getBOOL("RenderObjectBump"))
+	{
+		return 1;
+	}
+	else
+	{
+		return 0;
+	}
+}
+
 void LLDrawPoolBump::beginDeferredPass(S32 pass)
 {
 	if (!gPipeline.hasRenderBatches(LLRenderPass::PASS_BUMP))
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index bf940cf1e46ef6d5bbf0bd58eb57265fd5d58e2c..2019f1df2698c45a7ef014363c14a0f129cdd94f 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -79,7 +79,7 @@ protected :
 	void renderBump();
 	void endBump();
 
-	virtual S32 getNumDeferredPasses() { return 1; }
+	virtual S32 getNumDeferredPasses();
 	/*virtual*/ void beginDeferredPass(S32 pass);
 	/*virtual*/ void endDeferredPass(S32 pass);
 	/*virtual*/ void renderDeferred(S32 pass);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 4246cbc27f24d4322154878239318554513e0e96..e49ef8b96998da0e7435ea3148b8f48470d2a47b 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -1040,7 +1040,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	if (full_rebuild)
 	{
 		mVertexBuffer->getIndexStrider(indicesp, mIndicesIndex);
-		for (U16 i = 0; i < num_indices; i++)
+		for (S32 i = 0; i < num_indices; i++)
 		{
 			*indicesp++ = vf.mIndices[i] + index_offset;
 		}
diff --git a/indra/newview/llfilepicker.cpp b/indra/newview/llfilepicker.cpp
index 028e1cc098c50b0963c4873c8b4fae7683ec9b67..e12db901bd61a08bd5c876d42affe8a002cebfb1 100644
--- a/indra/newview/llfilepicker.cpp
+++ b/indra/newview/llfilepicker.cpp
@@ -61,6 +61,7 @@ LLFilePicker LLFilePicker::sInstance;
 #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
 
 //
@@ -193,6 +194,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;
diff --git a/indra/newview/llfilepicker.h b/indra/newview/llfilepicker.h
index ab2455620fee2ab9f0a40add1695eb65425bb281..7600922e9c0e51ca8792d53b92056b3dc18da8eb 100644
--- a/indra/newview/llfilepicker.h
+++ b/indra/newview/llfilepicker.h
@@ -93,6 +93,7 @@ class LLFilePicker
 		FFLOAD_XML = 6,
 		FFLOAD_SLOBJECT = 7,
 		FFLOAD_RAW = 8,
+		FFLOAD_MODEL = 9,
 	};
 
 	enum ESaveFilter
@@ -198,4 +199,6 @@ class LLFilePicker
 	~LLFilePicker();
 };
 
+const std::string upload_pick(void* data);
+
 #endif
diff --git a/indra/newview/llfloaterinventory.cpp b/indra/newview/llfloaterinventory.cpp
index c890f9f1226c963c48d15b1f55a1ea315a919080..364c79e3c1454e302a8b6b76f8e3f5095a06c36b 100644
--- a/indra/newview/llfloaterinventory.cpp
+++ b/indra/newview/llfloaterinventory.cpp
@@ -1143,6 +1143,9 @@ const std::string& get_item_icon_name(LLAssetType::EType asset_type,
 	case LLAssetType::AT_LINK_FOLDER:
 		idx = LINKFOLDER_ICON_NAME;
 		break;
+	case LLAssetType::AT_MESH:
+		idx = MESH_ICON_NAME;
+		break;
 	default:
 		break;
 	}
diff --git a/indra/newview/llhudtext.cpp b/indra/newview/llhudtext.cpp
index 55019f91f89d2f1458512c2697646359d4c2c12c..58637329d754606915fb204588742cd498340b47 100644
--- a/indra/newview/llhudtext.cpp
+++ b/indra/newview/llhudtext.cpp
@@ -567,6 +567,18 @@ void LLHUDText::setStringUTF8(const std::string &wtext)
 	setString(utf8str_to_wstring(wtext));
 }
 
+std::string LLHUDText::getString()
+{
+	std::ostringstream ostr;
+	for (U32 i = 0; i < mTextSegments.size(); ++i)
+	{
+		const std::string str = wstring_to_utf8str(mTextSegments[i].getText());
+		ostr << str;
+	}
+
+	return ostr.str();
+}
+
 void LLHUDText::setString(const LLWString &wtext)
 {
 	mTextSegments.clear();
diff --git a/indra/newview/llhudtext.h b/indra/newview/llhudtext.h
index dc14a8c764ac825e6687c454791aa2f52ed15fea..4787a15eafe88f4d82cf8c964153be44e7d827c0 100644
--- a/indra/newview/llhudtext.h
+++ b/indra/newview/llhudtext.h
@@ -90,6 +90,7 @@ class LLHUDText : public LLHUDObject
 
 public:
 	void setStringUTF8(const std::string &utf8string);
+	std::string getString();
 	void setString(const LLWString &wstring);
 	void clearString();
 	void addLine(const std::string &text, const LLColor4& color, const LLFontGL::StyleFlags style = LLFontGL::NORMAL);
diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp
index ca9ebf8dc14f3dc89c383424a70fcacfd4ecd606..028505456bcefb3e49060d69db3f86e5fd6f4139 100644
--- a/indra/newview/llinventorybridge.cpp
+++ b/indra/newview/llinventorybridge.cpp
@@ -154,7 +154,9 @@ std::string ICON_NAME[ICON_NAME_COUNT] =
 	"Inv_Gesture",
 
 	"inv_item_linkitem.tga",
-	"inv_item_linkfolder.tga"
+	"inv_item_linkfolder.tga",
+	
+	"inv_item_mesh.tga"
 };
 
 
@@ -891,6 +893,14 @@ LLInvFVBridge* LLInvFVBridge::createBridge(LLAssetType::EType asset_type,
 			// Only should happen for broken links.
 			new_listener = new LLLinkItemBridge(inventory, uuid);
 			break;
+	        case LLAssetType::AT_MESH:
+			if(!(inv_type == LLInventoryType::IT_MESH))
+			{
+				llwarns << LLAssetType::lookup(asset_type) << " asset has inventory type " << safe_inv_type_lookup(inv_type) << " on uuid " << uuid << llendl;
+			}
+			new_listener = new LLMeshBridge(inventory, uuid);
+			break;
+
 		default:
 			llinfos << "Unhandled asset type (llassetstorage.h): "
 					<< (S32)asset_type << llendl;
@@ -2189,6 +2199,9 @@ LLUIImagePtr LLFolderBridge::getIcon(LLAssetType::EType preferred_type)
 {
 	// we only have one folder image now
 	return LLUI::getUIImage("Inv_FolderClosed");
+		/*case LLAssetType::AT_MESH:
+			control = "inv_folder_mesh.tga";
+			break;*/
 }
 
 BOOL LLFolderBridge::renameItem(const std::string& new_name)
@@ -2558,6 +2571,7 @@ BOOL LLFolderBridge::dragOrDrop(MASK mask, BOOL drop,
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
 		case DAD_LINK:
+		case DAD_MESH:
 			accept = dragItemIntoFolder((LLInventoryItem*)cargo_data,
 										drop);
 			break;
@@ -3457,6 +3471,7 @@ BOOL LLCallingCardBridge::dragOrDrop(MASK mask, BOOL drop,
 		case DAD_BODYPART:
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
+		case DAD_MESH:
 			{
 				LLInventoryItem* inv_item = (LLInventoryItem*)cargo_data;
 				const LLPermissions& perm = inv_item->getPermissions();
@@ -4713,6 +4728,65 @@ void LLWearableBridge::onRemoveFromAvatarArrived(LLWearable* wearable,
 	delete on_remove_struct;
 }
 
+
+// +=================================================+
+// |        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(isInTrash())
+	{
+		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);
+	}
+
+
+	hideContextEntries(menu, items, disabled_items);
+}
+
+
+
 LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_type,
 													   const LLUUID& uuid,LLInventoryModel* model)
 {
@@ -4761,6 +4835,12 @@ LLInvFVBridgeAction* LLInvFVBridgeAction::createAction(LLAssetType::EType asset_
 
 		break;
 
+	case LLAssetType::AT_MESH:
+		action = new LLMeshBridgeAction(uuid,model);
+		break;
+
+
+		
 	default:
 		break;
 	}
@@ -4998,6 +5078,18 @@ void LLWearableBridgeAction::doIt()
 	LLInvFVBridgeAction::doIt();
 }
 
+//virtual
+void	LLMeshBridgeAction::doIt() 
+{
+	LLViewerInventoryItem* item = getItem();
+	if(item)
+	{
+		// do it
+	}
+	
+	LLInvFVBridgeAction::doIt();
+}
+
 // +=================================================+
 // |        LLLinkItemBridge                         |
 // +=================================================+
diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h
index 6b2a2d32dec98a3e4113c7d36fab3c57b1c00f50..95a5f97e7bfebe7e65e80598228e686bea9f2d4f 100644
--- a/indra/newview/llinventorybridge.h
+++ b/indra/newview/llinventorybridge.h
@@ -79,6 +79,8 @@ enum EInventoryIcon
 
 	LINKITEM_ICON_NAME,
 	LINKFOLDER_ICON_NAME,
+	
+	MESH_ICON_NAME,
 
 	ICON_NAME_COUNT
 };
@@ -609,7 +611,6 @@ class LLLinkItemBridge : public LLItemBridge
 	static std::string sPrefix;
 };
 
-
 class LLLinkFolderBridge : public LLItemBridge
 {
 	friend class LLInvFVBridge;
@@ -630,6 +631,25 @@ class LLLinkFolderBridge : public LLItemBridge
 	static std::string sPrefix;
 };
 
+
+
+class LLMeshBridge : public LLItemBridge
+{
+	friend class LLInvFVBridge;
+public:
+	virtual LLUIImagePtr getIcon() const;
+	virtual void openItem();
+	virtual void previewItem();
+	virtual void buildContextMenu(LLMenuGL& menu, U32 flags);
+
+protected:
+	LLMeshBridge(LLInventoryPanel* inventory, const LLUUID& uuid) :
+		LLItemBridge(inventory, uuid) {}
+};
+
+
+
+
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // Class LLInvFVBridgeAction (& its derived classes)
 //
@@ -790,6 +810,19 @@ class LLWearableBridgeAction: public LLInvFVBridgeAction
 
 };
 
+class LLMeshBridgeAction: public LLInvFVBridgeAction
+{
+	friend class LLInvFVBridgeAction;
+public:
+	virtual void	doIt() ;
+	virtual ~LLMeshBridgeAction(){}
+protected:
+	LLMeshBridgeAction(const LLUUID& id,LLInventoryModel* model):LLInvFVBridgeAction(id,model){}
+
+};
+
+
+
 void wear_inventory_item_on_avatar(LLInventoryItem* item);
 
 class LLViewerJointAttachment;
diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp
index 0ce85818dd61751b5083a985621383b56a02e79c..a82402572392304787cc767f76f6d881c2eda96e 100644
--- a/indra/newview/llpanelgroupnotices.cpp
+++ b/indra/newview/llpanelgroupnotices.cpp
@@ -157,6 +157,7 @@ BOOL LLGroupDropTarget::handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop,
 		case DAD_ANIMATION:
 		case DAD_GESTURE:
 		case DAD_CALLINGCARD:
+		case DAD_MESH:
 		{
 			LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
 			if(gInventory.getItem(inv_item->getUUID())
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index a7f0ce16d38611ff8146e20d73bf9b6172b4bbcc..a5e3a0492be59a98f3e9fc4d4259864fbbeb35ca 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -173,7 +173,6 @@ LLObjectSelection *get_null_object_selection()
 	return sNullSelection;
 }
 
-
 //-----------------------------------------------------------------------------
 // LLSelectMgr()
 //-----------------------------------------------------------------------------
@@ -5301,6 +5300,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()-gAgent.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()
 //-----------------------------------------------------------------------------
@@ -5318,6 +5389,13 @@ void LLSelectNode::renderOneSilhouette(const LLColor4 &color)
 		return;
 	}
 
+	LLVOVolume* vobj = drawable->getVOVolume();
+	if (vobj && vobj->isMesh())
+	{
+		renderOneWireframe(color);
+		return;
+	}
+
 	if (!mSilhouetteExists)
 	{
 		return;
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 6e757ef976fc05bc6a2e315adf07788bc7997e70..b51876594619ef254bc1a8e59556e268293ec523 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; }
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 9f317803ce745c5cea1579136ad290b881227f29..9704fe71b78361cbe72b12f5a3e8967e2c93380e 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2294,7 +2294,6 @@ void pushVerts(LLFace* face, U32 mask)
 		U16 offset = face->getIndicesStart();
 		buffer->drawRange(LLRender::TRIANGLES, start, end, count, offset);
 	}
-
 }
 
 void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index 64c2a9acbc7d94d7da76ad693d94b5e7217a1803..1d9127639afee906600c5a5b7ebd467f1e635950 100644
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -59,6 +59,7 @@ class LLTextureAtlasSlot;
 
 S32 AABBSphereIntersect(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &rad);
 S32 AABBSphereIntersectR2(const LLVector3& min, const LLVector3& max, const LLVector3 &origin, const F32 &radius_squared);
+void pushVerts(LLFace* face, U32 mask);
 
 // get index buffer for binary encoded axis vertex buffer given a box at center being viewed by given camera
 U8* get_box_fan_indices(LLCamera* camera, const LLVector3& center);
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index b5aec1b80bc370cdba8b4b9d9438afff2a17918c..ae4ec75a1b4479c518ea1dbe3756761fd7502ddb 100644
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -289,7 +289,7 @@ BOOL LLFloaterTexturePicker::handleDragAndDrop(
 {
 	BOOL handled = FALSE;
 
-	if (cargo_type == DAD_TEXTURE)
+	if ((cargo_type == DAD_TEXTURE) || (cargo_type == DAD_MESH))
 	{
 		LLInventoryItem *item = (LLInventoryItem *)cargo_data;
 
@@ -1152,7 +1152,9 @@ BOOL LLTextureCtrl::handleDragAndDrop(S32 x, S32 y, MASK mask,
 	// returns true, then the cast was valid, and we can perform
 	// the third test without problems.
 	LLInventoryItem* item = (LLInventoryItem*)cargo_data; 
-	if (getEnabled() && (cargo_type == DAD_TEXTURE) && allowDrop(item))
+	if (getEnabled() &&
+		((cargo_type == DAD_TEXTURE) || (cargo_type == DAD_MESH)) &&
+		 allowDrop(item))
 	{
 		if (drop)
 		{
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 9a63f07a7e578d0c121714b21c1500b912d50324..643a81be1f668a1ffe4174ba4d5d0e84805e9d4e 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -483,6 +483,16 @@ LLToolDragAndDrop::dragOrDrop3dImpl LLToolDragAndDrop::sDragAndDrop3d[DAD_COUNT]
 		&LLToolDragAndDrop::dad3dNULL, // Dest: DT_OBJECT
 		&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
 	},
+
+
+//	Source: DAD_MESH
+	{
+		&LLToolDragAndDrop::dad3dNULL, // Dest: DT_NONE
+		&LLToolDragAndDrop::dad3dNULL, // Dest: DT_SELF
+		&LLToolDragAndDrop::dad3dGiveInventory, // Dest: DT_AVATAR
+		&LLToolDragAndDrop::dad3dUpdateInventory, // Dest: DT_OBJECT
+		&LLToolDragAndDrop::dad3dNULL,//dad3dAssetOnLand, // Dest: DT_LAND
+	},
 };
 
 LLToolDragAndDrop::LLToolDragAndDrop()
@@ -2007,6 +2017,7 @@ bool LLToolDragAndDrop::handleGiveDragAndDrop(LLUUID dest_agent, LLUUID session_
 	case DAD_ANIMATION:
 	case DAD_GESTURE:
 	case DAD_CALLINGCARD:
+	case DAD_MESH:
 	{
 		LLViewerInventoryItem* inv_item = (LLViewerInventoryItem*)cargo_data;
 		if(gInventory.getItem(inv_item->getUUID())
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index a6a72e96661008945f1b2eb29f207895c6eb9565..3b727e28611a02a845bb46111e0f125723250f11 100644
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -869,12 +869,6 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			}
 		}
 
-		/// 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->getWindowDisplayWidth(), gViewerWindow->getWindowDisplayHeight());
-		
 		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
 		{
 			gPipeline.renderDeferredLighting();
@@ -1097,7 +1091,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 dace3f875f553c44598c9f84c31d3d86a6645821..7c5f5e8b2f9e48ca3ab35a267b23ee7b7aef0a70 100644
--- a/indra/newview/llviewerfloaterreg.cpp
+++ b/indra/newview/llviewerfloaterreg.cpp
@@ -122,6 +122,8 @@
 #include "llpreviewsound.h"
 #include "llpreviewtexture.h"
 #include "llsyswellwindow.h"
+#include "llfloatermodelpreview.h"
+
 // *NOTE: Please add files in alphabetical order to keep merges easy.
 
 
@@ -236,7 +238,7 @@ void LLViewerFloaterReg::registerFloaters()
 	LLFloaterReg::add("upload_anim", "floater_animation_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterAnimPreview>, "upload");
 	LLFloaterReg::add("upload_image", "floater_image_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterImagePreview>, "upload");
 	LLFloaterReg::add("upload_sound", "floater_sound_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSoundPreview>, "upload");
-	
+	LLFloaterReg::add("upload_model", "floater_model_preview.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterModelPreview>, "upload");
 	LLFloaterReg::add("voice_call", "floater_call.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterCall>);
 	
 	LLFloaterReg::add("whitelist_entry", "floater_whitelist_entry.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterWhiteListEntry>);	
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index dc291d6c34cf14bf883f07844677d944e55ed9bf..56f70e0f5dde1b02a19e9d559e55760db027ac20 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -268,7 +268,6 @@ LLMenuItemCallGL* gBusyMenu = NULL;
 // Local prototypes
 
 // File Menu
-const char* upload_pick(void* data);
 void handle_compress_image(void*);
 
 
@@ -557,6 +556,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);
+	gMenuHolder->childSetLabelArg("Upload Model", "[COST]", upload_cost);
 
 	gAFKMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Away", TRUE);
 	gBusyMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Busy", TRUE);
diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp
index d3a9e1cef8a96c54811166324fbffc25ea90cf1c..836ac79a87d35bfa1ea9f588ed23032936b66968 100644
--- a/indra/newview/llviewermenufile.cpp
+++ b/indra/newview/llviewermenufile.cpp
@@ -39,6 +39,7 @@
 #include "llfilepicker.h"
 #include "llfloaterreg.h"
 #include "llfloaterbuycurrency.h"
+#include "llfloatermodelpreview.h"
 #include "llfloatersnapshot.h"
 #include "llinventorymodel.h"	// gInventory
 #include "llresourcedata.h"
@@ -62,6 +63,7 @@
 #include "lleconomy.h"
 #include "llhttpclient.h"
 #include "llsdserialize.h"
+#include "llsdutil.h"
 #include "llstring.h"
 #include "lltransactiontypes.h"
 #include "lluuid.h"
@@ -101,6 +103,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)
 {
@@ -115,6 +118,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;
@@ -258,6 +263,16 @@ class LLFileUploadImage : public view_listener_t
 	}
 };
 
+class LLFileUploadModel : public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		LLFloaterReg::showInstance("upload_model");
+		
+		return TRUE;
+	}
+};
+	
 class LLFileUploadSound : public view_listener_t
 {
 	bool handleEvent(const LLSD& userdata)
@@ -319,10 +334,21 @@ class LLFileUploadBulk : public view_listener_t
 			LLAssetStorage::LLStoreAssetCallback callback = NULL;
 			S32 expected_upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
 			void *userdata = NULL;
-			upload_new_resource(filename, asset_name, asset_name, 0, LLAssetType::AT_NONE, LLInventoryType::IT_NONE,
-				LLFloaterPerms::getNextOwnerPerms(), LLFloaterPerms::getGroupPerms(), LLFloaterPerms::getEveryonePerms(),
-					    display_name,
-					    callback, expected_upload_cost, userdata);
+
+			upload_new_resource(
+				filename,
+				asset_name,
+				asset_name,
+				0,
+				LLAssetType::AT_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()
@@ -491,17 +517,20 @@ void handle_compress_image(void*)
 	}
 }
 
-void upload_new_resource(const std::string& src_filename, std::string name,
-			 std::string desc, S32 compression_info,
-			 LLAssetType::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 std::string& src_filename,
+	std::string name,
+	std::string desc,
+	S32 compression_info,
+	LLAssetType::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();
@@ -783,9 +812,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, compression_info, // tid
-				    destination_folder_type, inv_type, next_owner_perms, group_perms, everyone_perms,
-				    display_name, callback, expected_upload_cost, userdata);
+		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
 	{
@@ -801,7 +842,11 @@ void upload_new_resource(const std::string& src_filename, std::string name,
 	}
 }
 
-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;
@@ -902,71 +947,134 @@ void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExt
 		std::string display_name = LLStringUtil::null;
 		LLAssetStorage::LLStoreAssetCallback callback = NULL;
 		void *userdata = NULL;
-		upload_new_resource(next_file, asset_name, asset_name,	// file
-				    0, LLAssetType::AT_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);
+		upload_new_resource(
+			next_file,
+			asset_name,
+			asset_name,	// file
+			0,
+			LLAssetType::AT_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, S32 compression_info,
-			 LLAssetType::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 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)
+	if ( gDisconnected )
 	{
-		return ;
+		LLAssetID rv;
+
+		rv.setNull();
+		return rv;
 	}
 
 	LLAssetID uuid = tid.makeAssetID(gAgent.getSecureSessionID());
 	
-	if( LLAssetType::AT_SOUND == asset_type )
+	if ( LLAssetType::AT_SOUND == asset_type )
 	{
-		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT );
+		LLViewerStats::getInstance()->incStat(
+			LLViewerStats::ST_UPLOAD_SOUND_COUNT );
 	}
-	else
-	if( LLAssetType::AT_TEXTURE == asset_type )
+	else if ( LLAssetType::AT_TEXTURE == asset_type )
 	{
-		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
+		LLViewerStats::getInstance()->incStat(
+			LLViewerStats::ST_UPLOAD_TEXTURE_COUNT );
 	}
-	else
-	if( LLAssetType::AT_ANIMATION == asset_type)
+	else if ( LLAssetType::AT_ANIMATION == asset_type )
 	{
-		LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT );
+		LLViewerStats::getInstance()->incStat(
+			LLViewerStats::ST_UPLOAD_ANIM_COUNT );
 	}
 
-	if(LLInventoryType::IT_NONE == inv_type)
+	if ( LLInventoryType::IT_NONE == inventory_type )
 	{
-		inv_type = LLInventoryType::defaultForAssetType(asset_type);
+		inventory_type = LLInventoryType::defaultForAssetType(asset_type);
 	}
 	LLStringUtil::stripNonprintable(name);
-	LLStringUtil::stripNonprintable(desc);
-	if(name.empty())
+	LLStringUtil::stripNonprintable(description);
+
+	if ( name.empty() )
 	{
 		name = "(No Name)";
 	}
-	if(desc.empty())
+	if ( description.empty() )
 	{
-		desc = "(No Description)";
+		description = "(No Description)";
 	}
-	
+
 	// At this point, we're ready for the upload.
 	std::string upload_message = "Uploading...\n\n";
 	upload_message.append(display_name);
 	LLUploadDialog::modalUploadDialog(upload_message);
 
+	return uuid;
+}
+
+LLSD generate_new_resource_upload_capability_body(
+	LLAssetType::EType asset_type,
+	const std::string& name,
+	const std::string& desc,
+	LLAssetType::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 == LLAssetType::AT_NONE) ?
+		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,
+	LLAssetType::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;
@@ -975,26 +1083,32 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty
 	llinfos << "Expected Upload Cost: " << expected_upload_cost << llendl;
 	lldebugs << "Folder: " << gInventory.findCategoryUUIDForType((destination_folder_type == LLAssetType::AT_NONE) ? asset_type : destination_folder_type) << llendl;
 	lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
-	std::string url = gAgent.getRegion()->getCapability("NewFileAgentInventory");
-	if (!url.empty())
+
+	std::string url = gAgent.getRegion()->getCapability(
+		"NewFileAgentInventory");
+
+	if ( !url.empty() )
 	{
 		llinfos << "New Agent Inventory via capability" << llendl;
-		LLSD body;
-		body["folder_id"] = gInventory.findCategoryUUIDForType((destination_folder_type == LLAssetType::AT_NONE) ? 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);
-		
-		//std::ostringstream llsdxml;
-		//LLSDSerialize::toPrettyXML(body, llsdxml);
-		//llinfos << "posting body to capability: " << llsdxml.str() << llendl;
 
-		LLHTTPClient::post(url, body, new LLNewAgentInventoryResponder(body, uuid, asset_type));
+		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
 	{
@@ -1039,11 +1153,83 @@ void upload_new_resource(const LLTransactionID &tid, LLAssetType::EType asset_ty
 	}
 }
 
+BOOL upload_new_variable_cost_resource(
+	const LLTransactionID &tid, 
+	LLAssetType::EType asset_type,
+	std::string name,
+	std::string desc, 
+	S32 compression_info,
+	LLAssetType::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,
+	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;
+	lldebugs << "Folder: "
+ << gInventory.findCategoryUUIDForType((destination_folder_type == LLAssetType::AT_NONE) ? asset_type : destination_folder_type) << llendl;
+	lldebugs << "Asset Type: " << LLAssetType::lookup(asset_type) << llendl;
+
+	std::string url = gAgent.getRegion()->getCapability(
+		"NewFileAgentInventoryVariablePrice");
+
+	if ( !url.empty() )
+	{
+		llinfos << "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);
+
+		LLHTTPClient::post(
+			url,
+			body,
+			new LLNewAgentInventoryVariablePriceResponder(
+				uuid,
+				body));
+
+		return TRUE;
+	}
+	else
+	{
+		return FALSE;
+	}
+}
+
 void init_menu_file()
 {
 	view_listener_t::addCommit(new LLFileUploadImage(), "File.UploadImage");
 	view_listener_t::addCommit(new LLFileUploadSound(), "File.UploadSound");
 	view_listener_t::addCommit(new LLFileUploadAnim(), "File.UploadAnim");
+	view_listener_t::addCommit(new LLFileUploadModel(), "File.UploadModel");
 	view_listener_t::addCommit(new LLFileUploadBulk(), "File.UploadBulk");
 	view_listener_t::addCommit(new LLFileCloseWindow(), "File.CloseWindow");
 	view_listener_t::addCommit(new LLFileCloseAllWindows(), "File.CloseAllWindows");
diff --git a/indra/newview/llviewermenufile.h b/indra/newview/llviewermenufile.h
index bf21292082bc53a3bc37c88072d33918725958e8..b51192b499f60e5a742666c9dbe73757e9d92e03 100644
--- a/indra/newview/llviewermenufile.h
+++ b/indra/newview/llviewermenufile.h
@@ -41,33 +41,56 @@ class LLTransactionID;
 
 void init_menu_file();
 
-void upload_new_resource(const std::string& src_filename, 
-			 std::string name,
-			 std::string desc, 
-			 S32 compression_info,
-			 LLAssetType::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 std::string& src_filename, 
+	std::string name,
+	std::string desc, 
+	S32 compression_info,
+	LLAssetType::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,
+	LLAssetType::EType destination_folder_type,
+	LLInventoryType::EType inv_type,
+	U32 next_owner_perms,
+	U32 group_perms,
+	U32 everyone_perms,
+	const std::string& display_name,
+	LLAssetStorage::LLStoreAssetCallback callback,
+	S32 expected_upload_cost,
+	void *userdata);
+
+// TODO* : Move all uploads to use this new function
+// since at some point, that upload path will be deprecated and no longer
+// used
+
+// We make a new function here to ensure that previous code is not broken
+BOOL upload_new_variable_cost_resource(
+	const LLTransactionID &tid, 
+	LLAssetType::EType type,
+	std::string name,
+	std::string desc, 
+	S32 compression_info,
+	LLAssetType::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,
+	void *userdata);
 
-void upload_new_resource(const LLTransactionID &tid, 
-			 LLAssetType::EType type,
-			 std::string name,
-			 std::string desc, 
-			 S32 compression_info,
-			 LLAssetType::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);
 
 #endif
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 791ec07349116ce9d323cff4ac2322a8c0d5c9c2..f16465acba0234bf9e029456df7d196fe81660bd 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -4530,6 +4530,7 @@ void process_economy_data(LLMessageSystem *msg, void** /*user_data*/)
 
 	gMenuHolder->childSetLabelArg("Upload Image", "[COST]", llformat("%d", upload_cost));
 	gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", llformat("%d", upload_cost));
+	gMenuHolder->childSetLabelArg("Upload Model", "[COST]", llformat("%d", upload_cost));
 	gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", llformat("%d", upload_cost));
 	gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", llformat("%d", upload_cost));
 }
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 7ea55b49e869452ab988e4372a88eec4e8ead0f5..986264ad347311043143398a2652f5f8a7413529 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1437,6 +1437,8 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
 	capabilityNames.append("MapLayer");
 	capabilityNames.append("MapLayerGod");
 	capabilityNames.append("NewFileAgentInventory");
+	capabilityNames.append("NewFileAgentInventoryVariablePrice");
+	capabilityNames.append("ObjectAdd");
 	capabilityNames.append("ParcelPropertiesUpdate");
 	capabilityNames.append("ParcelMediaURLFilterList");
 	capabilityNames.append("ParcelNavigateMedia");
diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp
index 65994dfb3080b5c051b57bc95e96f7b9fd86ce3d..ed8d82084444eeb50ba05baaffbfe908f767e8d0 100644
--- a/indra/newview/llviewertexteditor.cpp
+++ b/indra/newview/llviewertexteditor.cpp
@@ -477,6 +477,7 @@ LLUIImagePtr LLEmbeddedItems::getItemImage(llwchar ext_char) const
 			case LLAssetType::AT_GESTURE:			img_name = "Inv_Gesture";	break;
 				//TODO need img_name
 			case LLAssetType::AT_FAVORITE:		img_name = "Inv_Landmark";	 break;
+			case LLAssetType::AT_MESH:            img_name = "inv_item_mesh.tga";	 break;
 			default: llassert(0); 
 		}
 
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index a0ab4cb1e68687c6064bd02ee707b8ea8af83df4..32baa29afbe94991edcf2196b5d10a0723550536 100644
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -583,7 +583,7 @@ BOOL LLViewerTexture::createGLTexture(S32 discard_level, const LLImageRaw* image
 	llassert_always(mGLTexturep.notNull()) ;	
 
 	BOOL ret = mGLTexturep->createGLTexture(discard_level, imageraw, usename) ;
-	
+
 	if(ret)
 	{
 		mFullWidth = mGLTexturep->getCurrentWidth() ;
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 5f95e9ccf1b5c67c1ff8c74a98074dab50300c64..72e40e30302025d3b4c6741a516edc0d22a57496 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -3733,140 +3733,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 / mWindowRect.getWidth(), (F32)h / mWindowRect.getHeight()) ;
-	LLRect window_rect = mWindowRect;
-	mWindowRect.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->getVirtualWindowRect(), 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) ;
-	mWindowRect = 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.
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 583246c23e801a75b13b3050f4920329b0ba2445..ef3244b199ad3340eaf384f8b3e7c2a035b35da7 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"
@@ -61,6 +63,7 @@
 #include "llsky.h"
 #include "llviewercamera.h"
 #include "llviewertexturelist.h"
+#include "llviewerobjectlist.h"
 #include "llviewerregion.h"
 #include "llviewertextureanim.h"
 #include "llworld.h"
@@ -90,6 +93,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");
+
 
 LLVOVolume::LLVOVolume(const LLUUID &id, const LLPCode pcode, LLViewerRegion *regionp)
 	: LLViewerObject(id, pcode, regionp),
@@ -513,6 +522,7 @@ void LLVOVolume::updateTextures(LLAgent &agent)
 
 void LLVOVolume::updateTextures()
 {
+	LLFastTimer ftm(FTM_VOLUME_TEXTURES);
 	// Update the pixel area of all faces
 
 	if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_SIMPLE))
@@ -599,36 +609,60 @@ void LLVOVolume::updateTextures()
 	if (isSculpted())
 	{
 		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
-		LLUUID id =  sculpt_params->getSculptTexture(); 
-		mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-		if (mSculptTexture.notNull())
-		{
-			S32 lod = llmin(mLOD, 3);
-			F32 lodf = ((F32)(lod + 1.0f)/4.f); 
-			F32 tex_size = lodf * MAX_SCULPT_REZ;
-			mSculptTexture->addTextureStats(2.f * tex_size * tex_size);
-			mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
-												(S32)LLViewerTexture::BOOST_SCULPTED));
-			mSculptTexture->setForSculpt() ;
-		}
-
-		S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture
-		S32 current_discard = mSculptLevel;
+		LLUUID id =  sculpt_params->getSculptTexture();
+		U8 sculpt_type = sculpt_params->getSculptType();
 
-		if (texture_discard >= 0 && //texture has some data available
-			(texture_discard < current_discard || //texture has more data than last rebuild
-			current_discard < 0)) //no previous rebuild
+		if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+			// mesh is a mesh
 		{
-			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
-			mSculptChanged = TRUE;
+			if (mSculptLevel == -2)
+			{
+				// get the asset please
+				gPipeline.loadMesh(this, id);
+				/*gAssetStorage->getAssetData(id,	LLAssetType::AT_MESH, (LLGetAssetCallback)NULL, NULL, TRUE);
+
+				if (gAssetStorage->hasLocalAsset(id, LLAssetType::AT_MESH))
+				{
+					gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
+					mSculptChanged = TRUE;
+				}*/
+			}
 		}
 
-		if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED))
+		else
+			// mesh is a sculptie
+		{
+			mSculptTexture = LLViewerTextureManager::getFetchedTexture(id, TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+
+			if (mSculptTexture.notNull())
+			{
+				S32 lod = llmin(mLOD, 3);
+				F32 lodf = ((F32)(lod + 1.0f)/4.f); 
+				F32 tex_size = lodf * MAX_SCULPT_REZ;
+				mSculptTexture->addTextureStats(2.f * tex_size * tex_size);
+				mSculptTexture->setBoostLevel(llmax((S32)mSculptTexture->getBoostLevel(),
+												(S32)LLViewerTexture::BOOST_SCULPTED));
+				mSculptTexture->setForSculpt() ;
+			}
+
+			S32 texture_discard = mSculptTexture->getDiscardLevel(); //try to match the texture
+			S32 current_discard = mSculptLevel;
+
+			if (texture_discard >= 0 && //texture has some data available
+				(texture_discard < current_discard || //texture has more data than last rebuild
+				 current_discard < 0)) //no previous rebuild
+			{
+				gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE);
+				mSculptChanged = TRUE;
+			}
+
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SCULPTED))
 			{
 				setDebugText(llformat("T%d C%d V%d\n%dx%d",
 									  texture_discard, current_discard, getVolume()->getSculptLevel(),
 									  mSculptTexture->getHeight(), mSculptTexture->getWidth()));
 			}
+		}
 	}
 
 	if (getLightTextureID().notNull())
@@ -771,8 +805,10 @@ LLDrawable *LLVOVolume::createDrawable(LLPipeline *pipeline)
 }
 
 
-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;
+
 	// Check if we need to change implementations
 	bool is_flexible = (volume_params.getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE);
 	if (is_flexible)
@@ -811,21 +847,39 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
 		
 		if (isSculpted())
 		{
-			mSculptTexture = LLViewerTextureManager::getFetchedTexture(volume_params.getSculptID(), TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
-			if (mSculptTexture.notNull())
+			// if it's a mesh
+			if ((volume_params.getSculptType() & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
 			{
-				//ignore sculpt GL usage since bao fixed this in a separate branch
-				if (!gGLActive)
+				if (getVolume()->getNumVolumeFaces() == 0)
 				{
-					gGLActive = TRUE;
-					sculpt();
-					gGLActive = FALSE;
+					//mesh is not loaded, request pipeline load this mesh
+					LLUUID asset_id = volume_params.getSculptID();
+					gPipeline.loadMesh(this, asset_id);
 				}
 				else
 				{
-					sculpt();
+					mSculptLevel = 1;
+				}
+			}
+			else // otherwise is sculptie
+			{
+				mSculptTexture = LLViewerTextureManager::getFetchedTexture(volume_params.getSculptID(), TRUE, FALSE, LLViewerTexture::LOD_TEXTURE);
+
+				if (mSculptTexture.notNull())
+				{
+					//ignore sculpt GL usage since bao fixed this in a separate branch
+					if (!gGLActive)
+					{
+						gGLActive = TRUE;
+						sculpt();
+						gGLActive = FALSE;
+					}
+					else
+					{
+						sculpt();
+					}
+					mSculptLevel = getVolume()->getSculptLevel();
 				}
-				mSculptLevel = getVolume()->getSculptLevel();
 			}
 		}
 		else
@@ -838,6 +892,14 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &volume_params, const S32 detail
 	return FALSE;
 }
 
+
+
+void LLVOVolume::notifyMeshLoaded()
+{ 
+	mSculptChanged = TRUE;
+	gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_GEOMETRY);
+}
+
 // sculpt replaces generate() for sculpted surfaces
 void LLVOVolume::sculpt()
 {
@@ -1039,6 +1101,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);
 
@@ -1111,6 +1178,10 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 	for (S32 i = 0; i < getVolume()->getNumFaces(); i++)
 	{
 		LLFace *face = mDrawable->getFace(i);
+		if (!face)
+		{
+			continue;
+		}
 		res &= face->genVolumeBBoxes(*getVolume(), i,
 										mRelativeXform, mRelativeXformInvTrans,
 										(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
@@ -2218,6 +2289,23 @@ BOOL LLVOVolume::isSculpted() const
 	return FALSE;
 }
 
+BOOL LLVOVolume::isMesh() const
+{
+	if (isSculpted())
+	{
+		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+		U8 sculpt_type = sculpt_params->getSculptType();
+
+		if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+			// mesh is a mesh
+		{
+			return TRUE;	
+		}
+	}
+
+	return FALSE;
+}
+
 BOOL LLVOVolume::hasLightTexture() const
 {
 	if (getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
@@ -2423,6 +2511,30 @@ F32 LLVOVolume::getBinRadius()
 {
 	F32 radius;
 	
+	F32 scale = 1.f;
+
+	if (isSculpted())
+	{
+		LLSculptParams *sculpt_params = (LLSculptParams *)getParameterEntry(LLNetworkData::PARAMS_SCULPT);
+		LLUUID id =  sculpt_params->getSculptTexture();
+		U8 sculpt_type = sculpt_params->getSculptType();
+
+		if ((sculpt_type & LL_SCULPT_TYPE_MASK) == LL_SCULPT_TYPE_MESH)
+			// mesh is a mesh
+		{
+			LLVolume* volume = getVolume();
+			U32 vert_count = 0;
+
+			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+			{
+				const LLVolumeFace& face = volume->getVolumeFace(i);
+				vert_count += face.mVertices.size();
+			}
+
+			scale = 1.f/llmax(vert_count/1024.f, 1.f);
+		}
+	}
+
 	const LLVector3* ext = mDrawable->getSpatialExtents();
 	
 	BOOL shrink_wrap = mDrawable->isAnimating();
@@ -2481,7 +2593,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
@@ -3071,6 +3183,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);
@@ -3354,7 +3471,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				}
 				else
 				{
-					if (LLPipeline::sRenderDeferred && te->getBumpmap())
+					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
 					{
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 250c3ed9170a6045a13e8de959e70c2df91db54a..6aaf5b2fddb8cf01246ad0e31723cfebb91094fe 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -182,6 +182,11 @@ class LLVOVolume : public LLViewerObject
 
 	/*virtual*/ BOOL	setVolume(const LLVolumeParams &volume_params, const S32 detail, bool unique_volume = false);
 				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);
@@ -227,6 +232,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;
@@ -235,6 +241,7 @@ class LLVOVolume : public LLViewerObject
 
 	void updateObjectMediaData(const LLSD &media_data_duples);
 	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);
@@ -247,6 +254,8 @@ class LLVOVolume : public LLViewerObject
    
 	bool hasMedia() const;
 
+	void notifyMeshLoaded();
+
 protected:
 	S32	computeLODDetail(F32	distance, F32 radius);
 	BOOL calcLOD();
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index b50e71bf485e7dae057a0258392df01b2e7c260d..7cf5cf75ad23cf1a9b1db458ef1d75587d01059d 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -342,6 +342,8 @@ LLPipeline::LLPipeline() :
 	mGlowPool(NULL),
 	mBumpPool(NULL),
 	mWLSkyPool(NULL),
+	mMeshMutex(NULL),
+	mMeshThreadCount(0),
 	mLightMask(0),
 	mLightMovingMask(0),
 	mLightingDetail(0)
@@ -399,6 +401,7 @@ void LLPipeline::init()
 
 	stop_glerror();
 
+	mMeshMutex = new LLMutex(NULL);
 	for (U32 i = 0; i < 2; ++i)
 	{
 		mSpotLightFade[i] = 1.f;
@@ -473,6 +476,9 @@ void LLPipeline::cleanup()
 	//delete mWLSkyPool;
 	mWLSkyPool = NULL;
 
+	delete mMeshMutex;
+	mMeshMutex = NULL;
+
 	releaseGLBuffers();
 
 	mBloomImagep = NULL;
@@ -1783,6 +1789,8 @@ void LLPipeline::rebuildPriorityGroups()
 	
 	assertInitialized();
 
+	notifyLoadedMeshes();
+
 	// Iterate through all drawables on the priority build queue,
 	for (LLSpatialGroup::sg_list_t::iterator iter = mGroupQ1.begin();
 		 iter != mGroupQ1.end(); ++iter)
@@ -1793,6 +1801,7 @@ void LLPipeline::rebuildPriorityGroups()
 	}
 
 	mGroupQ1.clear();
+
 }
 		
 void LLPipeline::rebuildGroups()
@@ -3419,27 +3428,14 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 	gGLLastMatrix = NULL;
 	glLoadMatrixd(gGLModelView);
 
-	renderHighlights();
-	mHighlightFaces.clear();
-
-	renderDebug();
-
-	LLVertexBuffer::unbind();
-
-	if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
-	{
-		// Render debugging beacons.
-		gObjectList.renderObjectBeacons();
-		LLHUDObject::renderAll();
-		gObjectList.resetObjectBeacons();
-	}
-
 	if (occlude)
 	{
 		occlude = FALSE;
 		gGLLastMatrix = NULL;
 		glLoadMatrixd(gGLModelView);
 		doOcclusion(camera);
+		gGLLastMatrix = NULL;
+		glLoadMatrixd(gGLModelView);
 	}
 }
 
@@ -5836,6 +5832,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);
+		}
 	}
 	
 
@@ -6912,6 +6914,24 @@ void LLPipeline::renderDeferredLighting()
 		mRenderTypeMask = render_mask;
 	}
 
+	{
+		//render highlights, etc.
+		renderHighlights();
+		mHighlightFaces.clear();
+
+		renderDebug();
+
+		LLVertexBuffer::unbind();
+
+		if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+		{
+			// Render debugging beacons.
+			gObjectList.renderObjectBeacons();
+			LLHUDObject::renderAll();
+			gObjectList.resetObjectBeacons();
+		}
+	}
+
 	mScreen.flush();
 						
 }
@@ -7241,18 +7261,12 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 					LLGLDisable cull(GL_CULL_FACE);
 					updateCull(camera, ref_result, 1);
 					stateSort(camera, ref_result);
-					gGL.setColorMask(true, true);
-					mWaterRef.clear();
-					gGL.setColorMask(true, false);
-
-				}
-				else
-				{
-					gGL.setColorMask(true, true);
-					mWaterRef.clear();
-					gGL.setColorMask(true, false);
-				}
-
+				}	
+				
+				gGL.setColorMask(true, true);
+				mWaterRef.clear();
+				gGL.setColorMask(true, false);
+			
 				ref_mask = mRenderTypeMask;
 				mRenderTypeMask = mask;
 			}
@@ -7907,6 +7921,7 @@ void LLPipeline::generateHighlight(LLCamera& camera)
 
 		mHighlight.flush();
 		gGL.setColorMask(true, false);
+		gViewerWindow->setup3DViewport();
 	}
 }
 
@@ -8886,3 +8901,175 @@ LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
 }
 
 
+void LLPipeline::loadMesh(LLVOVolume* volume, LLUUID mesh_id)
+{
+
+	{
+		LLMutexLock lock(mMeshMutex);
+		//add volume to list of loading meshes
+		mesh_load_map::iterator iter = mLoadingMeshes.find(mesh_id);
+		if (iter != mLoadingMeshes.end())
+		{ //request pending for this mesh, append volume id to list
+			iter->second.insert(volume->getID());
+			return;
+		}
+
+		//first request for this mesh
+		mLoadingMeshes[mesh_id].insert(volume->getID());
+	}
+
+	if (gAssetStorage->hasLocalAsset(mesh_id, LLAssetType::AT_MESH))
+	{ //already have asset, load desired LOD in background
+		mPendingMeshes.push_back(new LLMeshThread(mesh_id, volume->getVolume()));
+	}
+	else
+	{ //fetch asset and load when done
+		gAssetStorage->getAssetData(mesh_id, LLAssetType::AT_MESH,
+									getMeshAssetCallback, volume->getVolume(), TRUE);
+	}
+
+}
+
+//static
+void LLPipeline::getMeshAssetCallback(LLVFS *vfs,
+										  const LLUUID& asset_uuid,
+										  LLAssetType::EType type,
+										  void* user_data, S32 status, LLExtStat ext_status)
+{
+	gPipeline.mPendingMeshes.push_back(new LLMeshThread(asset_uuid, (LLVolume*) user_data));
+}
+
+
+LLPipeline::LLMeshThread::LLMeshThread(LLUUID mesh_id, LLVolume* target)
+: LLThread("mesh_loading_thread")
+{
+	mMeshID = mesh_id;
+	mVolume = NULL;
+	mDetail = target->getDetail();
+	mTargetVolume = target;
+}
+
+LLPipeline::LLMeshThread::~LLMeshThread()
+{
+
+}
+
+void LLPipeline::LLMeshThread::run()
+{
+	if (!gAssetStorage || LLApp::instance()->isQuitting())
+	{
+		return;
+	}
+
+	char* buffer = NULL;
+	S32 size = 0;
+	
+	LLVFS* vfs = gAssetStorage->mVFS;
+
+	{
+		LLVFile file(vfs, mMeshID, LLAssetType::AT_MESH, LLVFile::READ);
+		file.waitForLock(VFSLOCK_READ);
+		size = file.getSize();
+		
+		if (size == 0)
+		{
+			gPipeline.meshLoaded(this);
+			return;
+		}
+		
+		buffer = new char[size];
+		file.read((U8*)&buffer[0], size);
+	}
+
+	{
+		std::string buffer_string(buffer, size);
+		std::istringstream buffer_stream(buffer_string);
+
+		{
+			LLVolumeParams volume_params;
+			volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
+			mVolume = new LLVolume(volume_params, mDetail);
+			mVolume->createVolumeFacesFromStream(buffer_stream);
+		}
+	}
+	delete[] buffer;
+	
+	gPipeline.meshLoaded(this);
+}
+
+void LLPipeline::meshLoaded(LLPipeline::LLMeshThread* mesh_thread)
+{
+	LLMutexLock lock(mMeshMutex);
+	mLoadedMeshes.push_back(mesh_thread);
+}
+
+void LLPipeline::notifyLoadedMeshes()
+{ //called from main thread
+
+	U32 max_thread_count = llmax(gSavedSettings.getU32("MeshThreadCount"), (U32) 1);
+	while (mMeshThreadCount < max_thread_count && !mPendingMeshes.empty())
+	{
+		LLMeshThread* mesh_thread = mPendingMeshes.front();
+		mesh_thread->start();
+		++mMeshThreadCount;
+		mPendingMeshes.pop_front();
+	}
+
+	LLMutexLock lock(mMeshMutex);
+	std::list<LLMeshThread*> stopping_threads;
+
+	for (std::list<LLMeshThread*>::iterator iter = mLoadedMeshes.begin(); iter != mLoadedMeshes.end(); ++iter)
+	{ //for each mesh done loading
+		LLMeshThread* mesh = *iter;
+		
+		if (!mesh->isStopped())
+		{ //don't process a LLMeshThread until it's stopped
+			stopping_threads.push_back(mesh);
+			continue;
+		}
+
+		//get list of objects waiting to be notified this mesh is loaded
+		mesh_load_map::iterator obj_iter = mLoadingMeshes.find(mesh->mMeshID);
+
+		if (mesh->mVolume && obj_iter != mLoadingMeshes.end())
+		{
+			//make sure target volume is still valid
+			BOOL valid = FALSE;
+
+			for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
+			{
+				LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
+
+				if (vobj)
+				{
+					if (vobj->getVolume() == mesh->mTargetVolume)
+					{
+						valid = TRUE;
+					}
+				}
+			}
+
+
+			if (valid)
+			{
+				mesh->mTargetVolume->copyVolumeFaces(mesh->mVolume);
+				for (std::set<LLUUID>::iterator vobj_iter = obj_iter->second.begin(); vobj_iter != obj_iter->second.end(); ++vobj_iter)
+				{
+					LLVOVolume* vobj = (LLVOVolume*) gObjectList.findObject(*vobj_iter);
+					if (vobj)
+					{
+						vobj->notifyMeshLoaded();
+					}
+				}
+			}
+
+			mLoadingMeshes.erase(mesh->mMeshID);
+		}
+
+		delete mesh;
+		--mMeshThreadCount;
+	}
+
+	mLoadedMeshes = stopping_threads;
+}
+
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index ce50a3740503eb81c6e0eedfabb5741d30738152..bf654f88b15b6f3d10f20d7b0cc3fa6d9f3433bc 100644
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -278,6 +278,10 @@ class LLPipeline
 	LLCullResult::sg_list_t::iterator beginAlphaGroups();
 	LLCullResult::sg_list_t::iterator endAlphaGroups();
 	
+
+	//mesh management functions
+	void loadMesh(LLVOVolume* volume, LLUUID mesh_id);
+	
 	void addTrianglesDrawn(S32 count);
 	BOOL hasRenderType(const U32 type) const				{ return (type && (mRenderTypeMask & (1<<type))) ? TRUE : FALSE; }
 	BOOL hasRenderDebugFeatureMask(const U32 mask) const	{ return (mRenderDebugFeatureMask & mask) ? TRUE : FALSE; }
@@ -672,6 +676,35 @@ class LLPipeline
 protected:
 	std::vector<LLFace*>		mSelectedFaces;
 
+	typedef std::map<LLUUID, std::set<LLUUID> > mesh_load_map;
+	mesh_load_map mLoadingMeshes;
+	
+	LLMutex*					mMeshMutex;
+
+	class LLMeshThread : public LLThread
+	{
+	public:
+		LLPointer<LLVolume> mVolume;
+		LLVolume* mTargetVolume;
+		LLUUID mMeshID;
+		F32 mDetail;
+		LLMeshThread(LLUUID mesh_id, LLVolume* target);
+		~LLMeshThread();
+		void run();
+	};
+	
+	static void getMeshAssetCallback(LLVFS *vfs,
+										  const LLUUID& asset_uuid,
+										  LLAssetType::EType type,
+										  void* user_data, S32 status, LLExtStat ext_status);
+
+	std::list<LLMeshThread*> mLoadedMeshes;
+	std::list<LLMeshThread*> mPendingMeshes;
+	U32 mMeshThreadCount;
+
+	void meshLoaded(LLMeshThread* mesh_thread);
+	void notifyLoadedMeshes();
+
 	LLPointer<LLViewerFetchedTexture>	mFaceSelectImagep;
 	LLPointer<LLViewerTexture>	mBloomImagep;
 	LLPointer<LLViewerTexture>	mBloomImage2p;
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index 01976c9a5c2a67ab1965477b7acd653999c4fe30..26b0b39a68fb31bbcbf606ea996b9bc3aeaf0fc1 100644
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -568,6 +568,7 @@
   <texture name="inv_folder_landmark.tga" />
   <texture name="inv_folder_lostandfound.tga" />
   <texture name="inv_folder_my_outfits.tga" />
+  <texture name="inv_folder_mesh.tga"/>
   <texture name="inv_folder_notecard.tga" />
   <texture name="inv_folder_object.tga" />
   <texture name="inv_folder_outfit.tga" />
@@ -591,6 +592,7 @@
   <texture name="inv_item_landmark_visited.tga" />
   <texture name="inv_item_linkitem.tga" />
   <texture name="inv_item_linkfolder.tga" />
+  <texture name="inv_item_mesh.tga"/>
   <texture name="inv_item_notecard.tga" />
   <texture name="inv_item_object.tga" />
   <texture name="inv_item_object_multi.tga" />
diff --git a/indra/newview/skins/default/xui/en/floater_about.xml b/indra/newview/skins/default/xui/en/floater_about.xml
index 4d7433233aa92205497ec26b2ed402900a0f6b3c..09240a3e27639ac5d391c97d4e507e9e146c6a73 100644
--- a/indra/newview/skins/default/xui/en/floater_about.xml
+++ b/indra/newview/skins/default/xui/en/floater_about.xml
@@ -152,16 +152,19 @@ It is a rare mind indeed that can render the hitherto non-existent blindingly ob
        word_wrap="true">
 3Dconnexion SDK Copyright (C) 1992-2007 3Dconnexion
 APR Copyright (C) 2000-2004 The Apache Software Foundation
+  Collada DOM Copyright 2005 Sony Computer Entertainment Inc.
 cURL Copyright (C) 1996-2002, Daniel Stenberg, (daniel@haxx.se)
 DBus/dbus-glib Copyright (C) 2002, 2003  CodeFactory AB / Copyright (C) 2003, 2004 Red Hat, Inc.
 expat Copyright (C) 1998, 1999, 2000 Thai Open Source Software Center Ltd.
 FreeType Copyright (C) 1996-2002, The FreeType Project (www.freetype.org).
 GL Copyright (C) 1999-2004 Brian Paul.
+  GLOD Copyright (C) 2003-04 Jonathan Cohen, Nat Duca, Chris Niski, Johns Hopkins University and David Luebke, Brenden Schubert, University of Virginia.
 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
 SDL Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
 SSLeay Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 xmlrpc-epi Copyright (C) 2000 Epinions, Inc.
diff --git a/indra/newview/skins/default/xui/en/floater_inventory.xml b/indra/newview/skins/default/xui/en/floater_inventory.xml
index 0f06558dd1ffeec3cb8590f469f43ecbeb4d904a..6afeb4e82d27b553973f9cee9f8e9e3c99441016 100644
--- a/indra/newview/skins/default/xui/en/floater_inventory.xml
+++ b/indra/newview/skins/default/xui/en/floater_inventory.xml
@@ -123,6 +123,16 @@
                     <menu_item_call.on_enable
                      function="File.EnableUpload" />
                 </menu_item_call>
+              <menu_item_call
+                 label="Model (L$[COST])..."
+                 layout="topleft"
+                 name="Upload Model">
+                <menu_item_call.on_click
+                 function="File.UploadModel"
+                 parameter="" />
+                <menu_item_call.on_enable
+                 function="File.EnableUpload" />
+              </menu_item_call>
                 <menu_item_call
                  label="Animation (L$[COST])..."
                  layout="topleft"
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 7829a4fa933b3a49cc704acbc1915c3d12d4e5e6..c15811f0e8e74b879d9a22256054f782937cefb3 100644
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -1996,6 +1996,9 @@
                  label="Cylinder"
                  name="Cylinder"
                  value="Cylinder" />
+                <combo_box.item
+                 label="Mesh"
+                 value="Mesh" />
             </combo_box>
         </panel>
 
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index 284594426c7439b9ac5a18f6e8a5fcc2f1d75430..d90d1f0635b11c0edb99942f4b4d43d169d2771e 100644
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2210,10 +2210,10 @@
              name="Fast Alpha">
                 <menu_item_check.on_check
                  function="CheckControl"
-                 parameter="RenderDebugGL" />
+                 parameter="RenderFastAlpha" />
                 <menu_item_check.on_click
                  function="ToggleControl"
-                 parameter="RenderDebugGL" />
+                 parameter="RenderFastAlpha" />
             </menu_item_check>
             <menu_item_check
              label="Animation Textures"
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index d10bbe7569f7ecc8438f9fc85a29bb38ec310584..6831e56f0b9ce7a346374aaabb63362849bffe12 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -6540,7 +6540,7 @@ Attachment has been saved.
 Unable to find the help topic for this element.
   </notification>
 
-    <notification
+     <notification
  icon="alertmodal.tga"
  name="ObjectMediaFailure"
  type="alertmodal">
@@ -6551,6 +6551,29 @@ Server Error: Media update or get failed.
          yestext="OK"/>
     </notification>
 
+    
+ <notification
+   icon="alertmodal.tga"
+   name="ConfirmClearTeleportHistory"
+   type="alertmodal">
+Are you sure you want to delete your teleport history?
+    <usetemplate
+     name="okcancelbuttons"
+     notext="Cancel"
+     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"
    name="ConfirmClearTeleportHistory"
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index bdcea05c733c4ecc02035f9e5c88abe6bd7ac000..36f4fb98ed1ef34c941fef7757c0995354186ad0 100644
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -1872,6 +1872,7 @@ this texture in your inventory
 	<string name="InvFolder favorite">Favorites</string>
 	<string name="InvFolder Current Outfit">Current Outfit</string>
 	<string name="InvFolder My Outfits">My Outfits</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 045990811b4bac5c3460a456b04c01753656447e..db4b68e9d6d16f630a426f6398d4f1a153bf7e58 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -194,6 +194,12 @@ def construct(self):
         # For using FMOD for sound... DJS
         self.path("fmod.dll")
 
+        # For automatic level of detail generation in mesh importer
+        self.path("glod.dll")
+
+        # For reading collada files
+        self.path("libcollada14dom21.dll")
+
         # For textures
         if self.prefix(src="../../libraries/i686-win32/lib/release", dst=""):
             self.path("openjpeg.dll")
diff --git a/install.xml b/install.xml
index 44224664cae498d630fe64c1ef1eb4f9021739ec..24ade3209545df27822ba9b39e1b649017f7dc42 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>b97aa644a548310ca3c916518bb07b7e</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/GLOD-windows-20090915.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>01d17182ecc6728edaa520b3c780d194</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-linux-20090921.tar.bz2</uri>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>md5sum</key>
+            <string>fd3e5dade35c586ae13a320ab731df0d</string>
+            <key>url</key>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/colladadom-2.1.1-windows-20090908.tar.bz2</uri>
+          </map>
+        </map>
+      </map>
       <key>curl</key>
       <map>
         <key>copyright</key>
@@ -1186,6 +1252,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>quicktime</key>
       <map>
         <key>copyright</key>
@@ -1400,6 +1492,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>
@@ -1725,6 +1886,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>