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..81420fadb7296b6fdcde9aaae441e313718649c4 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);
@@ -1999,4 +1904,232 @@ void LLModel::setConvexHullDecomposition(
 	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);
+		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)
+{
+	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;
+}
 
diff --git a/indra/llprimitive/llmodel.h b/indra/llprimitive/llmodel.h
index addf527d8df5c965f03505c624f69f9d9e525868..81be9d18352fc4e52989eead3c20762465573ea4 100755
--- a/indra/llprimitive/llmodel.h
+++ b/indra/llprimitive/llmodel.h
@@ -36,6 +36,25 @@ 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.
 
@@ -210,7 +221,6 @@ class LLModel : public LLVolume
 
 protected:
 	void addVolumeFacesFromDomMesh(domMesh* mesh);
-	virtual BOOL createVolumeFacesFromFile(const std::string& file_name);
 	virtual BOOL createVolumeFacesFromDomMesh(domMesh *mesh);
 };
 
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index 0b7c011861f372a9af7c121dd622a48c67d4669e..d8088e2f51726b655def3ac3e6e06e2f05c5900d 100755
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -1330,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;
 							
 						}
 						
@@ -1479,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);
@@ -1500,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
@@ -1518,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;
 											}
 										}
 									}
@@ -1548,7 +1550,7 @@ bool LLModelLoader::doLoadModel()
 												}
 											}
 											
-											model->mInvBindMatrix.push_back(mat);
+											model->mSkinInfo.mInvBindMatrix.push_back(mat);
 										}
 									}
 								}
@@ -1559,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;
 						}
@@ -1600,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();
@@ -1610,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
 							{
@@ -1817,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
 			{
@@ -1875,7 +1882,7 @@ void LLModelLoader::loadModelCallback()
 {
 	if (mPreview)
 	{
-		mPreview->loadModelCallback(mLod);	
+		mPreview->loadModelCallback(mLod);
 	}
 
 	while (!isStopped())
@@ -2904,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
 
@@ -2936,12 +2946,40 @@ void LLModelPreview::loadModelCallback(S32 lod)
 							mModel[lod].resize(idx+1);
 						}
 
-						mModel[lod][idx] = list_iter->mModel;	
+						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];
@@ -3418,11 +3456,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;
 
@@ -4394,12 +4428,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();
 								}
 							}
@@ -4440,7 +4474,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;
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index a2792bcdc6357f47a6aaadde9776396091d258c1..f5fc0de0d305b5dc892107745f3f0dd8cbece2b6 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1111,66 +1111,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);
 	}
diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h
index 4e349a12709f4a9d5a9ad2ea01d3162cee05a04f..5960fe2949ad3fa4dde824517b576a2ee9846492 100644
--- a/indra/newview/llmeshrepository.h
+++ b/indra/newview/llmeshrepository.h
@@ -132,18 +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: