diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 3439cf3310c1debf9c932e3011c0549ce6147638..5acf93cfc43f162102885ea4cff9a8a13b23f6d2 100644
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -50,7 +50,7 @@ std::string model_names[] =
 	"low_lod",
 	"medium_lod",
 	"high_lod",
-	"physics_shape"
+	"physics_mesh"
 };
 
 const int MODEL_NAMES_LENGTH = sizeof(model_names) / sizeof(std::string);
@@ -1390,7 +1390,11 @@ LLSD LLModel::writeModel(
 	if (!decomp.mBaseHull.empty() ||
 		!decomp.mHull.empty())		
 	{
-		mdl["decomposition"] = decomp.asLLSD();
+		mdl["physics_convex"] = decomp.asLLSD();
+		if (!decomp.mHull.empty())
+		{ //convex decomposition exists, physics mesh will not be used
+			model[LLModel::LOD_PHYSICS] = NULL;
+		}
 	}
 
 	for (U32 idx = 0; idx < MODEL_NAMES_LENGTH; ++idx)
@@ -1449,7 +1453,6 @@ LLSD LLModel::writeModel(
 					//position + normal
 					for (U32 k = 0; k < 3; ++k)
 					{ //for each component
-
 						//convert to 16-bit normalized across domain
 						U16 val = (U16) (((pos[k]-min_pos.mV[k])/pos_range.mV[k])*65535);
 
@@ -1493,7 +1496,6 @@ LLSD LLModel::writeModel(
 				//write out face data
 				mdl[model_names[idx]][i]["PositionDomain"]["Min"] = min_pos.getValue();
 				mdl[model_names[idx]][i]["PositionDomain"]["Max"] = max_pos.getValue();
-
 				mdl[model_names[idx]][i]["TexCoord0Domain"]["Min"] = min_tc.getValue();
 				mdl[model_names[idx]][i]["TexCoord0Domain"]["Max"] = max_tc.getValue();
 
@@ -1586,15 +1588,15 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
 
 	std::string decomposition;
 
-	if (mdl.has("decomposition"))
+	if (mdl.has("physics_convex"))
 	{ //write out convex decomposition
-		decomposition = zip_llsd(mdl["decomposition"]);
+		decomposition = zip_llsd(mdl["physics_convex"]);
 
 		U32 size = decomposition.size();
 		if (size > 0)
 		{
-			header["decomposition"]["offset"] = (LLSD::Integer) cur_offset;
-			header["decomposition"]["size"] = (LLSD::Integer) size;
+			header["physics_convex"]["offset"] = (LLSD::Integer) cur_offset;
+			header["physics_convex"]["size"] = (LLSD::Integer) size;
 			cur_offset += size;
 			bytes += size;
 		}
@@ -1615,11 +1617,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
 			cur_offset += size;
 			bytes += size;
 		}
-		else
-		{
-			header[model_names[i]]["offset"] = -1;
-			header[model_names[i]]["size"] = 0;
-		}
 	}
 
 	if (!nowrite)
@@ -1633,7 +1630,7 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
 
 		if (!decomposition.empty())
 		{ //write decomposition block
-			ostr.write((const char*) decomposition.data(), header["decomposition"]["size"].asInteger());
+			ostr.write((const char*) decomposition.data(), header["physics_convex"]["size"].asInteger());
 		}
 
 		for (S32 i = 0; i < MODEL_NAMES_LENGTH; i++)
@@ -1772,7 +1769,7 @@ bool LLModel::loadModel(std::istream& is)
 		"low_lod",
 		"medium_lod",
 		"high_lod",
-		"physics_shape",
+		"physics_mesh",
 	};
 
 	const S32 MODEL_LODS = 5;
@@ -1871,8 +1868,8 @@ bool LLModel::loadSkinInfo(LLSD& header, std::istream &is)
 
 bool LLModel::loadDecomposition(LLSD& header, std::istream& is)
 {
-	S32 offset = header["decomposition"]["offset"].asInteger();
-	S32 size = header["decomposition"]["size"].asInteger();
+	S32 offset = header["physics_convex"]["offset"].asInteger();
+	S32 size = header["physics_convex"]["size"].asInteger();
 
 	if (offset >= 0 && size > 0)
 	{
@@ -2012,7 +2009,7 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)
 	{
 		// updated for const-correctness. gcc is picky about this type of thing - Nyx
 		const LLSD::Binary& hulls = decomp["HullList"].asBinary();
-		const LLSD::Binary& position = decomp["Position"].asBinary();
+		const LLSD::Binary& position = decomp["Positions"].asBinary();
 
 		U16* p = (U16*) &position[0];
 
@@ -2022,11 +2019,19 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)
 		LLVector3 max;
 		LLVector3 range;
 
-		min.setValue(decomp["Min"]);
-		max.setValue(decomp["Max"]);
+		if (decomp.has("Min"))
+		{
+			min.setValue(decomp["Min"]);
+			max.setValue(decomp["Max"]);
+		}
+		else
+		{
+			min.set(-0.5f, -0.5f, -0.5f);
+			max.set(0.5f, 0.5f, 0.5f);
+		}
+
 		range = max-min;
 
-		
 		for (U32 i = 0; i < hulls.size(); ++i)
 		{
 			U16 count = (hulls[i] == 0) ? 256 : hulls[i];
@@ -2042,6 +2047,7 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)
 				//point must be unique
 				//llassert(valid.find(test) == valid.end());
 				valid.insert(test);
+
 				mHull[i].push_back(LLVector3(
 					(F32) p[0]/65535.f*range.mV[0]+min.mV[0],
 					(F32) p[1]/65535.f*range.mV[1]+min.mV[1],
@@ -2056,9 +2062,9 @@ void LLModel::Decomposition::fromLLSD(LLSD& decomp)
 		}
 	}
 
-	if (decomp.has("Hull"))
+	if (decomp.has("BoundingVerts"))
 	{
-		const LLSD::Binary& position = decomp["Hull"].asBinary();
+		const LLSD::Binary& position = decomp["BundingVerts"].asBinary();
 
 		U16* p = (U16*) &position[0];
 
@@ -2113,11 +2119,9 @@ LLSD LLModel::Decomposition::asLLSD() const
 	}
 
 	//write decomposition block
-	// ["decomposition"]["HullList"] -- list of 8 bit integers, each entry represents a hull with specified number of points
-	// ["decomposition"]["PositionDomain"]["Min"/"Max"]
-	// ["decomposition"]["Position"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points
-	// ["decomposition"]["Hull"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points representing a single hull approximation of given shape
-	
+	// ["physics_convex"]["HullList"] -- list of 8 bit integers, each entry represents a hull with specified number of points
+	// ["physics_convex"]["Position"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points
+	// ["physics_convex"]["BoundingVerts"] -- list of 16-bit integers to be decoded to given domain, encoded 3D points representing a single hull approximation of given shape
 	
 	//get minimum and maximum
 	LLVector3 min;
@@ -2166,6 +2170,8 @@ LLSD LLModel::Decomposition::asLLSD() const
 	{
 		LLSD::Binary p(total*3*2);
 
+		LLVector3 min(-0.5f, -0.5f, -0.5f);
+		LLVector3 max(0.5f, 0.5f, 0.5f);
 		LLVector3 range = max-min;
 
 		U32 vert_idx = 0;
@@ -2181,8 +2187,12 @@ LLSD LLModel::Decomposition::asLLSD() const
 				U64 test = 0;
 				for (U32 k = 0; k < 3; k++)
 				{
+					F32* src = (F32*) (mHull[i][j].mV);
+
+					llassert(src[k] <= 0.501f && src[k] >= -0.501f);
+
 					//convert to 16-bit normalized across domain
-					U16 val = (U16) (((mHull[i][j].mV[k]-min.mV[k])/range.mV[k])*65535);
+					U16 val = (U16) (((src[k]-min.mV[k])/range.mV[k])*65535);
 
 					if(valid.size() < 3)
 					{
@@ -2210,13 +2220,15 @@ LLSD LLModel::Decomposition::asLLSD() const
 			llassert(valid.size() > 2);
 		}
 
-		ret["Position"] = p;
+		ret["Positions"] = p;
 	}
 
 	if (!mBaseHull.empty())
 	{
 		LLSD::Binary p(mBaseHull.size()*3*2);
 
+		LLVector3 min(-0.5f, -0.5f, -0.5f);
+		LLVector3 max(0.5f, 0.5f, 0.5f);
 		LLVector3 range = max-min;
 
 		U32 vert_idx = 0;
@@ -2224,6 +2236,8 @@ LLSD LLModel::Decomposition::asLLSD() const
 		{
 			for (U32 k = 0; k < 3; k++)
 			{
+				llassert(mBaseHull[j].mV[k] <= 0.50001f && mBaseHull[j].mV[k] >= -0.50001f);
+
 				//convert to 16-bit normalized across domain
 				U16 val = (U16) (((mBaseHull[j].mV[k]-min.mV[k])/range.mV[k])*65535);
 
@@ -2239,7 +2253,7 @@ LLSD LLModel::Decomposition::asLLSD() const
 			}
 		}
 		
-		ret["Hull"] = p;
+		ret["BoundingVerts"] = p;
 	}
 
 	return ret;
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 8be5c427fe8a054e67d582b46e27416783dfecb0..f21d60dd03970657a0bd4961ca9a02ef49f66d5e 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -178,6 +178,80 @@ std::string lod_label_name[NUM_LOD+1] =
 	"I went off the end of the lod_label_name array.  Me so smart."
 };
 
+
+#define LL_DEGENERACY_TOLERANCE  1e-7f
+
+inline F32 dot3fpu(const LLVector4a& a, const LLVector4a& b)
+{
+    volatile F32 p0 = a[0] * b[0];
+    volatile F32 p1 = a[1] * b[1];
+    volatile F32 p2 = a[2] * b[2];
+    return p0 + p1 + p2;
+}
+
+bool ll_is_degenerate(const LLVector4a& a, const LLVector4a& b, const LLVector4a& c, F32 tolerance = LL_DEGENERACY_TOLERANCE)
+{
+        // small area check
+        {
+                LLVector4a edge1; edge1.setSub( a, b );
+                LLVector4a edge2; edge2.setSub( a, c );
+                //////////////////////////////////////////////////////////////////////////
+                /// Linden Modified
+                //////////////////////////////////////////////////////////////////////////
+
+                // If no one edge is more than 10x longer than any other edge, we weaken
+                // the tolerance by a factor of 1e-4f.
+
+                LLVector4a edge3; edge3.setSub( c, b );
+				const F32 len1sq = edge1.dot3(edge1).getF32();
+                const F32 len2sq = edge2.dot3(edge2).getF32();
+                const F32 len3sq = edge3.dot3(edge3).getF32();
+                bool abOK = (len1sq <= 100.f * len2sq) && (len1sq <= 100.f * len3sq);
+                bool acOK = (len2sq <= 100.f * len1sq) && (len1sq <= 100.f * len3sq);
+                bool cbOK = (len3sq <= 100.f * len1sq) && (len1sq <= 100.f * len2sq);
+                if ( abOK && acOK && cbOK )
+                {
+                        tolerance *= 1e-4f;
+                }
+
+                //////////////////////////////////////////////////////////////////////////
+                /// End Modified
+                //////////////////////////////////////////////////////////////////////////
+
+                LLVector4a cross; cross.setCross3( edge1, edge2 );
+
+                LLVector4a edge1b; edge1b.setSub( b, a );
+                LLVector4a edge2b; edge2b.setSub( b, c );
+                LLVector4a crossb; crossb.setCross3( edge1b, edge2b );
+
+                if ( ( cross.dot3(cross).getF32() < tolerance ) || ( crossb.dot3(crossb).getF32() < tolerance ))
+                {
+                        return true;
+                }
+        }
+
+        // point triangle distance check
+        {
+                LLVector4a Q; Q.setSub(a, b);
+                LLVector4a R; R.setSub(c, b);
+
+                const F32 QQ = dot3fpu(Q, Q);
+                const F32 RR = dot3fpu(R, R);
+                const F32 QR = dot3fpu(R, Q);
+
+                volatile F32 QQRR = QQ * RR;
+                volatile F32 QRQR = QR * QR;
+                F32 Det = (QQRR - QRQR);
+
+                if( Det == 0.0f )
+                {
+                        return true;
+                }
+        }
+
+        return false;
+}
+
 bool validate_face(const LLVolumeFace& face)
 {
 	for (U32 i = 0; i < face.mNumIndices; ++i)
@@ -189,6 +263,31 @@ bool validate_face(const LLVolumeFace& face)
 		}
 	}
 
+	if (face.mNumIndices % 3 != 0 || face.mNumIndices == 0)
+	{
+		llwarns << "Face has invalid number of indices." << llendl;
+		return false;
+	}
+
+	/*const LLVector4a scale(0.5f);
+
+	for (U32 i = 0; i < face.mNumIndices; i+=3)
+	{
+		U16 idx1 = face.mIndices[i];
+		U16 idx2 = face.mIndices[i+1];
+		U16 idx3 = face.mIndices[i+2];
+
+		LLVector4a v1; v1.setMul(face.mPositions[idx1], scale);
+		LLVector4a v2; v2.setMul(face.mPositions[idx2], scale);
+		LLVector4a v3; v3.setMul(face.mPositions[idx3], scale);
+
+		if (ll_is_degenerate(v1,v2,v3))
+		{
+			llwarns << "Degenerate face found!" << llendl;
+			return false;
+		}
+	}*/
+
 	return true;
 }
 
@@ -3784,7 +3883,35 @@ void LLModelPreview::updateStatusMessages()
 		mMaxTriangleLimit = total_tris[LLModel::LOD_HIGH];
 	}
 
+	bool has_degenerate = false;
+
+	{//check for degenerate triangles in physics mesh
+		U32 lod = LLModel::LOD_PHYSICS;
+		const LLVector4a scale(0.5f);
+		for (U32 i = 0; i < mModel[lod].size() && !has_degenerate; ++i)
+		{ //for each model in the lod
+			if (mModel[lod][i]->mPhysics.mHull.empty())
+			{ //no decomp exists
+				S32 cur_submeshes = mModel[lod][i]->getNumVolumeFaces();
+				for (S32 j = 0; j < cur_submeshes && !has_degenerate; ++j)
+				{ //for each submesh (face), add triangles and vertices to current total
+					const LLVolumeFace& face = mModel[lod][i]->getVolumeFace(j);
+					for (S32 k = 0; k < face.mNumIndices && !has_degenerate; )
+					{
+						LLVector4a v1; v1.setMul(face.mPositions[face.mIndices[k++]], scale);
+						LLVector4a v2; v2.setMul(face.mPositions[face.mIndices[k++]], scale);
+						LLVector4a v3; v3.setMul(face.mPositions[face.mIndices[k++]], scale);
 
+						if (ll_is_degenerate(v1,v2,v3))
+						{
+							has_degenerate = true;
+						}
+					}
+				}
+			}
+		}
+	}
+	
 	mFMP->childSetTextArg("submeshes_info", "[SUBMESHES]", llformat("%d", total_submeshes[LLModel::LOD_HIGH]));
 
 	std::string mesh_status_na = mFMP->getString("mesh_status_na");
@@ -3885,7 +4012,10 @@ void LLModelPreview::updateStatusMessages()
 
 		for (U32 j = 0; upload_ok && j < mdl->mPhysics.mHull.size(); ++j)
 		{
-			upload_ok = upload_ok && mdl->mPhysics.mHull[i].size() <= 256;
+			if (mdl->mPhysics.mHull[j].size() > 256)
+			{
+				upload_ok = false;
+			}
 		}
 	}
 
@@ -3909,7 +4039,7 @@ void LLModelPreview::updateStatusMessages()
 	}
 	
 	const BOOL confirmed_checkbox = mFMP->getChild<LLCheckBoxCtrl>("confirm_checkbox")->getValue().asBoolean();
-	if ( upload_ok && !errorStateFromLoader && skinAndRigOk && confirmed_checkbox)
+	if ( upload_ok && !errorStateFromLoader && skinAndRigOk && !has_degenerate && confirmed_checkbox)
 	{
 		mFMP->childEnable("ok_btn");
 	}
@@ -4695,6 +4825,32 @@ BOOL LLModelPreview::render()
 							glLineWidth(3.f);
 							glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 							buffer->drawRange(LLRender::TRIANGLES, 0, buffer->getNumVerts()-1, buffer->getNumIndices(), 0);
+
+							{ //show degenerate triangles
+								LLStrider<LLVector3> pos_strider; 
+								buffer->getVertexStrider(pos_strider, 0);
+								LLVector4a* pos = (LLVector4a*) pos_strider.get();
+							
+								LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+								LLGLDisable cull(GL_CULL_FACE);
+								LLStrider<U16> idx;
+								buffer->getIndexStrider(idx, 0);
+
+								glColor4f(1.f,0.f,0.f,1.f);
+								const LLVector4a scale(0.5f);
+								for (U32 i = 0; i < buffer->getNumIndices(); i += 3)
+								{
+									LLVector4a v1; v1.setMul(pos[*idx++], scale);
+									LLVector4a v2; v2.setMul(pos[*idx++], scale);
+									LLVector4a v3; v3.setMul(pos[*idx++], scale);
+
+									if (ll_is_degenerate(v1,v2,v3))
+									{
+										buffer->draw(LLRender::TRIANGLES, 3, i);
+									}
+								}
+							}
+
 							glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 							glLineWidth(1.f);
 						}
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 12e0b26fed5872819371dc5ad01cce8d305c6ea6..d8024b362e85b56d16f525d7f15639339e4f3260 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -62,6 +62,8 @@
 #include "llinventorymodel.h"
 #include "llfoldertype.h"
 
+#include "boost/lexical_cast.hpp"
+
 #ifndef LL_WINDOWS
 #include "netdb.h"
 #endif
@@ -85,6 +87,12 @@ U32 LLMeshRepository::sPeakKbps = 0;
 
 const U32 MAX_TEXTURE_UPLOAD_RETRIES = 5;
 
+static S32 dump_num = 0;
+std::string make_dump_name(std::string prefix, S32 num)
+{
+	return prefix + boost::lexical_cast<std::string>(num) + std::string(".xml");
+	
+}
 void dumpLLSDToFile(const LLSD& content, std::string filename);
 
 std::string header_lod[] = 
@@ -498,7 +506,7 @@ class LLWholeModelFeeResponder: public LLCurl::Responder
 		//assert_main_thread();
 		llinfos << "completed" << llendl;
 		mThread->mPendingUploads--;
-		dumpLLSDToFile(content,"whole_model_fee_response.xml");
+		dumpLLSDToFile(content,make_dump_name("whole_model_fee_response_",dump_num));
 		if (isGoodStatus(status))
 		{
 			mThread->mWholeModelUploadURL = content["uploader"].asString(); 
@@ -530,7 +538,7 @@ class LLWholeModelUploadResponder: public LLCurl::Responder
 		//assert_main_thread();
 		llinfos << "upload completed" << llendl;
 		mThread->mPendingUploads--;
-		dumpLLSDToFile(content,"whole_model_upload_response.xml");
+		dumpLLSDToFile(content,make_dump_name("whole_model_upload_response_",dump_num));
 		// requested "mesh" asset type isn't actually the type
 		// of the resultant object, fix it up here.
 		mPostData["asset_type"] = "object";
@@ -829,8 +837,8 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id)
 
 	if (header_size > 0)
 	{
-		S32 offset = header_size + mMeshHeader[mesh_id]["decomposition"]["offset"].asInteger();
-		S32 size = mMeshHeader[mesh_id]["decomposition"]["size"].asInteger();
+		S32 offset = header_size + mMeshHeader[mesh_id]["physics_convex"]["offset"].asInteger();
+		S32 size = mMeshHeader[mesh_id]["physics_convex"]["size"].asInteger();
 
 		mHeaderMutex->unlock();
 
@@ -901,8 +909,8 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id)
 
 	if (header_size > 0)
 	{
-		S32 offset = header_size + mMeshHeader[mesh_id]["physics_shape"]["offset"].asInteger();
-		S32 size = mMeshHeader[mesh_id]["physics_shape"]["size"].asInteger();
+		S32 offset = header_size + mMeshHeader[mesh_id]["physics_mesh"]["offset"].asInteger();
+		S32 size = mMeshHeader[mesh_id]["physics_mesh"]["size"].asInteger();
 
 		mHeaderMutex->unlock();
 
@@ -1385,14 +1393,14 @@ BOOL LLMeshUploadThread::isDiscarded()
 
 void LLMeshUploadThread::run()
 {
-	if (gSavedSettings.getBOOL("MeshUseWholeModelUpload"))
+	//if (gSavedSettings.getBOOL("MeshUseWholeModelUpload"))
 	{
 		doWholeModelUpload();
 	}
-	else
+	/*else
 	{
 		doIterativeUpload();
-	}
+	}*/
 }
 
 void dumpLLSDToFile(const LLSD& content, std::string filename)
@@ -1431,9 +1439,13 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
 	{
 		LLMeshUploadData data;
 		data.mBaseModel = iter->first;
-		LLModelInstance& instance = *(iter->second.begin());
-		LLModel* model = instance.mModel;
-		if (mesh_index.find(model) == mesh_index.end())
+		LLModelInstance& first_instance = *(iter->second.begin());
+		for (S32 i = 0; i < 5; i++)
+		{
+			data.mModel[i] = first_instance.mLOD[i];
+		}
+
+		if (mesh_index.find(data.mBaseModel) == mesh_index.end())
 		{
 			// Have not seen this model before - create a new mesh_list entry for it.
 			std::string model_name = data.mBaseModel->getName();
@@ -1466,107 +1478,116 @@ void LLMeshUploadThread::wholeModelToLLSD(LLSD& dest, bool include_textures)
 			std::string str = ostr.str();
 
 			res["mesh_list"][mesh_num] = LLSD::Binary(str.begin(),str.end()); 
-			mesh_index[model] = mesh_num;
+			mesh_index[data.mBaseModel] = mesh_num;
 			mesh_num++;
 		}
+
+		// For all instances that use this model
+		for (instance_list::iterator instance_iter = iter->second.begin();
+			 instance_iter != iter->second.end();
+			 ++instance_iter)
+		{
+
+			LLModelInstance& instance = *instance_iter;
 		
-		LLSD instance_entry;
+			LLSD instance_entry;
 		
-		for (S32 i = 0; i < 5; i++)
-		{
-			data.mModel[i] = instance.mLOD[i];
-		}
+			for (S32 i = 0; i < 5; i++)
+			{
+				data.mModel[i] = instance.mLOD[i];
+			}
 		
-		LLVector3 pos, scale;
-		LLQuaternion rot;
-		LLMatrix4 transformation = instance.mTransform;
-		decomposeMeshMatrix(transformation,pos,rot,scale);
-		instance_entry["position"] = ll_sd_from_vector3(pos);
-		instance_entry["rotation"] = ll_sd_from_quaternion(rot);
-		instance_entry["scale"] = ll_sd_from_vector3(scale);
+			LLVector3 pos, scale;
+			LLQuaternion rot;
+			LLMatrix4 transformation = instance.mTransform;
+			decomposeMeshMatrix(transformation,pos,rot,scale);
+			instance_entry["position"] = ll_sd_from_vector3(pos);
+			instance_entry["rotation"] = ll_sd_from_quaternion(rot);
+			instance_entry["scale"] = ll_sd_from_vector3(scale);
 		
-		instance_entry["material"] = LL_MCODE_WOOD;
-		LLPermissions perm;
-		perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false);
-		perm.setCreator(gAgent.getID());
+			instance_entry["material"] = LL_MCODE_WOOD;
+			LLPermissions perm;
+			perm.setOwnerAndGroup(gAgent.getID(), gAgent.getID(), LLUUID::null, false);
+			perm.setCreator(gAgent.getID());
 		
-		perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base
-					   PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner
-					   LLFloaterPerms::getEveryonePerms(),
-					   LLFloaterPerms::getGroupPerms(),
-					   LLFloaterPerms::getNextOwnerPerms());
-		instance_entry["permissions"] = ll_create_sd_from_permissions(perm);
-		instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
-		instance_entry["mesh"] = mesh_index[model];
+			perm.initMasks(PERM_ITEM_UNRESTRICTED | PERM_MOVE, //base
+						   PERM_ITEM_UNRESTRICTED | PERM_MOVE, //owner
+						   LLFloaterPerms::getEveryonePerms(),
+						   LLFloaterPerms::getGroupPerms(),
+						   LLFloaterPerms::getNextOwnerPerms());
+			instance_entry["permissions"] = ll_create_sd_from_permissions(perm);
+			instance_entry["physics_shape_type"] = (U8)(LLViewerObject::PHYSICS_SHAPE_CONVEX_HULL);
+			instance_entry["mesh"] = mesh_index[data.mBaseModel];
 
-		if (mUploadTextures)
-		{
 			instance_entry["face_list"] = LLSD::emptyArray();
 
-			for (S32 face_num = 0; face_num < model->getNumVolumeFaces(); face_num++)
+			for (S32 face_num = 0; face_num < data.mBaseModel->getNumVolumeFaces(); face_num++)
 			{
 				LLImportMaterial& material = instance.mMaterial[face_num];
 				LLSD face_entry = LLSD::emptyMap();
 				LLViewerFetchedTexture *texture = material.mDiffuseMap.get();
 				
-				if (texture != NULL)
+				if ((texture != NULL) &&
+					(textures.find(texture) == textures.end()))
 				{
-					if (textures.find(texture) == textures.end())
-					{
-						textures.insert(texture);
-					}
+					textures.insert(texture);
+				}
 
-					std::stringstream ostr;
-					if (include_textures) // otherwise data is blank.
+				std::stringstream texture_str;
+				if (texture != NULL && include_textures && mUploadTextures)
+				{
+					// Get binary rep of texture, if needed.
+					LLTextureUploadData data(texture, material.mDiffuseMapLabel);
+					if (!data.mTexture->isRawImageValid())
 					{
-						LLTextureUploadData data(texture, material.mDiffuseMapLabel);
-						if (!data.mTexture->isRawImageValid())
-						{
-							data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel());
-						}
-						
-						LLPointer<LLImageJ2C> upload_file =
-							LLViewerTextureList::convertToUploadFile(data.mTexture->getRawImage());
-						ostr.write((const char*) upload_file->getData(), upload_file->getDataSize());
+						data.mTexture->reloadRawImage(data.mTexture->getDiscardLevel());
 					}
+						
+					LLPointer<LLImageJ2C> upload_file =
+						LLViewerTextureList::convertToUploadFile(data.mTexture->getRawImage());
+					texture_str.write((const char*) upload_file->getData(), upload_file->getDataSize());
+				}
 
-					if (texture_index.find(texture) == texture_index.end())
-					{
-						texture_index[texture] = texture_num;
-						std::string str = ostr.str();
-						res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
-						texture_num++;
-					}
+				if (texture != NULL &&
+					mUploadTextures &&
+					texture_index.find(texture) == texture_index.end())
+				{
+					texture_index[texture] = texture_num;
+					std::string str = texture_str.str();
+					res["texture_list"][texture_num] = LLSD::Binary(str.begin(),str.end());
+					texture_num++;
 				}
 
 				// Subset of TextureEntry fields.
-				if (texture)
+				if (texture != NULL && mUploadTextures)
 				{
 					face_entry["image"] = texture_index[texture];
+					face_entry["scales"] = 1.0;
+					face_entry["scalet"] = 1.0;
+					face_entry["offsets"] = 0.0;
+					face_entry["offsett"] = 0.0;
+					face_entry["imagerot"] = 0.0;
 				}
-				face_entry["scales"] = 1.0;
-				face_entry["scalet"] = 1.0;
-				face_entry["offsets"] = 0.0;
-				face_entry["offsett"] = 0.0;
-				face_entry["imagerot"] = 0.0;
 				face_entry["colors"] = ll_sd_from_color4(material.mDiffuseColor);
 				face_entry["fullbright"] = material.mFullbright;
 				instance_entry["face_list"][face_num] = face_entry;
-			}
-		}
+		    }
 
-		res["instance_list"][instance_num] = instance_entry;
-		instance_num++;
+			res["instance_list"][instance_num] = instance_entry;
+			instance_num++;
+		}
 	}
 
 	result["asset_resources"] = res;
-	dumpLLSDToFile(result,"whole_model.xml");
+	dumpLLSDToFile(result,make_dump_name("whole_model_",dump_num));
 
 	dest = result;
 }
 
 void LLMeshUploadThread::doWholeModelUpload()
 {
+	dump_num++;
+	
 	mCurlRequest = new LLCurlRequest();	
 
 	// Queue up models for hull generation (viewer-side)
@@ -1611,7 +1632,7 @@ void LLMeshUploadThread::doWholeModelUpload()
 
 	LLSD model_data;
 	wholeModelToLLSD(model_data,false);
-	dumpLLSDToFile(model_data,"whole_model_fee_request.xml");
+	dumpLLSDToFile(model_data,make_dump_name("whole_model_fee_request_",dump_num));
 
 	mPendingUploads++;
 	LLCurlRequest::headers_t headers;
@@ -1633,7 +1654,7 @@ void LLMeshUploadThread::doWholeModelUpload()
 		LLSD full_model_data;
 		wholeModelToLLSD(full_model_data, true);
 		LLSD body = full_model_data["asset_resources"];
-		dumpLLSDToFile(body,"whole_model_body.xml");
+		dumpLLSDToFile(body,make_dump_name("whole_model_body_",dump_num));
 		mCurlRequest->post(mWholeModelUploadURL, headers, body,
 						   new LLWholeModelUploadResponder(this, model_data));
 		do
@@ -2234,7 +2255,7 @@ void LLMeshHeaderResponder::completedRaw(U32 status, const std::string& reason,
 		
 		//just in case skin info or decomposition is at the end of the file (which it shouldn't be)
 		lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger());
-		lod_bytes = llmax(lod_bytes, header["decomposition"]["offset"].asInteger() + header["decomposition"]["size"].asInteger());
+		lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger());
 
 		S32 header_bytes = (S32) gMeshRepo.mThread->mMeshHeaderSize[mesh_id];
 		S32 bytes = lod_bytes + header_bytes; 
@@ -2860,7 +2881,7 @@ void LLMeshRepository::buildHull(const LLVolumeParams& params, S32 detail)
 bool LLMeshRepository::hasPhysicsShape(const LLUUID& mesh_id)
 {
 	LLSD mesh = mThread->getMeshHeader(mesh_id);
-	return mesh.has("physics_shape") && mesh["physics_shape"].has("size") && (mesh["physics_shape"]["size"].asInteger() > 0);
+	return mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0);
 }
 
 LLSD& LLMeshRepository::getMeshHeader(const LLUUID& mesh_id)
@@ -3314,8 +3335,8 @@ bool LLImportMaterial::operator<(const LLImportMaterial &rhs) const
 void LLMeshRepository::updateInventory(inventory_data data)
 {
 	LLMutexLock lock(mMeshMutex);
-	dumpLLSDToFile(data.mPostData,"update_inventory_post_data.xml");
-	dumpLLSDToFile(data.mResponse,"update_inventory_response.xml");
+	dumpLLSDToFile(data.mPostData,make_dump_name("update_inventory_post_data_",dump_num));
+	dumpLLSDToFile(data.mResponse,make_dump_name("update_inventory_response_",dump_num));
 	mInventoryQ.push(data);
 }