diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 7a2f06da8facdb86770ccd82ac8178d325ed388d..dc360818d69b5cf3a964eb9e14ad36f233d51cbb 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -2143,56 +2143,6 @@ bool LLVolumeFace::VertexData::compareNormal(const LLVolumeFace::VertexData& rhs
 	return retval;
 }
 
-BOOL LLVolume::createVolumeFacesFromFile(const std::string& file_name)
-{
-	std::ifstream is;
-	
-	is.open(file_name.c_str(), std::ifstream::in | std::ifstream::binary);
-
-	BOOL success = createVolumeFacesFromStream(is);
-	
-	is.close();
-
-	return success;
-}
-
-BOOL LLVolume::createVolumeFacesFromStream(std::istream& is)
-{
-	mSculptLevel = -1;  // default is an error occured
-
-	LLSD header;
-	{
-		if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
-		{
-			llwarns << "Mesh header parse error.  Not a valid mesh asset!" << llendl;
-			return FALSE;
-		}
-	}
-	
-	std::string nm[] = 
-	{
-		"lowest_lod",
-		"low_lod",
-		"medium_lod",
-		"high_lod",
-		"physics_shape",
-	};
-
-	const S32 MODEL_LODS = 5;
-
-	S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS);
-
-	if (header[nm[lod]]["offset"].asInteger() == -1 || 
-		header[nm[lod]]["size"].asInteger() == 0 )
-	{ //cannot load requested LOD
-		return FALSE;
-	}
-
-	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
-
-	return unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger());
-}
-
 bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 {
 	//input stream is now pointing at a zlib compressed block of LLSD
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index 60b64b1285426f6921b37a7f2221490882dbda94..01bfbd858be72fd6badd82b8e0e335f68b682eba 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -1048,8 +1048,6 @@ class LLVolume : public LLRefCount
 	BOOL generate();
 	void createVolumeFaces();
 public:
-	virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
-	virtual BOOL createVolumeFacesFromStream(std::istream& is);
 	virtual bool unpackVolumeFaces(std::istream& is, S32 size);
 
 	virtual void makeTetrahedron();
diff --git a/indra/llprimitive/llmodel.cpp b/indra/llprimitive/llmodel.cpp
index 3669fef0dc8a1af039f06e64afa19ee3d99cb819..595f9aa30719f087112d5a5299587073f2f5534e 100755
--- a/indra/llprimitive/llmodel.cpp
+++ b/indra/llprimitive/llmodel.cpp
@@ -775,43 +775,6 @@ BOOL LLModel::createVolumeFacesFromDomMesh(domMesh* mesh)
 	return FALSE;
 }
 
-
-BOOL LLModel::createVolumeFacesFromFile(const std::string& file_name)
-{
-	DAE dae;
-	domCOLLADA* dom = dae.open(file_name);
-	if (dom)
-	{
-		daeDatabase* db = dae.getDatabase();
-
-		daeInt count = db->getElementCount(NULL, COLLADA_TYPE_MESH);
-		
-		mVolumeFaces.clear();
-		mMaterialList.clear();
-
-		for (daeInt idx = 0; idx < count; ++idx)
-		{
-			domMesh* mesh = NULL;
-
-			db->getElement((daeElement**) &mesh, idx, NULL, COLLADA_TYPE_MESH);
-			
-			if (mesh)
-			{
-				addVolumeFacesFromDomMesh(mesh);
-			}
-		}
-
-		if (getNumVolumeFaces() > 0)
-		{
-			optimizeVolumeFaces();
-			normalizeVolumeFaces();
-			return TRUE;
-		}
-	}
-
-	return FALSE;
-}
-
 void LLModel::offsetMesh( const LLVector3& pivotPoint )
 {
 	LLVector4a pivot( pivotPoint[VX], pivotPoint[VY], pivotPoint[VZ] );
@@ -1351,16 +1314,6 @@ std::string LLModel::getElementLabel(daeElement *element)
 	return std::string("object");
 }
 
-//static 
-LLModel* LLModel::loadModelFromDae(std::string filename)
-{
-	LLVolumeParams volume_params;
-	volume_params.setType(LL_PCODE_PROFILE_SQUARE, LL_PCODE_PATH_LINE);
-	LLModel* ret = new LLModel(volume_params, 0.f); 
-	ret->createVolumeFacesFromFile(filename);
-	return ret;
-}
-
 //static 
 LLModel* LLModel::loadModelFromDomMesh(domMesh *mesh)
 {
@@ -1473,49 +1426,7 @@ LLSD LLModel::writeModel(
 
 	if (skinning)
 	{ //write skinning block
-		if (high->mJointList.size() != high->mInvBindMatrix.size())
-		{
-			llerrs << "WTF?" << llendl;
-		}
-
-		for (U32 i = 0; i < high->mJointList.size(); ++i)
-		{
-			mdl["skin"]["joint_names"][i] = high->mJointList[i];
-
-			for (U32 j = 0; j < 4; j++)
-			{
-				for (U32 k = 0; k < 4; k++)
-				{
-					mdl["skin"]["inverse_bind_matrix"][i][j*4+k] = high->mInvBindMatrix[i].mMatrix[j][k]; 
-				}
-			}
-		}
-
-		for (U32 i = 0; i < 4; i++)
-		{
-			for (U32 j = 0; j < 4; j++)
-			{
-				mdl["skin"]["bind_shape_matrix"][i*4+j] = high->mBindShapeMatrix.mMatrix[i][j];
-			}
-		}
-		
-		
-		if ( upload_joints && high->mAlternateBindMatrix.size() > 0 )
-		{
-			for (U32 i = 0; i < high->mJointList.size(); ++i)
-			{
-				for (U32 j = 0; j < 4; j++)
-				{
-					for (U32 k = 0; k < 4; k++)
-					{
-						mdl["skin"]["alt_inverse_bind_matrix"][i][j*4+k] = high->mAlternateBindMatrix[i].mMatrix[j][k]; 
-					}
-				}
-			}
-
-			mdl["skin"]["pelvis_offset"] = high->mPelvisOffset;
-		}
-		
+		mdl["skin"] = high->mSkinInfo.asLLSD(upload_joints);
 	}
 
 	if (!decomp.empty() || !base_hull.empty())
@@ -1897,12 +1808,6 @@ LLSD LLModel::writeModelToStream(std::ostream& ostr, LLSD& mdl, BOOL nowrite)
 	return header;
 }
 
-//static 
-LLModel* LLModel::loadModelFromAsset(std::string filename, S32 lod)
-{
-	return NULL;
-}
-
 LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
 {
 	weight_map::iterator iter = mSkinWeights.find(pos);
@@ -1976,27 +1881,380 @@ LLModel::weight_list& LLModel::getJointInfluences(const LLVector3& pos)
 void LLModel::setConvexHullDecomposition(
 	const LLModel::convex_hull_decomposition& decomp)
 {
-	mConvexHullDecomp = decomp;
+	mPhysics.mHull = decomp;
+	mPhysics.mMesh.clear();
+	updateHullCenters();
+}
 
-	mHullCenter.resize(mConvexHullDecomp.size());
+void LLModel::updateHullCenters()
+{
+	mHullCenter.resize(mPhysics.mHull.size());
 	mHullPoints = 0;
 	mCenterOfHullCenters.clear();
 
-	for (U32 i = 0; i < decomp.size(); ++i)
+	for (U32 i = 0; i < mPhysics.mHull.size(); ++i)
 	{
 		LLVector3 cur_center;
 
-		for (U32 j = 0; j < decomp[i].size(); ++j)
+		for (U32 j = 0; j < mPhysics.mHull[i].size(); ++j)
 		{
-			cur_center += decomp[i][j];
+			cur_center += mPhysics.mHull[i][j];
 		}
 		mCenterOfHullCenters += cur_center;
-		cur_center *= 1.f/decomp[i].size();
+		cur_center *= 1.f/mPhysics.mHull[i].size();
 		mHullCenter[i] = cur_center;
-		mHullPoints += decomp[i].size();
+		mHullPoints += mPhysics.mHull[i].size();
 	}
 
 	mCenterOfHullCenters *= 1.f / mHullPoints;
 }
 
+bool LLModel::loadModel(std::istream& is)
+{
+	mSculptLevel = -1;  // default is an error occured
+
+	LLSD header;
+	{
+		if (!LLSDSerialize::fromBinary(header, is, 1024*1024*1024))
+		{
+			llwarns << "Mesh header parse error.  Not a valid mesh asset!" << llendl;
+			return false;
+		}
+	}
+	
+	std::string nm[] = 
+	{
+		"lowest_lod",
+		"low_lod",
+		"medium_lod",
+		"high_lod",
+		"physics_shape",
+	};
+
+	const S32 MODEL_LODS = 5;
+
+	S32 lod = llclamp((S32) mDetail, 0, MODEL_LODS);
+
+	if (header[nm[lod]]["offset"].asInteger() == -1 || 
+		header[nm[lod]]["size"].asInteger() == 0 )
+	{ //cannot load requested LOD
+		return false;
+	}
+
+	bool has_skin = header["skin"]["offset"].asInteger() >=0 &&
+					header["skin"]["size"].asInteger() > 0;
+
+	if (lod == LLModel::LOD_HIGH)
+	{ //try to load skin info and decomp info
+		std::ios::pos_type cur_pos = is.tellg();
+		loadSkinInfo(header, is);
+		is.seekg(cur_pos);
+	}
+
+	if (lod == LLModel::LOD_PHYSICS)
+	{
+		std::ios::pos_type cur_pos = is.tellg();
+		loadDecomposition(header, is);
+		is.seekg(cur_pos);
+	}
+
+	is.seekg(header[nm[lod]]["offset"].asInteger(), std::ios_base::cur);
+
+	if (unpackVolumeFaces(is, header[nm[lod]]["size"].asInteger()))
+	{
+		if (has_skin)
+		{ 
+			//build out mSkinWeight from face info
+			for (S32 i = 0; i < getNumVolumeFaces(); ++i)
+			{
+				const LLVolumeFace& face = getVolumeFace(i);
+
+				if (face.mWeights)
+				{
+					for (S32 j = 0; j < face.mNumVertices; ++j)
+					{
+						LLVector4a& w = face.mWeights[j];
+
+						std::vector<JointWeight> wght;
+
+						for (S32 k = 0; k < 4; ++k)
+						{
+							S32 idx = (S32) w[k];
+							F32 f = w[k] - idx;
+							if (f > 0.f)
+							{
+								wght.push_back(JointWeight(idx, f));
+							}
+						}
+
+						if (!wght.empty())
+						{
+							LLVector3 pos(face.mPositions[j].getF32ptr());
+							mSkinWeights[pos] = wght;
+						}
+					}
+				}
+			}
+		}
+		return true;
+	}
+
+	return false;
+
+}
+
+
+bool LLModel::loadSkinInfo(LLSD& header, std::istream &is)
+{
+	S32 offset = header["skin"]["offset"].asInteger();
+	S32 size = header["skin"]["size"].asInteger();
+
+	if (offset >= 0 && size > 0)
+	{
+		is.seekg(offset, std::ios_base::cur);
+
+		LLSD skin_data;
+
+		if (unzip_llsd(skin_data, is, size))
+		{
+			mSkinInfo.fromLLSD(skin_data);
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool LLModel::loadDecomposition(LLSD& header, std::istream& is)
+{
+	S32 offset = header["decomposition"]["offset"].asInteger();
+	S32 size = header["decomposition"]["size"].asInteger();
+
+	if (offset >= 0 && size > 0)
+	{
+		is.seekg(offset, std::ios_base::cur);
+
+		LLSD data;
+
+		if (unzip_llsd(data, is, size))
+		{
+			mPhysics.fromLLSD(data);
+			updateHullCenters();
+		}
+	}
+
+	return true;
+}
+
+
+LLMeshSkinInfo::LLMeshSkinInfo(LLSD& skin)
+{
+	fromLLSD(skin);
+}
+
+void LLMeshSkinInfo::fromLLSD(LLSD& skin)
+{
+	if (skin.has("joint_names"))
+	{
+		for (U32 i = 0; i < skin["joint_names"].size(); ++i)
+		{
+			mJointNames.push_back(skin["joint_names"][i]);
+		}
+	}
+
+	if (skin.has("inverse_bind_matrix"))
+	{
+		for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i)
+		{
+			LLMatrix4 mat;
+			for (U32 j = 0; j < 4; j++)
+			{
+				for (U32 k = 0; k < 4; k++)
+				{
+					mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal();
+				}
+			}
+
+			mInvBindMatrix.push_back(mat);
+		}
+	}
+
+	if (skin.has("bind_shape_matrix"))
+	{
+		for (U32 j = 0; j < 4; j++)
+		{
+			for (U32 k = 0; k < 4; k++)
+			{
+				mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal();
+			}
+		}
+	}
+
+	if (skin.has("alt_inverse_bind_matrix"))
+	{
+		for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i)
+		{
+			LLMatrix4 mat;
+			for (U32 j = 0; j < 4; j++)
+			{
+				for (U32 k = 0; k < 4; k++)
+				{
+					mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal();
+				}
+			}
+			
+			mAlternateBindMatrix.push_back(mat);
+		}
+	}
+
+	if (skin.has("pelvis_offset"))
+	{
+		mPelvisOffset = skin["pelvis_offset"].asReal();
+	}
+}
+
+LLSD LLMeshSkinInfo::asLLSD(bool include_joints) const
+{
+	LLSD ret;
+
+	for (U32 i = 0; i < mJointNames.size(); ++i)
+	{
+		ret["joint_names"][i] = mJointNames[i];
+
+		for (U32 j = 0; j < 4; j++)
+		{
+			for (U32 k = 0; k < 4; k++)
+			{
+				ret["inverse_bind_matrix"][i][j*4+k] = mInvBindMatrix[i].mMatrix[j][k]; 
+			}
+		}
+	}
+
+	for (U32 i = 0; i < 4; i++)
+	{
+		for (U32 j = 0; j < 4; j++)
+		{
+			ret["bind_shape_matrix"][i*4+j] = mBindShapeMatrix.mMatrix[i][j];
+		}
+	}
+		
+	if ( include_joints && mAlternateBindMatrix.size() > 0 )
+	{
+		for (U32 i = 0; i < mJointNames.size(); ++i)
+		{
+			for (U32 j = 0; j < 4; j++)
+			{
+				for (U32 k = 0; k < 4; k++)
+				{
+					ret["alt_inverse_bind_matrix"][i][j*4+k] = mAlternateBindMatrix[i].mMatrix[j][k]; 
+				}
+			}
+		}
+
+		ret["pelvis_offset"] = mPelvisOffset;
+	}
+
+	return ret;
+}
+
+LLModel::Decomposition::Decomposition(LLSD& data)
+{
+	fromLLSD(data);
+}
+
+void LLModel::Decomposition::fromLLSD(LLSD& decomp)
+{
+	if (decomp.has("HullList"))
+	{
+		// 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();
+
+		U16* p = (U16*) &position[0];
+
+		mHull.resize(hulls.size());
+
+		LLVector3 min;
+		LLVector3 max;
+		LLVector3 range;
+
+		min.setValue(decomp["Min"]);
+		max.setValue(decomp["Max"]);
+		range = max-min;
+
+		for (U32 i = 0; i < hulls.size(); ++i)
+		{
+			U16 count = (hulls[i] == 0) ? 256 : hulls[i];
+			
+			for (U32 j = 0; j < count; ++j)
+			{
+				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],
+					(F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
+				p += 3;
+			}		 
+
+		}
+	}
+
+	if (decomp.has("Hull"))
+	{
+		const LLSD::Binary& position = decomp["Hull"].asBinary();
+
+		U16* p = (U16*) &position[0];
+
+		LLVector3 min;
+		LLVector3 max;
+		LLVector3 range;
+
+		min.setValue(decomp["Min"]);
+		max.setValue(decomp["Max"]);
+		range = max-min;
+
+		U16 count = position.size()/6;
+		
+		for (U32 j = 0; j < count; ++j)
+		{
+			mBaseHull.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],
+				(F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
+			p += 3;
+		}		 
+	}
+	else
+	{
+		//empty base hull mesh to indicate decomposition has been loaded
+		//but contains no base hull
+		mBaseHullMesh.clear();;
+	}
+
+}
+
+void LLModel::Decomposition::merge(const LLModel::Decomposition* rhs)
+{
+	if (!rhs)
+	{
+		return;
+	}
+
+	if (mMeshID != rhs->mMeshID)
+	{
+		llerrs << "Attempted to merge with decomposition of some other mesh." << llendl;
+	}
+
+	if (mBaseHull.empty())
+	{ //take base hull and decomposition from rhs
+		mHull = rhs->mHull;
+		mBaseHull = rhs->mBaseHull;
+		mMesh = rhs->mMesh;
+		mBaseHullMesh = rhs->mBaseHullMesh;
+	}
+
+	if (mPhysicsShapeMesh.empty())
+	{ //take physics shape mesh from rhs
+		mPhysicsShapeMesh = rhs->mPhysicsShapeMesh;
+	}
+}
 
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index addf527d8df5c965f03505c624f69f9d9e525868..e9450d29678da12c3b7e3cec1788a9ff74e3bf19 100755
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -27,6 +27,7 @@
 #ifndef LL_LLMODEL_H
 #define LL_LLMODEL_H
 
+#include "llpointer.h"
 #include "llvolume.h"
 #include "v4math.h"
 #include "m4math.h"
@@ -36,6 +37,24 @@ class domMesh;
 
 #define MAX_MODEL_FACES 8
 
+
+class LLMeshSkinInfo 
+{
+public:
+	LLUUID mMeshID;
+	std::vector<std::string> mJointNames;
+	std::vector<LLMatrix4> mInvBindMatrix;
+	std::vector<LLMatrix4> mAlternateBindMatrix;
+	std::map<std::string, U32> mJointMap;
+
+	LLMeshSkinInfo() { }
+	LLMeshSkinInfo(LLSD& data);
+	void fromLLSD(LLSD& data);
+	LLSD asLLSD(bool include_joints) const;
+	LLMatrix4 mBindShapeMatrix;
+	float mPelvisOffset;
+};
+
 class LLModel : public LLVolume
 {
 public:
@@ -58,6 +77,9 @@ class LLModel : public LLVolume
 	LLModel(LLVolumeParams& params, F32 detail);
 	~LLModel();
 
+	bool loadModel(std::istream& is);
+	bool loadSkinInfo(LLSD& header, std::istream& is);
+	bool loadDecomposition(LLSD& header, std::istream& is);
 	static LLSD writeModel(
 		std::string filename,
 		LLModel* physics,
@@ -98,8 +120,6 @@ class LLModel : public LLVolume
 		LLSD& mdl,
 		BOOL nowrite = FALSE);
 
-	static LLModel* loadModelFromAsset(std::string filename, S32 lod);
-	static LLModel* loadModelFromDae(std::string filename);
 	static LLModel* loadModelFromDomMesh(domMesh* mesh);
 	static std::string getElementLabel(daeElement* element);
 	std::string getName() const;
@@ -177,17 +197,8 @@ class LLModel : public LLVolume
 	//get list of weight influences closest to given position
 	weight_list& getJointInfluences(const LLVector3& pos);
 
-	//should always be true that mJointList[mJointMap["foo"]] == "foo"
-
-	//map of joint names to joint index
-	std::map<std::string, U32> mJointMap;
-
-	//list of joint names
-	std::vector<std::string> mJointList;
-
-	LLMatrix4 mBindShapeMatrix;
-	std::vector<LLMatrix4> mInvBindMatrix;
-	std::vector<LLMatrix4> mAlternateBindMatrix;
+	LLMeshSkinInfo mSkinInfo;
+	
 	std::string mRequestedLabel; // name requested in UI, if any.
 	std::string mLabel; // name computed from dae.
 
@@ -197,9 +208,10 @@ class LLModel : public LLVolume
 	float	mPelvisOffset;
 	// convex hull decomposition
 	S32 mDecompID;
-	convex_hull_decomposition mConvexHullDecomp;
+	
 	void setConvexHullDecomposition(
 		const convex_hull_decomposition& decomp);
+	void updateHullCenters();
 
 	LLVector3 mCenterOfHullCenters;
 	std::vector<LLVector3> mHullCenter;
@@ -208,9 +220,46 @@ class LLModel : public LLVolume
 	//ID for storing this model in a .slm file
 	S32 mLocalID;
 
+	class PhysicsMesh
+	{
+	public:
+		std::vector<LLVector3> mPositions;
+		std::vector<LLVector3> mNormals;
+
+		void clear()
+		{
+			mPositions.clear();
+			mNormals.clear();
+		}
+
+		bool empty() const
+		{
+			return mPositions.empty();
+		}
+	};
+
+	class Decomposition
+	{
+	public:
+		Decomposition() { }
+		Decomposition(LLSD& data);
+		void fromLLSD(LLSD& data);
+		
+		void merge(const Decomposition* rhs);
+
+		LLUUID mMeshID;
+		LLModel::convex_hull_decomposition mHull;
+		LLModel::hull mBaseHull;
+
+		std::vector<LLModel::PhysicsMesh> mMesh;
+		LLModel::PhysicsMesh mBaseHullMesh;
+		LLModel::PhysicsMesh mPhysicsShapeMesh;
+	};
+
+	Decomposition mPhysics;
+
 protected:
 	void addVolumeFacesFromDomMesh(domMesh* mesh);
-	virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
 	virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);
 };
 
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 0d3f5b81bcc3b698012e5d1f3e5b8d231f362aff..73efbfc9998ea399056523caca5ac5555e589cc0 100644
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -236,6 +236,22 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 	}
 }
 
+//static
+void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm)
+{
+	U32 count = pos.size();
+	llassert(norm.size() >= pos.size());
+
+	unbind();
+	
+	setupClientArrays(MAP_VERTEX | MAP_NORMAL);
+
+	glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
+	glNormalPointer(GL_FLOAT, 0, norm[0].mV);
+
+	glDrawArrays(sGLMode[mode], 0, count);
+}
+
 void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
 {
 	if (start >= (U32) mRequestedNumVerts ||
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 2bbc17fb12a67ed16ad7a5d9be06b736b4124edc..6c0895512ea1e6347c9c9cebc5cde3f8ba9eb4ed 100644
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -97,6 +97,8 @@ class LLVertexBuffer : public LLRefCount
 	static void initClass(bool use_vbo, bool no_vbo_mapping);
 	static void cleanupClass();
 	static void setupClientArrays(U32 data_mask);
+	static void drawArrays(U32 mode, const std::vector<LLVector3>& pos, const std::vector<LLVector3>& norm);
+
  	static void clientCopy(F64 max_time = 0.005); //copy data from client to GL
 	static void unbind(); //unbind any bound vertex buffer
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 4d498840fed231867e91eaf392aa3f8cb88180ee..a2a25105bce3d599b1098f9900f192cf0a4c745e 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -389,7 +389,11 @@ LLFloaterModelPreview::~LLFloaterModelPreview()
 		gAgentAvatarp->resetJointPositions();
 	}
 
+	
+	if ( mModelPreview )
+	{
 	delete mModelPreview;
+	}
 
 	if (mGLName)
 	{
@@ -1326,17 +1330,19 @@ bool LLModelLoader::doLoadModel()
 						{ //get bind shape matrix
 							domFloat4x4& dom_value = bind_mat->getValue();
 							
+							LLMeshSkinInfo& skin_info = model->mSkinInfo;
+
 							for (int i = 0; i < 4; i++)
 							{
 								for(int j = 0; j < 4; j++)
 								{
-									model->mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
+									skin_info.mBindShapeMatrix.mMatrix[i][j] = dom_value[i + j*4];
 								}
 							}
 							
 							LLMatrix4 trans = normalized_transformation;
-							trans *= model->mBindShapeMatrix;
-							model->mBindShapeMatrix = trans;
+							trans *= skin_info.mBindShapeMatrix;
+							skin_info.mBindShapeMatrix = trans;
 							
 						}
 						
@@ -1475,7 +1481,7 @@ bool LLModelLoader::doLoadModel()
 							xsNMTOKEN semantic = input->getSemantic();
 							
 							if (strcmp(semantic, COMMON_PROFILE_INPUT_JOINT) == 0)
-							{ //found joint source, fill model->mJointMap and model->mJointList
+							{ //found joint source, fill model->mJointMap and model->mSkinInfo.mJointNames
 								daeElement* elem = input->getSource().getElement();
 								
 								domSource* source = daeSafeCast<domSource>(elem);
@@ -1496,8 +1502,8 @@ bool LLModelLoader::doLoadModel()
 											{
 												name = mJointMap[name];
 											}
-											model->mJointList.push_back(name);
-											model->mJointMap[name] = j;
+											model->mSkinInfo.mJointNames.push_back(name);
+											model->mSkinInfo.mJointMap[name] = j;
 										}
 									}
 									else
@@ -1514,8 +1520,8 @@ bool LLModelLoader::doLoadModel()
 												{
 													name = mJointMap[name];
 												}
-												model->mJointList.push_back(name);
-												model->mJointMap[name] = j;
+												model->mSkinInfo.mJointNames.push_back(name);
+												model->mSkinInfo.mJointMap[name] = j;
 											}
 										}
 									}
@@ -1544,7 +1550,7 @@ bool LLModelLoader::doLoadModel()
 												}
 											}
 											
-											model->mInvBindMatrix.push_back(mat);
+											model->mSkinInfo.mInvBindMatrix.push_back(mat);
 										}
 									}
 								}
@@ -1555,8 +1561,8 @@ bool LLModelLoader::doLoadModel()
 						//(which means we have all the joints that are required for an avatar versus
 						//a skinned asset attached to a node in a file that contains an entire skeleton,
 						//but does not use the skeleton).
-						mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mJointList ) );
-							if ( !skeletonWithNoRootNode && !model->mJointList.empty() && mPreview->isRigValid() ) 
+						mPreview->setRigValid( doesJointArrayContainACompleteRig( model->mSkinInfo.mJointNames ) );
+						if ( !skeletonWithNoRootNode && !model->mSkinInfo.mJointNames.empty() && mPreview->isRigValid() ) 
 						{
 							mResetJoints = true;
 						}
@@ -1596,8 +1602,8 @@ bool LLModelLoader::doLoadModel()
 						//in the same order as they were stored in the joint buffer. The joints associated
 						//with the skeleton are not stored in the same order as they are in the exported joint buffer.
 						//This remaps the skeletal joints to be in the same order as the joints stored in the model.
-						std::vector<std::string> :: const_iterator jointIt  = model->mJointList.begin();
-						const int jointCnt = model->mJointList.size();
+						std::vector<std::string> :: const_iterator jointIt  = model->mSkinInfo.mJointNames.begin();
+						const int jointCnt = model->mSkinInfo.mJointNames.size();
 						for ( int i=0; i<jointCnt; ++i, ++jointIt )
 						{
 							std::string lookingForJoint = (*jointIt).c_str();
@@ -1606,9 +1612,9 @@ bool LLModelLoader::doLoadModel()
 							if ( jointTransforms.find( lookingForJoint ) != jointTransforms.end() )
 							{
 								LLMatrix4 jointTransform = jointTransforms[lookingForJoint];
-								LLMatrix4 newInverse = model->mInvBindMatrix[i];
+								LLMatrix4 newInverse = model->mSkinInfo.mInvBindMatrix[i];
 								newInverse.setTranslation( jointTransforms[lookingForJoint].getTranslation() );
-								model->mAlternateBindMatrix.push_back( newInverse );
+								model->mSkinInfo.mAlternateBindMatrix.push_back( newInverse );
 							}
 							else
 							{
@@ -1813,10 +1819,15 @@ bool LLModelLoader::loadFromSLM(const std::string& filename)
 		{
 			std::stringstream str(mesh[i].asString());
 			LLPointer<LLModel> loaded_model = new LLModel(volume_params, (F32) lod);
-			if (loaded_model->createVolumeFacesFromStream(str))
+			if (loaded_model->loadModel(str))
 			{
 				loaded_model->mLocalID = i;
 				model[lod].push_back(loaded_model);
+
+				if (lod == LLModel::LOD_HIGH && !loaded_model->mSkinInfo.mJointNames.empty())
+				{ //check to see if rig is valid
+					mPreview->setRigValid( doesJointArrayContainACompleteRig( loaded_model->mSkinInfo.mJointNames ) );
+				}
 			}
 			else
 			{
@@ -1878,8 +1889,6 @@ void LLModelLoader::loadModelCallback()
 	{ //wait until this thread is stopped before deleting self
 		apr_sleep(100);
 	}
-
-	delete this;
 }
 
 void LLModelLoader::handlePivotPoint( daeElement* pRoot )
@@ -2455,6 +2464,7 @@ LLModelPreview::~LLModelPreview()
 {
 	if (mModelLoader)
 	{
+		delete mModelLoader;
 		mModelLoader->mPreview = NULL;
 	}
 	//*HACK : *TODO : turn this back on when we understand why this crashes
@@ -2510,8 +2520,8 @@ U32 LLModelPreview::calcResourceCost()
 
 			LLModel::convex_hull_decomposition& decomp =
 			instance.mLOD[LLModel::LOD_PHYSICS] ?
-			instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp :
-			instance.mModel->mConvexHullDecomp;
+			instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull :
+			instance.mModel->mPhysics.mHull;
 
 			LLSD ret = LLModel::writeModel(
 										   "",
@@ -2729,8 +2739,8 @@ void LLModelPreview::saveUploadData(const std::string& filename, bool save_skinw
 
 			LLModel::convex_hull_decomposition& decomp =
 				instance.mLOD[LLModel::LOD_PHYSICS].notNull() ? 
-				instance.mLOD[LLModel::LOD_PHYSICS]->mConvexHullDecomp : 
-				instance.mModel->mConvexHullDecomp;
+				instance.mLOD[LLModel::LOD_PHYSICS]->mPhysics.mHull : 
+				instance.mModel->mPhysics.mHull;
 
 			LLModel::writeModel(str, 
 				instance.mLOD[LLModel::LOD_PHYSICS], 
@@ -2901,6 +2911,9 @@ void LLModelPreview::loadModelCallback(S32 lod)
 		mBaseModel.clear();
 		mBaseScene.clear();
 
+		bool skin_weights = false;
+		bool joint_positions = false;
+
 		for (S32 lod = 0; lod < LLModel::NUM_LODS; ++lod)
 		{ //for each LoD
 
@@ -2934,11 +2947,39 @@ void LLModelPreview::loadModelCallback(S32 lod)
 						}
 
 						mModel[lod][idx] = list_iter->mModel;	
+						if (!list_iter->mModel->mSkinWeights.empty())
+						{
+							skin_weights = true;
+
+							if (!list_iter->mModel->mSkinInfo.mAlternateBindMatrix.empty())
+							{
+								joint_positions = true;
+							}
+						}
 					}
 				}
 			}
 		}
 
+		if (mFMP)
+		{
+			LLFloaterModelPreview* fmp = (LLFloaterModelPreview*) mFMP;
+
+			if (skin_weights)
+			{ //enable uploading/previewing of skin weights if present in .slm file
+				fmp->enableViewOption("show_skin_weight");
+				mViewOption["show_skin_weight"] = true;
+				fmp->childSetValue("upload_skin", true);
+			}
+
+			if (joint_positions)
+			{ 
+				fmp->enableViewOption("show_joint_positions");
+				mViewOption["show_joint_positions"] = true;
+				fmp->childSetValue("upload_joints", true);
+			}
+		}
+
 		//copy high lod to base scene for LoD generation
 		mBaseScene = mScene[LLModel::LOD_HIGH];
 		mBaseModel = mModel[LLModel::LOD_HIGH];
@@ -2952,14 +2993,8 @@ void LLModelPreview::loadModelCallback(S32 lod)
 		mScene[lod] = mModelLoader->mScene;
 		mVertexBuffer[lod].clear();
 
-		if (lod == LLModel::LOD_PHYSICS)
-		{
-			mPhysicsMesh.clear();
-		}
-
 		setPreviewLOD(lod);
 
-
 		if (lod == LLModel::LOD_HIGH)
 		{ //save a copy of the highest LOD for automatic LOD manipulation
 			if (mBaseModel.empty())
@@ -3082,11 +3117,6 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
 		return;
 	}
 
-	if (which_lod == LLModel::LOD_PHYSICS)
-	{ //clear physics mesh map
-		mPhysicsMesh.clear();
-	}
-
 	LLVertexBuffer::unbind();
 
 	stop_gloderror();
@@ -3415,11 +3445,7 @@ void LLModelPreview::genLODs(S32 which_lod, U32 decimation, bool enforce_tri_lim
 			//of an open problem).
 			target_model->mPosition = base->mPosition;
 			target_model->mSkinWeights = base->mSkinWeights;
-			target_model->mJointMap = base->mJointMap;
-			target_model->mJointList = base->mJointList;
-			target_model->mInvBindMatrix = base->mInvBindMatrix;
-			target_model->mBindShapeMatrix = base->mBindShapeMatrix;
-			target_model->mAlternateBindMatrix = base->mAlternateBindMatrix;
+			target_model->mSkinInfo = base->mSkinInfo;
 			//copy material list
 			target_model->mMaterialList = base->mMaterialList;
 
@@ -3639,7 +3665,7 @@ void LLModelPreview::updateStatusMessages()
 		LLModel* model = mModel[LLModel::LOD_PHYSICS][i];
 		S32 cur_submeshes = model->getNumVolumeFaces();
 
-		LLModel::convex_hull_decomposition& decomp = model->mConvexHullDecomp;
+		LLModel::convex_hull_decomposition& decomp = model->mPhysics.mHull;
 
 		if (!decomp.empty())
 		{
@@ -4276,12 +4302,17 @@ BOOL LLModelPreview::render()
 					{
 						LLMutexLock(decomp->mMutex);
 
-						std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > >::iterator iter =
-							mPhysicsMesh.find(model);
-						if (iter != mPhysicsMesh.end())
+						LLModel::Decomposition& physics = model->mPhysics;
+
+						if (physics.mMesh.empty())
+						{ //build vertex buffer for physics mesh
+							gMeshRepo.buildPhysicsMesh(physics);
+						}
+							
+						if (!physics.mMesh.empty())
 						{ //render hull instead of mesh
 							render_mesh = false;
-							for (U32 i = 0; i < iter->second.size(); ++i)
+							for (U32 i = 0; i < physics.mMesh.size(); ++i)
 							{
 								if (explode > 0.f)
 								{
@@ -4300,14 +4331,8 @@ BOOL LLModelPreview::render()
 									hull_colors.push_back(LLColor4U(rand()%128+127, rand()%128+127, rand()%128+127, 255));
 								}
 
-								LLVertexBuffer* buff = iter->second[i];
-								if (buff)
-								{
-									buff->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL);
-
 									glColor4ubv(hull_colors[i].mV);
-									buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
-								}
+								LLVertexBuffer::drawArrays(LLRender::TRIANGLES, physics.mMesh[i].mPositions, physics.mMesh[i].mNormals);
 
 								if (explode > 0.f)
 								{
@@ -4391,12 +4416,12 @@ BOOL LLModelPreview::render()
 
 							//build matrix palette
 							LLMatrix4 mat[64];
-							for (U32 j = 0; j < model->mJointList.size(); ++j)
+							for (U32 j = 0; j < model->mSkinInfo.mJointNames.size(); ++j)
 							{
-								LLJoint* joint = avatar->getJoint(model->mJointList[j]);
+								LLJoint* joint = avatar->getJoint(model->mSkinInfo.mJointNames[j]);
 								if (joint)
 								{
-									mat[j] = model->mInvBindMatrix[j];
+									mat[j] = model->mSkinInfo.mInvBindMatrix[j];
 									mat[j] *= joint->getWorldMatrix();
 								}
 							}
@@ -4437,7 +4462,7 @@ BOOL LLModelPreview::render()
 								//VECTORIZE THIS
 								LLVector3 v(face.mPositions[j].getF32ptr());
 
-								v = v * model->mBindShapeMatrix;
+								v = v * model->mSkinInfo.mBindShapeMatrix;
 								v = v * final_mat;
 
 								position[j] = v;
@@ -4687,7 +4712,6 @@ void LLFloaterModelPreview::DecompRequest::completed()
 			{
 				if (sInstance->mModelPreview)
 				{
-					sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh;
 					sInstance->mModelPreview->mDirty = true;
 					LLFloaterModelPreview::sInstance->mModelPreview->refresh();
 				}
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index 68fa0fa4c11dc172a0e677d494c54eee56766bf3..6542ed4fbe85d87f001c85db6740a3d921b66b2d 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -358,8 +358,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 	U32 mGroup;
 	std::map<LLPointer<LLModel>, U32> mObject;
 	U32 mMaxTriangleLimit;
-	std::map<LLPointer<LLModel>, std::vector<LLPointer<LLVertexBuffer> > > mPhysicsMesh;
-
+	
 	LLMeshUploadThread::instance_list mUploadData;
 	std::set<LLViewerFetchedTexture* > mTextureSet;
 
diff --git a/indra/newview/llfloatermodelwizard.cpp b/indra/newview/llfloatermodelwizard.cpp
index 9751b87b4c032f1adc52cac011d608fcbe41471e..532c6789bb4b6987666100b0878ce5abc0a6ca0e 100644
--- a/indra/newview/llfloatermodelwizard.cpp
+++ b/indra/newview/llfloatermodelwizard.cpp
@@ -485,7 +485,6 @@ void LLFloaterModelWizard::DecompRequest::completed()
 	{
 		if (sInstance->mModelPreview)
 		{
-			sInstance->mModelPreview->mPhysicsMesh[mModel] = mHullMesh;
 			sInstance->mModelPreview->mDirty = true;
 			LLFloaterModelWizard::sInstance->mModelPreview->refresh();
 		}
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index a2792bcdc6357f47a6aaadde9776396091d258c1..752e4c87442efc1439e809111e5a4f4ead46aa1a 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -108,19 +108,13 @@ U32 get_volume_memory_size(const LLVolume* volume)
 	return indices*2+vertices*11+sizeof(LLVolume)+sizeof(LLVolumeFace)*volume->getNumVolumeFaces();
 }
 
-LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f)
+void get_vertex_buffer_from_mesh(LLCDMeshData& mesh, LLModel::PhysicsMesh& res, F32 scale = 1.f)
 {
-	LLVertexBuffer* buff = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_NORMAL, 0);
-	buff->allocateBuffer(mesh.mNumTriangles*3, 0, true);
-
-	LLStrider<LLVector3> pos;
-	LLStrider<LLVector3> norm;
+	res.mPositions.clear();
+	res.mNormals.clear();
 	
-	buff->getVertexStrider(pos);
-	buff->getNormalStrider(norm);
-
 	const F32* v = mesh.mVertexBase;
-	
+
 	if (mesh.mIndexType == LLCDMeshData::INT_16)
 	{
 		U16* idx = (U16*) mesh.mIndexBase;
@@ -139,13 +133,13 @@ LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f)
 			LLVector3 n = (v1-v0)%(v2-v0);
 			n.normalize();
 
-			*pos++ = v0*scale;
-			*pos++ = v1*scale;
-			*pos++ = v2*scale;
+			res.mPositions.push_back(v0*scale);
+			res.mPositions.push_back(v1*scale);
+			res.mPositions.push_back(v2*scale);
 
-			*norm++ = n;
-			*norm++ = n;
-			*norm++ = n;			
+			res.mNormals.push_back(n);
+			res.mNormals.push_back(n);
+			res.mNormals.push_back(n);			
 		}
 	}
 	else
@@ -166,17 +160,15 @@ LLVertexBuffer* get_vertex_buffer_from_mesh(LLCDMeshData& mesh, F32 scale = 1.f)
 			LLVector3 n = (v1-v0)%(v2-v0);
 			n.normalize();
 
-			*(pos++) = v0*scale;
-			*(pos++) = v1*scale;
-			*(pos++) = v2*scale;
+			res.mPositions.push_back(v0*scale);
+			res.mPositions.push_back(v1*scale);
+			res.mPositions.push_back(v2*scale);
 
-			*(norm++) = n;
-			*(norm++) = n;
-			*(norm++) = n;			
+			res.mNormals.push_back(n);
+			res.mNormals.push_back(n);
+			res.mNormals.push_back(n);			
 		}
 	}
-
-	return buff;
 }
 
 S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
@@ -1111,66 +1103,9 @@ bool LLMeshRepoThread::skinInfoReceived(const LLUUID& mesh_id, U8* data, S32 dat
 	}
 	
 	{
-		LLMeshSkinInfo info;
+		LLMeshSkinInfo info(skin);
 		info.mMeshID = mesh_id;
 
-		if (skin.has("joint_names"))
-		{
-			for (U32 i = 0; i < skin["joint_names"].size(); ++i)
-			{
-				info.mJointNames.push_back(skin["joint_names"][i]);
-			}
-		}
-
-		if (skin.has("inverse_bind_matrix"))
-		{
-			for (U32 i = 0; i < skin["inverse_bind_matrix"].size(); ++i)
-			{
-				LLMatrix4 mat;
-				for (U32 j = 0; j < 4; j++)
-				{
-					for (U32 k = 0; k < 4; k++)
-					{
-						mat.mMatrix[j][k] = skin["inverse_bind_matrix"][i][j*4+k].asReal();
-					}
-				}
-
-				info.mInvBindMatrix.push_back(mat);
-			}
-		}
-
-		if (skin.has("bind_shape_matrix"))
-		{
-			for (U32 j = 0; j < 4; j++)
-			{
-				for (U32 k = 0; k < 4; k++)
-				{
-					info.mBindShapeMatrix.mMatrix[j][k] = skin["bind_shape_matrix"][j*4+k].asReal();
-				}
-			}
-		}
-
-		if (skin.has("alt_inverse_bind_matrix"))
-		{
-			for (U32 i = 0; i < skin["alt_inverse_bind_matrix"].size(); ++i)
-			{
-				LLMatrix4 mat;
-				for (U32 j = 0; j < 4; j++)
-				{
-					for (U32 k = 0; k < 4; k++)
-					{
-						mat.mMatrix[j][k] = skin["alt_inverse_bind_matrix"][i][j*4+k].asReal();
-					}
-				}
-				
-				info.mAlternateBindMatrix.push_back(mat);
-			}
-		}
-
-		if (skin.has("pelvis_offset"))
-		{
-			info.mPelvisOffset = skin["pelvis_offset"].asReal();
-		}
 		//llinfos<<"info pelvis offset"<<info.mPelvisOffset<<llendl;
 		mSkinInfoQ.push(info);
 	}
@@ -1196,119 +1131,8 @@ bool LLMeshRepoThread::decompositionReceived(const LLUUID& mesh_id, U8* data, S3
 	}
 	
 	{
-		LLMeshDecomposition* d = new LLMeshDecomposition();
+		LLModel::Decomposition* d = new LLModel::Decomposition(decomp);
 		d->mMeshID = mesh_id;
-
-		if (decomp.has("HullList"))
-		{
-			// 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();
-
-			U16* p = (U16*) &position[0];
-
-			d->mHull.resize(hulls.size());
-
-			LLVector3 min;
-			LLVector3 max;
-			LLVector3 range;
-
-			min.setValue(decomp["Min"]);
-			max.setValue(decomp["Max"]);
-			range = max-min;
-
-			for (U32 i = 0; i < hulls.size(); ++i)
-			{
-				U16 count = (hulls[i] == 0) ? 256 : hulls[i];
-				
-				for (U32 j = 0; j < count; ++j)
-				{
-					d->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],
-						(F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
-					p += 3;
-				}		 
-
-			}
-				
-			//get mesh for decomposition
-			for (U32 i = 0; i < d->mHull.size(); ++i)
-			{
-				LLCDHull hull;
-				hull.mNumVertices = d->mHull[i].size();
-				hull.mVertexBase = d->mHull[i][0].mV;
-				hull.mVertexStrideBytes = 12;
-
-				LLCDMeshData mesh;
-				LLCDResult res = LLCD_OK;
-				if (LLConvexDecomposition::getInstance() != NULL)
-				{
-					res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
-				}
-				if (res != LLCD_OK)
-				{
-					llwarns << "could not get mesh from hull from convex decomposition lib." << llendl;
-					return false;
-				}
-
-
-				d->mMesh.push_back(get_vertex_buffer_from_mesh(mesh));
-			}	
-		}
-
-		if (decomp.has("Hull"))
-		{
-			const LLSD::Binary& position = decomp["Hull"].asBinary();
-
-			U16* p = (U16*) &position[0];
-
-			LLVector3 min;
-			LLVector3 max;
-			LLVector3 range;
-
-			min.setValue(decomp["Min"]);
-			max.setValue(decomp["Max"]);
-			range = max-min;
-
-			U16 count = position.size()/6;
-			
-			for (U32 j = 0; j < count; ++j)
-			{
-				d->mBaseHull.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],
-					(F32) p[2]/65535.f*range.mV[2]+min.mV[2]));
-				p += 3;
-			}		 
-				
-			//get mesh for decomposition
-			LLCDHull hull;
-			hull.mNumVertices = d->mBaseHull.size();
-			hull.mVertexBase = d->mBaseHull[0].mV;
-			hull.mVertexStrideBytes = 12;
-
-			LLCDMeshData mesh;
-			LLCDResult res = LLCD_OK;
-			if (LLConvexDecomposition::getInstance() != NULL)
-			{
-				res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
-			}
-			if (res != LLCD_OK)
-			{
-				llwarns << "could not get mesh from hull from convex decomposition lib." << llendl;
-				return false;
-			}
-
-			d->mBaseHullMesh = get_vertex_buffer_from_mesh(mesh);
-		}
-		else
-		{
-			//empty vertex buffer to indicate decomposition has been fetched
-			//but contains no base hull
-			d->mBaseHullMesh = new LLVertexBuffer(0, 0);
-		}
-
 		mDecompositionQ.push(d);
 	}
 
@@ -1319,12 +1143,12 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32
 {
 	LLSD physics_shape;
 
-	LLMeshDecomposition* d = new LLMeshDecomposition();
+	LLModel::Decomposition* d = new LLModel::Decomposition();
 	d->mMeshID = mesh_id;
 
 	if (data == NULL)
 	{ //no data, no physics shape exists
-		d->mPhysicsShapeMesh = new LLVertexBuffer(0,0);
+		d->mPhysicsShapeMesh.clear();
 	}
 	else
 	{
@@ -1348,33 +1172,22 @@ bool LLMeshRepoThread::physicsShapeReceived(const LLUUID& mesh_id, U8* data, S32
 				index_count += face.mNumIndices;
 			}
 
-			d->mPhysicsShapeMesh = new LLVertexBuffer(LLVertexBuffer::MAP_VERTEX, 0);
-
-			d->mPhysicsShapeMesh->allocateBuffer(vertex_count, index_count, true);
-
-			LLStrider<LLVector3> pos;
-			LLStrider<U16> idx;
+			d->mPhysicsShapeMesh.clear();
 
-			d->mPhysicsShapeMesh->getVertexStrider(pos);
-			d->mPhysicsShapeMesh->getIndexStrider(idx);
+			std::vector<LLVector3>& pos = d->mPhysicsShapeMesh.mPositions;
+			std::vector<LLVector3>& norm = d->mPhysicsShapeMesh.mNormals;
 
-			S32 idx_offset = 0;
 			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 			{
 				const LLVolumeFace& face = volume->getVolumeFace(i);
-				if (idx_offset + face.mNumIndices > 65535)
-				{ //avoid 16-bit index overflow
-					continue;
-				}
-
-				LLVector4a::memcpyNonAliased16(pos[idx_offset].mV, face.mPositions[0].getF32ptr(), face.mNumVertices*sizeof(LLVector4a));
 			
 				for (S32 i = 0; i < face.mNumIndices; ++i)
 				{
-					*idx++ = face.mIndices[i] + idx_offset;
-				}
+					U16 idx = face.mIndices[i];
 
-				idx_offset += face.mNumVertices;
+					pos.push_back(LLVector3(face.mPositions[idx].getF32ptr()));
+					norm.push_back(LLVector3(face.mNormals[idx].getF32ptr()));				
+				}			
 			}
 		}
 	}
@@ -2485,33 +2298,7 @@ void LLMeshRepository::notifySkinInfoReceived(LLMeshSkinInfo& info)
 	mLoadingSkins.erase(info.mMeshID);
 }
 
-void LLMeshDecomposition::merge(const LLMeshDecomposition* rhs)
-{
-	if (!rhs)
-	{
-		return;
-	}
-
-	if (mMeshID != rhs->mMeshID)
-	{
-		llerrs << "Attempted to merge with decomposition of some other mesh." << llendl;
-	}
-
-	if (mBaseHull.empty())
-	{ //take base hull and decomposition from rhs
-		mHull = rhs->mHull;
-		mBaseHull = rhs->mBaseHull;
-		mMesh = rhs->mMesh;
-		mBaseHullMesh = rhs->mBaseHullMesh;
-	}
-
-	if (mPhysicsShapeMesh.isNull())
-	{ //take physics shape mesh from rhs
-		mPhysicsShapeMesh = rhs->mPhysicsShapeMesh;
-	}
-}
-
-void LLMeshRepository::notifyDecompositionReceived(LLMeshDecomposition* decomp)
+void LLMeshRepository::notifyDecompositionReceived(LLModel::Decomposition* decomp)
 {
 	decomposition_map::iterator iter = mDecompositionMap.find(decomp->mMeshID);
 	if (iter == mDecompositionMap.end())
@@ -2653,7 +2440,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 {
 	if (mesh_id.notNull())
 	{
-		LLMeshDecomposition* decomp = NULL;
+		LLModel::Decomposition* decomp = NULL;
 		decomposition_map::iterator iter = mDecompositionMap.find(mesh_id);
 		if (iter != mDecompositionMap.end())
 		{
@@ -2661,7 +2448,7 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 		}
 		
 		//decomposition block hasn't been fetched yet
-		if (!decomp || decomp->mPhysicsShapeMesh.isNull())
+		if (!decomp || decomp->mPhysicsShapeMesh.empty())
 		{
 			LLMutexLock lock(mMeshMutex);
 			//add volume to list of loading meshes
@@ -2676,9 +2463,9 @@ void LLMeshRepository::fetchPhysicsShape(const LLUUID& mesh_id)
 
 }
 
-const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)
+LLModel::Decomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh_id)
 {
-	LLMeshDecomposition* ret = NULL;
+	LLModel::Decomposition* ret = NULL;
 
 	if (mesh_id.notNull())
 	{
@@ -2689,7 +2476,7 @@ const LLMeshDecomposition* LLMeshRepository::getDecomposition(const LLUUID& mesh
 		}
 		
 		//decomposition block hasn't been fetched yet
-		if (!ret || ret->mBaseHullMesh.isNull())
+		if (!ret || ret->mBaseHullMesh.empty())
 		{
 			LLMutexLock lock(mMeshMutex);
 			//add volume to list of loading meshes
@@ -2792,8 +2579,8 @@ void LLMeshUploadThread::sendCostRequest(LLMeshUploadData& data)
 
 	LLModel::convex_hull_decomposition& decomp =
 		data.mModel[LLModel::LOD_PHYSICS].notNull() ? 
-		data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp : 
-		data.mBaseModel->mConvexHullDecomp;
+		data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : 
+		data.mBaseModel->mPhysics.mHull;
 
 	LLModel::hull dummy_hull;
 
@@ -2893,8 +2680,8 @@ void LLMeshUploadThread::doUploadModel(LLMeshUploadData& data)
 
 		LLModel::convex_hull_decomposition& decomp =
 			data.mModel[LLModel::LOD_PHYSICS].notNull() ? 
-			data.mModel[LLModel::LOD_PHYSICS]->mConvexHullDecomp : 
-			data.mBaseModel->mConvexHullDecomp;
+			data.mModel[LLModel::LOD_PHYSICS]->mPhysics.mHull : 
+			data.mBaseModel->mPhysics.mHull;
 
 		LLModel::writeModel(
 			ostr,  
@@ -3412,7 +3199,7 @@ void LLPhysicsDecomp::doDecomposition()
 			// if LLConvexDecomposition is a stub, num_hulls should have been set to 0 above, and we should not reach this code
 			LLConvexDecomposition::getInstance()->getMeshFromStage(stage, i, &mesh);
 
-			mCurRequest->mHullMesh[i] = get_vertex_buffer_from_mesh(mesh);
+			get_vertex_buffer_from_mesh(mesh, mCurRequest->mHullMesh[i]);
 			
 			mMutex->lock();
 			mCurRequest->mHull[i] = p;
@@ -3685,3 +3472,46 @@ LLSD LLImportMaterial::asLLSD()
 	
 	return ret;
 }
+
+void LLMeshRepository::buildPhysicsMesh(LLModel::Decomposition& decomp)
+{
+	decomp.mMesh.resize(decomp.mHull.size());
+
+	for (U32 i = 0; i < decomp.mHull.size(); ++i)
+	{
+		LLCDHull hull;
+		hull.mNumVertices = decomp.mHull[i].size();
+		hull.mVertexBase = decomp.mHull[i][0].mV;
+		hull.mVertexStrideBytes = 12;
+
+		LLCDMeshData mesh;
+		LLCDResult res = LLCD_OK;
+		if (LLConvexDecomposition::getInstance() != NULL)
+		{
+			res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
+		}
+		if (res == LLCD_OK)
+		{
+			get_vertex_buffer_from_mesh(mesh, decomp.mMesh[i]);
+		}
+	}
+
+	if (!decomp.mBaseHull.empty() && decomp.mBaseHullMesh.empty())
+	{ //get mesh for base hull
+		LLCDHull hull;
+		hull.mNumVertices = decomp.mBaseHull.size();
+		hull.mVertexBase = decomp.mBaseHull[0].mV;
+		hull.mVertexStrideBytes = 12;
+
+		LLCDMeshData mesh;
+		LLCDResult res = LLCD_OK;
+		if (LLConvexDecomposition::getInstance() != NULL)
+		{
+			res = LLConvexDecomposition::getInstance()->getMeshFromHull(&hull, &mesh);
+		}
+		if (res == LLCD_OK)
+		{
+			get_vertex_buffer_from_mesh(mesh, decomp.mBaseHullMesh);
+		}
+	}
+}
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 4e349a12709f4a9d5a9ad2ea01d3162cee05a04f..31c2049c323128e901ca734408747fd00f0bf10d 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -132,34 +132,6 @@ class LLModelInstance
 	LLSD asLLSD();
 };
 
-class LLMeshSkinInfo 
-{
-public:
-	LLUUID mMeshID;
-	std::vector<std::string> mJointNames;
-	std::vector<LLMatrix4> mInvBindMatrix;
-	std::vector<LLMatrix4> mAlternateBindMatrix;
-	
-	LLMatrix4 mBindShapeMatrix;
-	float mPelvisOffset;
-};
-
-class LLMeshDecomposition
-{
-public:
-	LLMeshDecomposition() { }
-
-	void merge(const LLMeshDecomposition* rhs);
-
-	LLUUID mMeshID;
-	LLModel::convex_hull_decomposition mHull;
-	LLModel::hull mBaseHull;
-
-	std::vector<LLPointer<LLVertexBuffer> > mMesh;
-	LLPointer<LLVertexBuffer> mBaseHullMesh;
-	LLPointer<LLVertexBuffer> mPhysicsShapeMesh;
-};
-
 class LLPhysicsDecomp : public LLThread
 {
 public:
@@ -178,7 +150,7 @@ class LLPhysicsDecomp : public LLThread
 				
 		//output state
 		std::string mStatusMessage;
-		std::vector<LLPointer<LLVertexBuffer> > mHullMesh;
+		std::vector<LLModel::PhysicsMesh> mHullMesh;
 		LLModel::convex_hull_decomposition mHull;
 		
 		//status message callback, called from decomposition thread
@@ -313,7 +285,7 @@ class LLMeshRepoThread : public LLThread
 	std::set<LLUUID> mPhysicsShapeRequests;
 
 	//queue of completed Decomposition info requests
-	std::queue<LLMeshDecomposition*> mDecompositionQ;
+	std::queue<LLModel::Decomposition*> mDecompositionQ;
 
 	//queue of requested headers
 	std::queue<HeaderRequest> mHeaderReqQ;
@@ -477,17 +449,19 @@ class LLMeshRepository
 	void notifyMeshLoaded(const LLVolumeParams& mesh_params, LLVolume* volume);
 	void notifyMeshUnavailable(const LLVolumeParams& mesh_params, S32 lod);
 	void notifySkinInfoReceived(LLMeshSkinInfo& info);
-	void notifyDecompositionReceived(LLMeshDecomposition* info);
+	void notifyDecompositionReceived(LLModel::Decomposition* info);
 
 	S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod);
 	U32 calcResourceCost(LLSD& header);
 	U32 getResourceCost(const LLUUID& mesh_params);
 	const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id);
-	const LLMeshDecomposition* getDecomposition(const LLUUID& mesh_id);
+	LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id);
 	void fetchPhysicsShape(const LLUUID& mesh_id);
 	bool hasPhysicsShape(const LLUUID& mesh_id);
 	
 	void buildHull(const LLVolumeParams& params, S32 detail);
+	void buildPhysicsMesh(LLModel::Decomposition& decomp);
+
 	const LLSD& getMeshHeader(const LLUUID& mesh_id);
 
 	void uploadModel(std::vector<LLModelInstance>& data, LLVector3& scale, bool upload_textures,
@@ -501,7 +475,7 @@ class LLMeshRepository
 	typedef std::map<LLUUID, LLMeshSkinInfo> skin_map;
 	skin_map mSkinMap;
 
-	typedef std::map<LLUUID, LLMeshDecomposition*> decomposition_map;
+	typedef std::map<LLUUID, LLModel::Decomposition*> decomposition_map;
 	decomposition_map mDecompositionMap;
 
 	LLMutex*					mMeshMutex;
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 5e7af6bbb3e08547fe08c65890b8f308e69903d6..65f7d299bc92d5b7e5b01f65365fd31e809fd113 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -2961,31 +2961,21 @@ S32 get_physics_detail(const LLVolumeParams& volume_params, const LLVector3& sca
 void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLColor4& line_color)
 {
 	LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
-	const LLMeshDecomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+	LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
 
 	const LLVector3 center(0,0,0);
 	const LLVector3 size(0.25f,0.25f,0.25f);
 
 	if (decomp)
 	{		
-		LLVertexBuffer* buff = decomp->mBaseHullMesh;
-
-		if (buff && buff->getNumVerts() > 0)
+		if (!decomp->mBaseHullMesh.empty())
 		{
-			buff->setBuffer(data_mask);
-
-		/*	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-			glColor4fv(line_color.mV);
-			buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
-			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);*/
-
-			{
-				glColor4fv(color.mV);
-				buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
-			}
+			glColor4fv(color.mV);
+			LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mBaseHullMesh.mPositions, decomp->mBaseHullMesh.mNormals);
 		}
 		else
 		{
+			gMeshRepo.buildPhysicsMesh(*decomp);
 			gGL.color3f(0,1,1);
 			drawBoxOutline(center, size);
 		}
@@ -2998,19 +2988,16 @@ void renderMeshBaseHull(LLVOVolume* volume, U32 data_mask, LLColor4& color, LLCo
 	}
 }
 
-void render_hull(LLVertexBuffer* buff, U32 data_mask, const LLColor4& color, const LLColor4& line_color)
+void render_hull(LLModel::PhysicsMesh& mesh, const LLColor4& color, const LLColor4& line_color)
 {
-	buff->setBuffer(data_mask);
-
 	glColor4fv(color.mV);
-	buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
-
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
 	LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 	glPolygonOffset(3.f, 3.f);
 	glLineWidth(3.f);
 	glColor4fv(line_color.mV);
-	buff->drawArrays(LLRender::TRIANGLES, 0, buff->getNumVerts());
+	LLVertexBuffer::drawArrays(LLRender::TRIANGLES, mesh.mPositions, mesh.mNormals);
 	glLineWidth(1.f);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 }
@@ -3075,7 +3062,7 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 	if (type == LLPhysicsShapeBuilderUtil::PhysicsShapeSpecification::USER_MESH)
 	{
 		LLUUID mesh_id = volume->getVolume()->getParams().getSculptID();
-		const LLMeshDecomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
+		LLModel::Decomposition* decomp = gMeshRepo.getDecomposition(mesh_id);
 			
 		if (decomp)
 		{ //render a physics based mesh
@@ -3084,27 +3071,33 @@ void renderPhysicsShape(LLDrawable* drawable, LLVOVolume* volume)
 
 			if (!decomp->mHull.empty())
 			{ //decomposition exists, use that
-				for (U32 i = 0; i < decomp->mHull.size(); ++i)
+
+				if (decomp->mMesh.empty())
+				{
+					gMeshRepo.buildPhysicsMesh(*decomp);
+				}
+
+				for (U32 i = 0; i < decomp->mMesh.size(); ++i)
 				{		
-					render_hull(decomp->mMesh[i], data_mask, color, line_color);
+					render_hull(decomp->mMesh[i], color, line_color);
 				}
 			}
-			else if (decomp->mPhysicsShapeMesh.notNull() && decomp->mPhysicsShapeMesh->getNumVerts() > 0)
+			else if (!decomp->mPhysicsShapeMesh.empty())
 			{ 
 				//decomp has physics mesh, render that mesh
 				glColor4fv(color.mV);
-				pushBufferVerts(decomp->mPhysicsShapeMesh, data_mask);
-				
+				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
+								
 				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 				glColor4fv(line_color.mV);
-				pushBufferVerts(decomp->mPhysicsShapeMesh, data_mask);
+				LLVertexBuffer::drawArrays(LLRender::TRIANGLES, decomp->mPhysicsShapeMesh.mPositions, decomp->mPhysicsShapeMesh.mNormals);
 				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 			}
 			else
 			{ //no mesh or decomposition, render base hull
 				renderMeshBaseHull(volume, data_mask, color, line_color);
 
-				if (decomp->mPhysicsShapeMesh.isNull())
+				if (decomp->mPhysicsShapeMesh.empty())
 				{
 					//attempt to fetch physics shape mesh if available
 					gMeshRepo.fetchPhysicsShape(mesh_id);
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 7468281f658591b5262fd06a3b31ad2ed0895364..71706f0146669571b7b082caff2ff8fd5356d28e 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -762,6 +762,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mPelvisOffset = LLVector3(0.0f,0.0f,0.0f);
 	mLastPelvisToFoot = 0.0f;
 	mPelvisFixup = 0.0f;
+	mLastPelvisFixup = 0.0f;
 }
 
 //------------------------------------------------------------------------
@@ -3805,6 +3806,7 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,
 		//Store off last pelvis to foot value
 		mLastPelvisToFoot = mPelvisToFoot;
 		mPelvisOffset	  = offsetAmount;
+		mLastPelvisFixup  = mPelvisFixup;
 		mPelvisFixup	  = pelvisFixup;
 	}
 }
@@ -3825,6 +3827,7 @@ void LLVOAvatar::postPelvisSetRecalc( void )
 void LLVOAvatar::setPelvisOffset( F32 pelvisFixupAmount )
 {	
 	mHasPelvisOffset  = true;
+	mLastPelvisFixup  = mPelvisFixup;	
 	mPelvisFixup	  = pelvisFixupAmount;	
 }
 //------------------------------------------------------------------------
@@ -4965,6 +4968,7 @@ void LLVOAvatar::resetJointPositions( void )
 		mSkeleton[i].setId( LLUUID::null );
 	}
 	mHasPelvisOffset = false;
+	mPelvisFixup	 = mLastPelvisFixup;
 }
 //-----------------------------------------------------------------------------
 // resetSpecificJointPosition
@@ -5024,6 +5028,7 @@ void LLVOAvatar::resetJointPositionsToDefault( void )
 	}
 	//make sure we don't apply the joint offset
 	mHasPelvisOffset = false;
+	mPelvisFixup	 = mLastPelvisFixup;
 	postPelvisSetRecalc();
 }
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 1552532a97cf7d8eaddfd9b99b3519269be960f5..edec1b480aa8fadcc40a72f82900854607e85e73 100644
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -301,6 +301,7 @@ class LLVOAvatar :
 	LLVector3			mPelvisOffset;
 	F32					mLastPelvisToFoot;
 	F32					mPelvisFixup;
+	F32					mLastPelvisFixup;
 
 	LLVector3			mHeadOffset; // current head position
 	LLViewerJoint		mRoot;
diff --git a/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml
index 19264db59873d5d584288e477ae0ec228c98f280..443092319b5049a5ea9d7a905d202c58c4d95d31 100644
--- a/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<toggleable_menu name="Gear Menu">
+<toggleable_menu name="Self Pie">
 	<menu_item_call label="Hinsetzen" name="Sit Down Here"/>
 	<menu_item_call label="Aufstehen" name="Stand Up"/>
 	<menu_item_call label="Meine Freunde" name="Friends..."/>
diff --git a/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml
index 6b7613711489dc0ce0615067f174997e25611668..1a49efb9d027903c07257b43dbd75b89f5a3838a 100644
--- a/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<toggleable_menu name="Gear Menu">
+<toggleable_menu name="Self Pie">
 	<menu_item_call label="Sentarme" name="Sit Down Here"/>
 	<menu_item_call label="Levantarme" name="Stand Up"/>
 	<menu_item_call label="Mis amigos" name="Friends..."/>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml
index 7a79c00123db410859c9b6a08b27c10ff0747c28..fd48aa4f7d7bb76329cd11c989bff4ceab786e62 100644
--- a/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<toggleable_menu name="Gear Menu">
+<toggleable_menu name="Self Pie">
 	<menu_item_call label="M&apos;asseoir" name="Sit Down Here"/>
 	<menu_item_call label="Me lever" name="Stand Up"/>
 	<menu_item_call label="Mes amis" name="Friends..."/>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml
index e514d2f4f56eb54519e4a4ebc62aadda0bd8a626..c1f27e765d797fe223fc1042ae3940570ee0f400 100644
--- a/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
-<toggleable_menu name="Gear Menu">
+<toggleable_menu name="Self Pie">
 	<menu_item_call label="Sentar" name="Sit Down Here"/>
 	<menu_item_call label="Ficar de pé" name="Stand Up"/>
 	<menu_item_call label="Meus amigos" name="Friends..."/>