From 77b33d9623c08152932282048fe847d79fcf43cd Mon Sep 17 00:00:00 2001
From: "Nyx (Neal Orman)" <nyx@lindenlab.com>
Date: Fri, 7 Sep 2012 23:17:34 -0400
Subject: SH-3264 Porting over the XML loading of the avatar structure to
 llappearance

Moved over the necessary classes to llappearance to support the loading of the
avatar's structure & params from file.
---
 indra/llappearance/CMakeLists.txt               |   10 +
 indra/llappearance/llavatarappearance.cpp       | 1421 ++++++++++++++++++++-
 indra/llappearance/llavatarappearance.h         |  207 ++-
 indra/llappearance/llavatarjoint.cpp            |  261 ++++
 indra/llappearance/llavatarjoint.h              |  127 ++
 indra/llappearance/llavatarjointmesh.cpp        |  359 ++++++
 indra/llappearance/llavatarjointmesh.h          |  140 ++
 indra/llappearance/llpolymesh.cpp               | 1050 +++++++++++++++
 indra/llappearance/llpolymesh.h                 |  369 ++++++
 indra/llappearance/llpolymorph.cpp              |  748 +++++++++++
 indra/llappearance/llpolymorph.h                |  182 +++
 indra/llappearance/llpolyskeletaldistortion.cpp |  293 +++++
 indra/llappearance/llpolyskeletaldistortion.h   |  119 ++
 indra/newview/CMakeLists.txt                    |    4 -
 indra/newview/llagentcamera.cpp                 |   10 +-
 indra/newview/llfloaterbvhpreview.cpp           |    4 +-
 indra/newview/llfloaterimagepreview.cpp         |    8 +-
 indra/newview/llhudeffectlookat.cpp             |    2 +-
 indra/newview/llpolymesh.cpp                    | 1297 -------------------
 indra/newview/llpolymesh.h                      |  438 -------
 indra/newview/llpolymorph.h                     |    6 +-
 indra/newview/llspatialpartition.cpp            |    2 +-
 indra/newview/llstartup.cpp                     |    3 +
 indra/newview/llviewerjoint.cpp                 |  121 +-
 indra/newview/llviewerjoint.h                   |   20 +-
 indra/newview/llviewerjointmesh.cpp             |  283 +----
 indra/newview/llviewerjointmesh.h               |   86 +-
 indra/newview/llviewerwindow.cpp                |    2 +-
 indra/newview/llvoavatar.cpp                    | 1548 +++--------------------
 indra/newview/llvoavatar.h                      |  172 +--
 indra/newview/llvoavatarself.cpp                |    6 +-
 indra/newview/llvoavatarself.h                  |    2 +-
 32 files changed, 5466 insertions(+), 3834 deletions(-)
 create mode 100644 indra/llappearance/llavatarjoint.cpp
 create mode 100644 indra/llappearance/llavatarjoint.h
 create mode 100755 indra/llappearance/llavatarjointmesh.cpp
 create mode 100755 indra/llappearance/llavatarjointmesh.h
 create mode 100644 indra/llappearance/llpolymesh.cpp
 create mode 100644 indra/llappearance/llpolymesh.h
 create mode 100644 indra/llappearance/llpolymorph.cpp
 create mode 100644 indra/llappearance/llpolymorph.h
 create mode 100644 indra/llappearance/llpolyskeletaldistortion.cpp
 create mode 100644 indra/llappearance/llpolyskeletaldistortion.h
 delete mode 100644 indra/newview/llpolymesh.cpp
 delete mode 100644 indra/newview/llpolymesh.h

(limited to 'indra')

diff --git a/indra/llappearance/CMakeLists.txt b/indra/llappearance/CMakeLists.txt
index 41da898457..c5a855a505 100644
--- a/indra/llappearance/CMakeLists.txt
+++ b/indra/llappearance/CMakeLists.txt
@@ -42,9 +42,14 @@ include_directories(
 
 set(llappearance_SOURCE_FILES
     llavatarappearance.cpp
+    llavatarjoint.cpp
+    llavatarjointmesh.cpp
     lldriverparam.cpp
     llinventoryicon.cpp
     lllocaltextureobject.cpp
+    llpolyskeletaldistortion.cpp
+    llpolymesh.cpp
+    llpolymorph.cpp
     lltexglobalcolor.cpp
     lltexlayer.cpp
     lltexlayerparams.cpp
@@ -60,10 +65,15 @@ set(llappearance_HEADER_FILES
     CMakeLists.txt
 
     llavatarappearance.h
+    llavatarjoint.h
+    llavatarjointmesh.h
     lldriverparam.h
     llinventoryicon.h
     lljointpickname.h
     lllocaltextureobject.h
+    llpolyskeletaldistortion.h
+    llpolymesh.h
+    llpolymorph.h
     lltexglobalcolor.h
     lltexlayer.h
     lltexlayerparams.h
diff --git a/indra/llappearance/llavatarappearance.cpp b/indra/llappearance/llavatarappearance.cpp
index 2c03f8ba02..406e6153e0 100644
--- a/indra/llappearance/llavatarappearance.cpp
+++ b/indra/llappearance/llavatarappearance.cpp
@@ -29,19 +29,128 @@
 
 #include "llavatarappearance.h"
 #include "llavatarappearancedefines.h"
+#include "llavatarjointmesh.h"
 #include "imageids.h"
+#include "lldir.h"
 #include "lldeleteutils.h"
+#include "llpolymorph.h"
+#include "llpolymesh.h"
+#include "llpolyskeletaldistortion.h"
 #include "lltexglobalcolor.h"
 #include "llwearabledata.h"
 
+//-----------------------------------------------------------------------------
+// Constants
+//-----------------------------------------------------------------------------
+
+const std::string AVATAR_DEFAULT_CHAR = "avatar";
 const LLColor4 DUMMY_COLOR = LLColor4(0.5,0.5,0.5,1.0);
 
+/*********************************************************************************
+ **                                                                             **
+ ** Begin private LLAvatarAppearance Support classes
+ **
+ **/
+
+//------------------------------------------------------------------------
+// LLAvatarBoneInfo
+// Trans/Scale/Rot etc. info about each avatar bone.  Used by LLVOAvatarSkeleton.
+//------------------------------------------------------------------------
+class LLAvatarBoneInfo
+{
+	friend class LLAvatarAppearance;
+	friend class LLAvatarSkeletonInfo;
+public:
+	LLAvatarBoneInfo() : mIsJoint(FALSE) {}
+	~LLAvatarBoneInfo()
+	{
+		std::for_each(mChildList.begin(), mChildList.end(), DeletePointer());
+	}
+	BOOL parseXml(LLXmlTreeNode* node);
+	
+private:
+	std::string mName;
+	BOOL mIsJoint;
+	LLVector3 mPos;
+	LLVector3 mRot;
+	LLVector3 mScale;
+	LLVector3 mPivot;
+	typedef std::vector<LLAvatarBoneInfo*> child_list_t;
+	child_list_t mChildList;
+};
+
+//------------------------------------------------------------------------
+// LLAvatarSkeletonInfo
+// Overall avatar skeleton
+//------------------------------------------------------------------------
+class LLAvatarSkeletonInfo
+{
+	friend class LLAvatarAppearance;
+public:
+	LLAvatarSkeletonInfo() :
+		mNumBones(0), mNumCollisionVolumes(0) {}
+	~LLAvatarSkeletonInfo()
+	{
+		std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer());
+	}
+	BOOL parseXml(LLXmlTreeNode* node);
+	S32 getNumBones() const { return mNumBones; }
+	S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; }
+	
+private:
+	S32 mNumBones;
+	S32 mNumCollisionVolumes;
+	typedef std::vector<LLAvatarBoneInfo*> bone_info_list_t;
+	bone_info_list_t mBoneInfoList;
+};
+
+//-----------------------------------------------------------------------------
+// LLAvatarXmlInfo
+//-----------------------------------------------------------------------------
+
+LLAvatarAppearance::LLAvatarXmlInfo::LLAvatarXmlInfo()
+	: mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0)
+{
+}
+
+LLAvatarAppearance::LLAvatarXmlInfo::~LLAvatarXmlInfo()
+{
+	std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer());
+	std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());		
+	std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer());
+	deleteAndClear(mTexSkinColorInfo);
+	deleteAndClear(mTexHairColorInfo);
+	deleteAndClear(mTexEyeColorInfo);
+	std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());		
+	std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
+	std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer());
+}
+
+
+/**
+ **
+ ** End LLAvatarAppearance Support classes
+ **                                                                             **
+ *********************************************************************************/
+
+//-----------------------------------------------------------------------------
+// Static Data
+//-----------------------------------------------------------------------------
+LLXmlTree LLAvatarAppearance::sXMLTree;
+LLXmlTree LLAvatarAppearance::sSkeletonXMLTree;
+LLAvatarSkeletonInfo* LLAvatarAppearance::sAvatarSkeletonInfo = NULL;
+LLAvatarAppearance::LLAvatarXmlInfo* LLAvatarAppearance::sAvatarXmlInfo = NULL;
+
+
 LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
 	LLCharacter(),
 	mIsDummy(FALSE),
 	mTexSkinColor( NULL ),
 	mTexHairColor( NULL ),
 	mTexEyeColor( NULL ),
+	mPelvisToFoot(0.f),
+	mHeadOffset(),
+
 	mWearableData(wearable_data)
 {
 	llassert(mWearableData);
@@ -55,30 +164,824 @@ LLAvatarAppearance::LLAvatarAppearance(LLWearableData* wearable_data) :
 		mBakedTextureDatas[i].mMaskTexName = 0;
 		mBakedTextureDatas[i].mTextureIndex = LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary::bakedToLocalTextureIndex((LLAvatarAppearanceDefines::EBakedTextureIndex)i);
 	}
+
+	mIsBuilt = FALSE;
+
+	mNumJoints = 0;
+	mSkeleton = NULL;
+
+	mNumCollisionVolumes = 0;
+	mCollisionVolumes = NULL;
+
+	mRoot = new LLAvatarJoint();
+
+}
+
+// virtual
+LLAvatarAppearance::~LLAvatarAppearance()
+{
+	deleteAndClear(mTexSkinColor);
+	deleteAndClear(mTexHairColor);
+	deleteAndClear(mTexEyeColor);
+
+	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+	{
+		deleteAndClear(mBakedTextureDatas[i].mTexLayerSet);
+		mBakedTextureDatas[i].mMeshes.clear();
+
+		for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin();
+			 iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++)
+		{
+			LLMaskedMorph* masked_morph = (*iter2);
+			delete masked_morph;
+		}
+	}
+
+	mRoot->removeAllChildren();
+	mJointMap.clear();
+
+	deleteAndClearArray(mSkeleton);
+	deleteAndClearArray(mCollisionVolumes);
+
+	mNumJoints = 0;
+
+	deleteAndClear(mTexSkinColor);
+	deleteAndClear(mTexHairColor);
+	deleteAndClear(mTexEyeColor);
+
+	std::for_each(mMeshes.begin(), mMeshes.end(), DeletePairedPointer());
+	mMeshes.clear();
+
+	for (std::vector<LLAvatarJoint*>::iterator jointIter = mMeshLOD.begin();
+		 jointIter != mMeshLOD.end(); 
+		 ++jointIter)
+	{
+		LLAvatarJoint* joint = (LLAvatarJoint *) *jointIter;
+		std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer());
+		joint->mMeshParts.clear();
+	}
+	std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer());
+	mMeshLOD.clear();
+}
+
+//static
+void LLAvatarAppearance::initClass()
+{
+	std::string xmlFile;
+
+	xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml";
+	BOOL success = sXMLTree.parseFile( xmlFile, FALSE );
+	if (!success)
+	{
+		llerrs << "Problem reading avatar configuration file:" << xmlFile << llendl;
+	}
+
+	// now sanity check xml file
+	LLXmlTreeNode* root = sXMLTree.getRoot();
+	if (!root) 
+	{
+		llerrs << "No root node found in avatar configuration file: " << xmlFile << llendl;
+		return;
+	}
+
+	//-------------------------------------------------------------------------
+	// <linden_avatar version="1.0"> (root)
+	//-------------------------------------------------------------------------
+	if( !root->hasName( "linden_avatar" ) )
+	{
+		llerrs << "Invalid avatar file header: " << xmlFile << llendl;
+	}
+	
+	std::string version;
+	static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
+	if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
+	{
+		llerrs << "Invalid avatar file version: " << version << " in file: " << xmlFile << llendl;
+	}
+
+	S32 wearable_def_version = 1;
+	static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version");
+	root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version );
+	LLWearable::setCurrentDefinitionVersion( wearable_def_version );
+
+	std::string mesh_file_name;
+
+	LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" );
+	if (!skeleton_node)
+	{
+		llerrs << "No skeleton in avatar configuration file: " << xmlFile << llendl;
+		return;
+	}
+	
+	std::string skeleton_file_name;
+	static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+	if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
+	{
+		llerrs << "No file name in skeleton node in avatar config file: " << xmlFile << llendl;
+	}
+	
+	std::string skeleton_path;
+	skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name);
+	if (!parseSkeletonFile(skeleton_path))
+	{
+		llerrs << "Error parsing skeleton file: " << skeleton_path << llendl;
+	}
+
+	// Process XML data
+
+	// avatar_skeleton.xml
+	if (sAvatarSkeletonInfo)
+	{ //this can happen if a login attempt failed
+		delete sAvatarSkeletonInfo;
+	}
+	sAvatarSkeletonInfo = new LLAvatarSkeletonInfo;
+	if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot()))
+	{
+		llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl;
+	}
+	// parse avatar_lad.xml
+	if (sAvatarXmlInfo)
+	{ //this can happen if a login attempt failed
+		deleteAndClear(sAvatarXmlInfo);
+	}
+	sAvatarXmlInfo = new LLAvatarXmlInfo;
+	if (!sAvatarXmlInfo->parseXmlSkeletonNode(root))
+	{
+		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+	}
+	if (!sAvatarXmlInfo->parseXmlMeshNodes(root))
+	{
+		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+	}
+	if (!sAvatarXmlInfo->parseXmlColorNodes(root))
+	{
+		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+	}
+	if (!sAvatarXmlInfo->parseXmlLayerNodes(root))
+	{
+		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+	}
+	if (!sAvatarXmlInfo->parseXmlDriverNodes(root))
+	{
+		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+	}
+	if (!sAvatarXmlInfo->parseXmlMorphNodes(root))
+	{
+		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
+	}
+}
+
+using namespace LLAvatarAppearanceDefines;
+
+//------------------------------------------------------------------------
+// The viewer can only suggest a good size for the agent,
+// the simulator will keep it inside a reasonable range.
+void LLAvatarAppearance::computeBodySize() 
+{
+	LLVector3 pelvis_scale = mPelvisp->getScale();
+
+	// some of the joints have not been cached
+	LLVector3 skull = mSkullp->getPosition();
+	LLVector3 skull_scale = mSkullp->getScale();
+
+	LLVector3 neck = mNeckp->getPosition();
+	LLVector3 neck_scale = mNeckp->getScale();
+
+	LLVector3 chest = mChestp->getPosition();
+	LLVector3 chest_scale = mChestp->getScale();
+
+	// the rest of the joints have been cached
+	LLVector3 head = mHeadp->getPosition();
+	LLVector3 head_scale = mHeadp->getScale();
+
+	LLVector3 torso = mTorsop->getPosition();
+	LLVector3 torso_scale = mTorsop->getScale();
+
+	LLVector3 hip = mHipLeftp->getPosition();
+	LLVector3 hip_scale = mHipLeftp->getScale();
+
+	LLVector3 knee = mKneeLeftp->getPosition();
+	LLVector3 knee_scale = mKneeLeftp->getScale();
+
+	LLVector3 ankle = mAnkleLeftp->getPosition();
+	LLVector3 ankle_scale = mAnkleLeftp->getScale();
+
+	LLVector3 foot  = mFootLeftp->getPosition();
+
+	mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] -
+				 	knee.mV[VZ] * hip_scale.mV[VZ] -
+				 	ankle.mV[VZ] * knee_scale.mV[VZ] -
+				 	foot.mV[VZ] * ankle_scale.mV[VZ];
+
+	LLVector3 new_body_size;
+	new_body_size.mV[VZ] = mPelvisToFoot +
+					   // the sqrt(2) correction below is an approximate
+					   // correction to get to the top of the head
+					   F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + 
+					   head.mV[VZ] * neck_scale.mV[VZ] + 
+					   neck.mV[VZ] * chest_scale.mV[VZ] + 
+					   chest.mV[VZ] * torso_scale.mV[VZ] + 
+					   torso.mV[VZ] * pelvis_scale.mV[VZ]; 
+
+	// TODO -- measure the real depth and width
+	new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH;
+	new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH;
+
+	if (new_body_size != mBodySize)
+	{
+		mBodySize = new_body_size;
+		bodySizeChanged();
+	}
+}
+
+//-----------------------------------------------------------------------------
+// parseSkeletonFile()
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::parseSkeletonFile(const std::string& filename)
+{
+	LLMemType mt(LLMemType::MTYPE_AVATAR);
+	
+	//-------------------------------------------------------------------------
+	// parse the file
+	//-------------------------------------------------------------------------
+	BOOL parsesuccess = sSkeletonXMLTree.parseFile( filename, FALSE );
+
+	if (!parsesuccess)
+	{
+		llerrs << "Can't parse skeleton file: " << filename << llendl;
+		return FALSE;
+	}
+
+	// now sanity check xml file
+	LLXmlTreeNode* root = sSkeletonXMLTree.getRoot();
+	if (!root) 
+	{
+		llerrs << "No root node found in avatar skeleton file: " << filename << llendl;
+		return FALSE;
+	}
+
+	if( !root->hasName( "linden_skeleton" ) )
+	{
+		llerrs << "Invalid avatar skeleton file header: " << filename << llendl;
+		return FALSE;
+	}
+
+	std::string version;
+	static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
+	if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
+	{
+		llerrs << "Invalid avatar skeleton file version: " << version << " in file: " << filename << llendl;
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// setupBone()
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &volume_num, S32 &joint_num)
+{
+	LLMemType mt(LLMemType::MTYPE_AVATAR);
+	
+	LLJoint* joint = NULL;
+
+	if (info->mIsJoint)
+	{
+		joint = getCharacterJoint(joint_num);
+		if (!joint)
+		{
+			llwarns << "Too many bones" << llendl;
+			return FALSE;
+		}
+		joint->setName( info->mName );
+	}
+	else // collision volume
+	{
+		if (volume_num >= (S32)mNumCollisionVolumes)
+		{
+			llwarns << "Too many bones" << llendl;
+			return FALSE;
+		}
+		joint = (&mCollisionVolumes[volume_num]);
+		joint->setName( info->mName );
+	}
+
+	// add to parent
+	if (parent)
+	{
+		parent->addChild( joint );
+	}
+
+	joint->setPosition(info->mPos);
+	joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY],
+							 info->mRot.mV[VZ], LLQuaternion::XYZ));
+	joint->setScale(info->mScale);
+
+	joint->setDefaultFromCurrentXform();
+	
+	if (info->mIsJoint)
+	{
+		joint->setSkinOffset( info->mPivot );
+		joint_num++;
+	}
+	else // collision volume
+	{
+		volume_num++;
+	}
+
+	// setup children
+	LLAvatarBoneInfo::child_list_t::const_iterator iter;
+	for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter)
+	{
+		LLAvatarBoneInfo *child_info = *iter;
+		if (!setupBone(child_info, joint, volume_num, joint_num))
+		{
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// buildSkeleton()
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::buildSkeleton(const LLAvatarSkeletonInfo *info)
+{
+	LLMemType mt(LLMemType::MTYPE_AVATAR);
+	
+	//-------------------------------------------------------------------------
+	// allocate joints
+	//-------------------------------------------------------------------------
+	if (!allocateCharacterJoints(info->mNumBones))
+	{
+		llerrs << "Can't allocate " << info->mNumBones << " joints" << llendl;
+		return FALSE;
+	}
+	
+	//-------------------------------------------------------------------------
+	// allocate volumes
+	//-------------------------------------------------------------------------
+	if (info->mNumCollisionVolumes)
+	{
+		if (!allocateCollisionVolumes(info->mNumCollisionVolumes))
+		{
+			llerrs << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << llendl;
+			return FALSE;
+		}
+	}
+
+	S32 current_joint_num = 0;
+	S32 current_volume_num = 0;
+	LLAvatarSkeletonInfo::bone_info_list_t::const_iterator iter;
+	for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter)
+	{
+		LLAvatarBoneInfo *info = *iter;
+		if (!setupBone(info, NULL, current_volume_num, current_joint_num))
+		{
+			llerrs << "Error parsing bone in skeleton file" << llendl;
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarAppearance::buildCharacter()
+// Deferred initialization and rebuild of the avatar.
+//-----------------------------------------------------------------------------
+void LLAvatarAppearance::buildCharacter()
+{
+	LLMemType mt(LLMemType::MTYPE_AVATAR);
+	
+	//-------------------------------------------------------------------------
+	// remove all references to our existing skeleton
+	// so we can rebuild it
+	//-------------------------------------------------------------------------
+	flushAllMotions();
+
+	//-------------------------------------------------------------------------
+	// remove all of mRoot's children
+	//-------------------------------------------------------------------------
+	mRoot->removeAllChildren();
+	mJointMap.clear();
+	mIsBuilt = FALSE;
+
+	//-------------------------------------------------------------------------
+	// (re)load our skeleton and meshes
+	//-------------------------------------------------------------------------
+	LLTimer timer;
+
+	BOOL status = loadAvatar();
+	stop_glerror();
+
+// 	gPrintMessagesThisFrame = TRUE;
+	lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl;
+
+	if (!status)
+	{
+		if (isSelf())
+		{
+			llerrs << "Unable to load user's avatar" << llendl;
+		}
+		else
+		{
+			llwarns << "Unable to load other's avatar" << llendl;
+		}
+		return;
+	}
+
+	//-------------------------------------------------------------------------
+	// initialize "well known" joint pointers
+	//-------------------------------------------------------------------------
+	mPelvisp		= mRoot->findJoint("mPelvis");
+	mTorsop			= mRoot->findJoint("mTorso");
+	mChestp			= mRoot->findJoint("mChest");
+	mNeckp			= mRoot->findJoint("mNeck");
+	mHeadp			= mRoot->findJoint("mHead");
+	mSkullp			= mRoot->findJoint("mSkull");
+	mHipLeftp		= mRoot->findJoint("mHipLeft");
+	mHipRightp		= mRoot->findJoint("mHipRight");
+	mKneeLeftp		= mRoot->findJoint("mKneeLeft");
+	mKneeRightp		= mRoot->findJoint("mKneeRight");
+	mAnkleLeftp		= mRoot->findJoint("mAnkleLeft");
+	mAnkleRightp	= mRoot->findJoint("mAnkleRight");
+	mFootLeftp		= mRoot->findJoint("mFootLeft");
+	mFootRightp		= mRoot->findJoint("mFootRight");
+	mWristLeftp		= mRoot->findJoint("mWristLeft");
+	mWristRightp	= mRoot->findJoint("mWristRight");
+	mEyeLeftp		= mRoot->findJoint("mEyeLeft");
+	mEyeRightp		= mRoot->findJoint("mEyeRight");
+
+	//-------------------------------------------------------------------------
+	// Make sure "well known" pointers exist
+	//-------------------------------------------------------------------------
+	if (!(mPelvisp && 
+		  mTorsop &&
+		  mChestp &&
+		  mNeckp &&
+		  mHeadp &&
+		  mSkullp &&
+		  mHipLeftp &&
+		  mHipRightp &&
+		  mKneeLeftp &&
+		  mKneeRightp &&
+		  mAnkleLeftp &&
+		  mAnkleRightp &&
+		  mFootLeftp &&
+		  mFootRightp &&
+		  mWristLeftp &&
+		  mWristRightp &&
+		  mEyeLeftp &&
+		  mEyeRightp))
+	{
+		llerrs << "Failed to create avatar." << llendl;
+		return;
+	}
+
+	//-------------------------------------------------------------------------
+	// initialize the pelvis
+	//-------------------------------------------------------------------------
+	mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) );
+
+	mIsBuilt = TRUE;
+	stop_glerror();
+
+}
+
+BOOL LLAvatarAppearance::loadAvatar()
+{
+// 	LLFastTimer t(FTM_LOAD_AVATAR);
+	
+	// avatar_skeleton.xml
+	if( !buildSkeleton(sAvatarSkeletonInfo) )
+	{
+		llwarns << "avatar file: buildSkeleton() failed" << llendl;
+		return FALSE;
+	}
+
+	// avatar_lad.xml : <skeleton>
+	if( !loadSkeletonNode() )
+	{
+		llwarns << "avatar file: loadNodeSkeleton() failed" << llendl;
+		return FALSE;
+	}
+	
+	// avatar_lad.xml : <mesh>
+	if( !loadMeshNodes() )
+	{
+		llwarns << "avatar file: loadNodeMesh() failed" << llendl;
+		return FALSE;
+	}
+	
+	// avatar_lad.xml : <global_color>
+	if( sAvatarXmlInfo->mTexSkinColorInfo )
+	{
+		mTexSkinColor = new LLTexGlobalColor( this );
+		if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) )
+		{
+			llwarns << "avatar file: mTexSkinColor->setInfo() failed" << llendl;
+			return FALSE;
+		}
+	}
+	else
+	{
+		llwarns << "<global_color> name=\"skin_color\" not found" << llendl;
+		return FALSE;
+	}
+	if( sAvatarXmlInfo->mTexHairColorInfo )
+	{
+		mTexHairColor = new LLTexGlobalColor( this );
+		if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) )
+		{
+			llwarns << "avatar file: mTexHairColor->setInfo() failed" << llendl;
+			return FALSE;
+		}
+	}
+	else
+	{
+		llwarns << "<global_color> name=\"hair_color\" not found" << llendl;
+		return FALSE;
+	}
+	if( sAvatarXmlInfo->mTexEyeColorInfo )
+	{
+		mTexEyeColor = new LLTexGlobalColor( this );
+		if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) )
+		{
+			llwarns << "avatar file: mTexEyeColor->setInfo() failed" << llendl;
+			return FALSE;
+		}
+	}
+	else
+	{
+		llwarns << "<global_color> name=\"eye_color\" not found" << llendl;
+		return FALSE;
+	}
+	
+	// avatar_lad.xml : <layer_set>
+	if (sAvatarXmlInfo->mLayerInfoList.empty())
+	{
+		llwarns << "avatar file: missing <layer_set> node" << llendl;
+		return FALSE;
+	}
+
+	if (sAvatarXmlInfo->mMorphMaskInfoList.empty())
+	{
+		llwarns << "avatar file: missing <morph_masks> node" << llendl;
+		return FALSE;
+	}
+
+	// avatar_lad.xml : <morph_masks>
+	for (LLAvatarXmlInfo::morph_info_list_t::iterator iter = sAvatarXmlInfo->mMorphMaskInfoList.begin();
+		 iter != sAvatarXmlInfo->mMorphMaskInfoList.end();
+		 ++iter)
+	{
+		LLAvatarXmlInfo::LLAvatarMorphInfo *info = *iter;
+
+		EBakedTextureIndex baked = LLAvatarAppearanceDictionary::findBakedByRegionName(info->mRegion); 
+		if (baked != BAKED_NUM_INDICES)
+		{
+			LLVisualParam* morph_param;
+			const std::string *name = &info->mName;
+			morph_param = getVisualParam(name->c_str());
+			if (morph_param)
+			{
+				BOOL invert = info->mInvert;
+				addMaskedMorph(baked, morph_param, invert, info->mLayer);
+			}
+		}
+
+	}
+
+	loadLayersets();	
+	
+	// avatar_lad.xml : <driver_parameters>
+	for (LLAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin();
+		 iter != sAvatarXmlInfo->mDriverInfoList.end(); 
+		 ++iter)
+	{
+		LLDriverParamInfo *info = *iter;
+		LLDriverParam* driver_param = new LLDriverParam( this );
+		if (driver_param->setInfo(info))
+		{
+			addVisualParam( driver_param );
+			LLVisualParam*(LLAvatarAppearance::*avatar_function)(S32)const = &LLAvatarAppearance::getVisualParam; 
+			if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLAvatarAppearance*)this,_1 ), false))
+			{
+				llwarns << "could not link driven params for avatar " << getID().asString() << " param id: " << driver_param->getID() << llendl;
+				continue;
+			}
+		}
+		else
+		{
+			delete driver_param;
+			llwarns << "avatar file: driver_param->parseData() failed" << llendl;
+			return FALSE;
+		}
+	}
+
+	
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// loadSkeletonNode(): loads <skeleton> node from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::loadSkeletonNode ()
+{
+	mRoot->addChild( &mSkeleton[0] );
+
+	mRoot->addChild(mMeshLOD[MESH_ID_HEAD]);
+	mRoot->addChild(mMeshLOD[MESH_ID_EYELASH]);
+	mRoot->addChild(mMeshLOD[MESH_ID_UPPER_BODY]);
+	mRoot->addChild(mMeshLOD[MESH_ID_LOWER_BODY]);
+	mRoot->addChild(mMeshLOD[MESH_ID_SKIRT]);
+	mRoot->addChild(mMeshLOD[MESH_ID_HEAD]);
+
+	LLAvatarJoint *skull = (LLAvatarJoint*)mRoot->findJoint("mSkull");
+	if (skull)
+	{
+		skull->addChild(mMeshLOD[MESH_ID_HAIR] );
+	}
+
+	LLAvatarJoint *eyeL = (LLAvatarJoint*)mRoot->findJoint("mEyeLeft");
+	if (eyeL)
+	{
+		eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] );
+	}
+
+	LLAvatarJoint *eyeR = (LLAvatarJoint*)mRoot->findJoint("mEyeRight");
+	if (eyeR)
+	{
+		eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] );
+	}
+
+	// SKELETAL DISTORTIONS
+	{
+		LLAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter;
+		for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin();
+			 iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end(); 
+			 ++iter)
+		{
+			LLPolySkeletalDistortionInfo *info = (LLPolySkeletalDistortionInfo*)*iter;
+			LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this);
+			if (!param->setInfo(info))
+			{
+				delete param;
+				return FALSE;
+			}
+			else
+			{
+				addVisualParam(param);
+			}				
+		}
+	}
+
+
+	return TRUE;
 }
 
-// virtual
-LLAvatarAppearance::~LLAvatarAppearance()
+//-----------------------------------------------------------------------------
+// loadMeshNodes(): loads <mesh> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::loadMeshNodes()
 {
-	deleteAndClear(mTexSkinColor);
-	deleteAndClear(mTexHairColor);
-	deleteAndClear(mTexEyeColor);
-
-	for (U32 i = 0; i < mBakedTextureDatas.size(); i++)
+	for (LLAvatarXmlInfo::mesh_info_list_t::const_iterator meshinfo_iter = sAvatarXmlInfo->mMeshInfoList.begin();
+		 meshinfo_iter != sAvatarXmlInfo->mMeshInfoList.end(); 
+		 ++meshinfo_iter)
 	{
-		deleteAndClear(mBakedTextureDatas[i].mTexLayerSet);
-		mBakedTextureDatas[i].mMeshes.clear();
+		const LLAvatarXmlInfo::LLAvatarMeshInfo *info = *meshinfo_iter;
+		const std::string &type = info->mType;
+		S32 lod = info->mLOD;
 
-		for (morph_list_t::iterator iter2 = mBakedTextureDatas[i].mMaskedMorphs.begin();
-			 iter2 != mBakedTextureDatas[i].mMaskedMorphs.end(); iter2++)
+		LLAvatarJointMesh* mesh = NULL;
+		U8 mesh_id = 0;
+		BOOL found_mesh_id = FALSE;
+
+		/* if (type == "hairMesh")
+			switch(lod)
+			  case 0:
+				mesh = &mHairMesh0; */
+		for (LLAvatarAppearanceDictionary::Meshes::const_iterator mesh_iter = LLAvatarAppearanceDictionary::getInstance()->getMeshes().begin();
+			 mesh_iter != LLAvatarAppearanceDictionary::getInstance()->getMeshes().end();
+			 ++mesh_iter)
 		{
-			LLMaskedMorph* masked_morph = (*iter2);
-			delete masked_morph;
+			const EMeshIndex mesh_index = mesh_iter->first;
+			const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_iter->second;
+			if (type.compare(mesh_dict->mName) == 0)
+			{
+				mesh_id = mesh_index;
+				found_mesh_id = TRUE;
+				break;
+			}
+		}
+
+		if (found_mesh_id)
+		{
+			if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size())
+			{
+				mesh = mMeshLOD[mesh_id]->mMeshParts[lod];
+			}
+			else
+			{
+				llwarns << "Avatar file: <mesh> has invalid lod setting " << lod << llendl;
+				return FALSE;
+			}
+		}
+		else 
+		{
+			llwarns << "Ignoring unrecognized mesh type: " << type << llendl;
+			return FALSE;
+		}
+
+		//	llinfos << "Parsing mesh data for " << type << "..." << llendl;
+
+		// If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings.
+		// Do not touch!!!
+		mesh->setColor( 1.0f, 1.0f, 1.0f, 1.0f );
+
+		LLPolyMesh *poly_mesh = NULL;
+
+		if (!info->mReferenceMeshName.empty())
+		{
+			polymesh_map_t::const_iterator polymesh_iter = mMeshes.find(info->mReferenceMeshName);
+			if (polymesh_iter != mMeshes.end())
+			{
+				poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second);
+				poly_mesh->setAvatar(this);
+			}
+			else
+			{
+				// This should never happen
+				LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL;
+			}
+		}
+		else
+		{
+			poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName);
+			poly_mesh->setAvatar(this);
+		}
+
+		if( !poly_mesh )
+		{
+			llwarns << "Failed to load mesh of type " << type << llendl;
+			return FALSE;
+		}
+
+		// Multimap insert
+		mMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh));
+	
+		mesh->setMesh( poly_mesh );
+		mesh->setLOD( info->mMinPixelArea );
+
+		for (LLAvatarXmlInfo::LLAvatarMeshInfo::morph_info_list_t::const_iterator xmlinfo_iter = info->mPolyMorphTargetInfoList.begin();
+			 xmlinfo_iter != info->mPolyMorphTargetInfoList.end(); 
+			 ++xmlinfo_iter)
+		{
+			const LLAvatarXmlInfo::LLAvatarMeshInfo::morph_info_pair_t *info_pair = &(*xmlinfo_iter);
+			LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh());
+			if (!param->setInfo((LLPolyMorphTargetInfo*)info_pair->first))
+			{
+				delete param;
+				return FALSE;
+			}
+			else
+			{
+				if (info_pair->second)
+				{
+					addSharedVisualParam(param);
+				}
+				else
+				{
+					addVisualParam(param);
+				}
+			}				
 		}
 	}
+
+	return TRUE;
 }
 
-using namespace LLAvatarAppearanceDefines;
+//-----------------------------------------------------------------------------
+// loadLayerSets()
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::loadLayersets()
+{
+	BOOL success = TRUE;
+	for (LLAvatarXmlInfo::layer_info_list_t::const_iterator layerset_iter = sAvatarXmlInfo->mLayerInfoList.begin();
+		 layerset_iter != sAvatarXmlInfo->mLayerInfoList.end(); 
+		 ++layerset_iter)
+	{
+		// Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
+		LLTexLayerSetInfo *layerset_info = *layerset_iter;
+		layerset_info->createVisualParams(this);
+	}
+	return success;
+}
+
+
 
 // virtual
 BOOL LLAvatarAppearance::isValid() const
@@ -273,4 +1176,494 @@ BOOL LLAvatarAppearance::isWearingWearableType(LLWearableType::EType type) const
 	return FALSE;
 }
 
+//-----------------------------------------------------------------------------
+// allocateCollisionVolumes()
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::allocateCollisionVolumes( U32 num )
+{
+	deleteAndClearArray(mCollisionVolumes);
+	mNumCollisionVolumes = 0;
+
+	mCollisionVolumes = new LLAvatarJointCollisionVolume[num];
+	if (!mCollisionVolumes)
+	{
+		return FALSE;
+	}
+
+	mNumCollisionVolumes = num;
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarBoneInfo::parseXml()
+//-----------------------------------------------------------------------------
+BOOL LLAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
+{
+	if (node->hasName("bone"))
+	{
+		mIsJoint = TRUE;
+		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+		if (!node->getFastAttributeString(name_string, mName))
+		{
+			llwarns << "Bone without name" << llendl;
+			return FALSE;
+		}
+	}
+	else if (node->hasName("collision_volume"))
+	{
+		mIsJoint = FALSE;
+		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+		if (!node->getFastAttributeString(name_string, mName))
+		{
+			mName = "Collision Volume";
+		}
+	}
+	else
+	{
+		llwarns << "Invalid node " << node->getName() << llendl;
+		return FALSE;
+	}
+
+	static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
+	if (!node->getFastAttributeVector3(pos_string, mPos))
+	{
+		llwarns << "Bone without position" << llendl;
+		return FALSE;
+	}
+
+	static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot");
+	if (!node->getFastAttributeVector3(rot_string, mRot))
+	{
+		llwarns << "Bone without rotation" << llendl;
+		return FALSE;
+	}
+	
+	static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+	if (!node->getFastAttributeVector3(scale_string, mScale))
+	{
+		llwarns << "Bone without scale" << llendl;
+		return FALSE;
+	}
+
+	if (mIsJoint)
+	{
+		static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
+		if (!node->getFastAttributeVector3(pivot_string, mPivot))
+		{
+			llwarns << "Bone without pivot" << llendl;
+			return FALSE;
+		}
+	}
+
+	// parse children
+	LLXmlTreeNode* child;
+	for( child = node->getFirstChild(); child; child = node->getNextChild() )
+	{
+		LLAvatarBoneInfo *child_info = new LLAvatarBoneInfo;
+		if (!child_info->parseXml(child))
+		{
+			delete child_info;
+			return FALSE;
+		}
+		mChildList.push_back(child_info);
+	}
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarSkeletonInfo::parseXml()
+//-----------------------------------------------------------------------------
+BOOL LLAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
+{
+	static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones");
+	if (!node->getFastAttributeS32(num_bones_string, mNumBones))
+	{
+		llwarns << "Couldn't find number of bones." << llendl;
+		return FALSE;
+	}
+
+	static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes");
+	node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes);
+
+	LLXmlTreeNode* child;
+	for( child = node->getFirstChild(); child; child = node->getNextChild() )
+	{
+		LLAvatarBoneInfo *info = new LLAvatarBoneInfo;
+		if (!info->parseXml(child))
+		{
+			delete info;
+			llwarns << "Error parsing bone in skeleton file" << llendl;
+			return FALSE;
+		}
+		mBoneInfoList.push_back(info);
+	}
+	return TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root)
+{
+	LLXmlTreeNode* node = root->getChildByName( "skeleton" );
+	if( !node )
+	{
+		llwarns << "avatar file: missing <skeleton>" << llendl;
+		return FALSE;
+	}
+
+	LLXmlTreeNode* child;
+
+	// SKELETON DISTORTIONS
+	for (child = node->getChildByName( "param" );
+		 child;
+		 child = node->getNextNamedChild())
+	{
+		if (!child->getChildByName("param_skeleton"))
+		{
+			if (child->getChildByName("param_morph"))
+			{
+				llwarns << "Can't specify morph param in skeleton definition." << llendl;
+			}
+			else
+			{
+				llwarns << "Unknown param type." << llendl;
+			}
+			continue;
+		}
+		
+		LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo;
+		if (!info->parseXml(child))
+		{
+			delete info;
+			return FALSE;
+		}
+
+		mSkeletalDistortionInfoList.push_back(info);
+	}
+
+	// ATTACHMENT POINTS
+	for (child = node->getChildByName( "attachment_point" );
+		 child;
+		 child = node->getNextNamedChild())
+	{
+		LLAvatarAttachmentInfo* info = new LLAvatarAttachmentInfo();
+
+		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+		if (!child->getFastAttributeString(name_string, info->mName))
+		{
+			llwarns << "No name supplied for attachment point." << llendl;
+			delete info;
+			continue;
+		}
+
+		static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint");
+		if (!child->getFastAttributeString(joint_string, info->mJointName))
+		{
+			llwarns << "No bone declared in attachment point " << info->mName << llendl;
+			delete info;
+			continue;
+		}
+
+		static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position");
+		if (child->getFastAttributeVector3(position_string, info->mPosition))
+		{
+			info->mHasPosition = TRUE;
+		}
+
+		static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation");
+		if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler))
+		{
+			info->mHasRotation = TRUE;
+		}
+		 static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
+		if (child->getFastAttributeS32(group_string, info->mGroup))
+		{
+			if (info->mGroup == -1)
+				info->mGroup = -1111; // -1 = none parsed, < -1 = bad value
+		}
+
+		static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
+		if (!child->getFastAttributeS32(id_string, info->mAttachmentID))
+		{
+			llwarns << "No id supplied for attachment point " << info->mName << llendl;
+			delete info;
+			continue;
+		}
+
+		static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice");
+		child->getFastAttributeS32(slot_string, info->mPieMenuSlice);
+			
+		static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person");
+		child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson);
+
+		static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud");
+		child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment);
+
+		mAttachmentInfoList.push_back(info);
+	}
+
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlMeshNodes(): parses <mesh> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root)
+{
+	for (LLXmlTreeNode* node = root->getChildByName( "mesh" );
+		 node;
+		 node = root->getNextNamedChild())
+	{
+		LLAvatarMeshInfo *info = new LLAvatarMeshInfo;
+
+		// attribute: type
+		static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type");
+		if( !node->getFastAttributeString( type_string, info->mType ) )
+		{
+			llwarns << "Avatar file: <mesh> is missing type attribute.  Ignoring element. " << llendl;
+			delete info;
+			return FALSE;  // Ignore this element
+		}
+		
+		static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod");
+		if (!node->getFastAttributeS32( lod_string, info->mLOD ))
+		{
+			llwarns << "Avatar file: <mesh> is missing lod attribute.  Ignoring element. " << llendl;
+			delete info;
+			return FALSE;  // Ignore this element
+		}
+
+		static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
+		if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) )
+		{
+			llwarns << "Avatar file: <mesh> is missing file_name attribute.  Ignoring: " << info->mType << llendl;
+			delete info;
+			return FALSE;  // Ignore this element
+		}
+
+		static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference");
+		node->getFastAttributeString( reference_string, info->mReferenceMeshName );
+		
+		// attribute: min_pixel_area
+		static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area");
+		static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width");
+		if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea ))
+		{
+			F32 min_pixel_area = 0.1f;
+			if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area ))
+			{
+				// this is square root of pixel area (sensible to use linear space in defining lods)
+				min_pixel_area = min_pixel_area * min_pixel_area;
+			}
+			info->mMinPixelArea = min_pixel_area;
+		}
+		
+		// Parse visual params for this node only if we haven't already
+		for (LLXmlTreeNode* child = node->getChildByName( "param" );
+			 child;
+			 child = node->getNextNamedChild())
+		{
+			if (!child->getChildByName("param_morph"))
+			{
+				if (child->getChildByName("param_skeleton"))
+				{
+					llwarns << "Can't specify skeleton param in a mesh definition." << llendl;
+				}
+				else
+				{
+					llwarns << "Unknown param type." << llendl;
+				}
+				continue;
+			}
+
+			LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo();
+			if (!morphinfo->parseXml(child))
+			{
+				delete morphinfo;
+				delete info;
+				return -1;
+			}
+			BOOL shared = FALSE;
+			static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared");
+			child->getFastAttributeBOOL(shared_string, shared);
+
+			info->mPolyMorphTargetInfoList.push_back(LLAvatarMeshInfo::morph_info_pair_t(morphinfo, shared));
+		}
+
+		mMeshInfoList.push_back(info);
+	}
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlColorNodes(): parses <global_color> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root)
+{
+	for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" );
+		 color_node;
+		 color_node = root->getNextNamedChild())
+	{
+		std::string global_color_name;
+		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+		if (color_node->getFastAttributeString( name_string, global_color_name ) )
+		{
+			if( global_color_name == "skin_color" )
+			{
+				if (mTexSkinColorInfo)
+				{
+					llwarns << "avatar file: multiple instances of skin_color" << llendl;
+					return FALSE;
+				}
+				mTexSkinColorInfo = new LLTexGlobalColorInfo;
+				if( !mTexSkinColorInfo->parseXml( color_node ) )
+				{
+					deleteAndClear(mTexSkinColorInfo);
+					llwarns << "avatar file: mTexSkinColor->parseXml() failed" << llendl;
+					return FALSE;
+				}
+			}
+			else if( global_color_name == "hair_color" )
+			{
+				if (mTexHairColorInfo)
+				{
+					llwarns << "avatar file: multiple instances of hair_color" << llendl;
+					return FALSE;
+				}
+				mTexHairColorInfo = new LLTexGlobalColorInfo;
+				if( !mTexHairColorInfo->parseXml( color_node ) )
+				{
+					deleteAndClear(mTexHairColorInfo);
+					llwarns << "avatar file: mTexHairColor->parseXml() failed" << llendl;
+					return FALSE;
+				}
+			}
+			else if( global_color_name == "eye_color" )
+			{
+				if (mTexEyeColorInfo)
+				{
+					llwarns << "avatar file: multiple instances of eye_color" << llendl;
+					return FALSE;
+				}
+				mTexEyeColorInfo = new LLTexGlobalColorInfo;
+				if( !mTexEyeColorInfo->parseXml( color_node ) )
+				{
+					llwarns << "avatar file: mTexEyeColor->parseXml() failed" << llendl;
+					return FALSE;
+				}
+			}
+		}
+	}
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlLayerNodes(): parses <layer_set> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root)
+{
+	for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" );
+		 layer_node;
+		 layer_node = root->getNextNamedChild())
+	{
+		LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo();
+		if( layer_info->parseXml( layer_node ) )
+		{
+			mLayerInfoList.push_back(layer_info);
+		}
+		else
+		{
+			delete layer_info;
+			llwarns << "avatar file: layer_set->parseXml() failed" << llendl;
+			return FALSE;
+		}
+	}
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root)
+{
+	LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" );
+	if( driver )
+	{
+		for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" );
+			 grand_child;
+			 grand_child = driver->getNextNamedChild())
+		{
+			if( grand_child->getChildByName( "param_driver" ) )
+			{
+				LLDriverParamInfo* driver_info = new LLDriverParamInfo();
+				if( driver_info->parseXml( grand_child ) )
+				{
+					mDriverInfoList.push_back(driver_info);
+				}
+				else
+				{
+					delete driver_info;
+					llwarns << "avatar file: driver_param->parseXml() failed" << llendl;
+					return FALSE;
+				}
+			}
+		}
+	}
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
+//-----------------------------------------------------------------------------
+BOOL LLAvatarAppearance::LLAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root)
+{
+	LLXmlTreeNode* masks = root->getChildByName( "morph_masks" );
+	if( !masks )
+	{
+		return FALSE;
+	}
+
+	for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" );
+		 grand_child;
+		 grand_child = masks->getNextNamedChild())
+	{
+		LLAvatarMorphInfo* info = new LLAvatarMorphInfo();
+
+		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name");
+		if (!grand_child->getFastAttributeString(name_string, info->mName))
+		{
+			llwarns << "No name supplied for morph mask." << llendl;
+			delete info;
+			continue;
+		}
+
+		static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region");
+		if (!grand_child->getFastAttributeString(region_string, info->mRegion))
+		{
+			llwarns << "No region supplied for morph mask." << llendl;
+			delete info;
+			continue;
+		}
+
+		static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer");
+		if (!grand_child->getFastAttributeString(layer_string, info->mLayer))
+		{
+			llwarns << "No layer supplied for morph mask." << llendl;
+			delete info;
+			continue;
+		}
+
+		// optional parameter. don't throw a warning if not present.
+		static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert");
+		grand_child->getFastAttributeBOOL(invert_string, info->mInvert);
+
+		mMorphMaskInfoList.push_back(info);
+	}
+
+	return TRUE;
+}
+
+
 
diff --git a/indra/llappearance/llavatarappearance.h b/indra/llappearance/llavatarappearance.h
index b2ab6b069f..38a54d904d 100644
--- a/indra/llappearance/llavatarappearance.h
+++ b/indra/llappearance/llavatarappearance.h
@@ -30,11 +30,17 @@
 #include "llcharacter.h"
 //#include "llframetimer.h"
 #include "llavatarappearancedefines.h"
-#include "lljoint.h"
+#include "llavatarjoint.h"
+#include "lldriverparam.h"
+#include "lltexlayer.h"
+#include "llviewervisualparam.h"
+#include "llxmltree.h"
 
 class LLTexLayerSet;
 class LLTexGlobalColor;
 class LLWearableData;
+class LLAvatarBoneInfo;
+class LLAvatarSkeletonInfo;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // LLAvatarAppearance
@@ -45,6 +51,9 @@ class LLAvatarAppearance : public LLCharacter
 {
 	LOG_CLASS(LLAvatarAppearance);
 
+protected:
+	struct LLAvatarXmlInfo;
+
 /********************************************************************************
  **                                                                            **
  **                    INITIALIZATION
@@ -57,6 +66,12 @@ public:
 	LLAvatarAppearance(LLWearableData* wearable_data);
 	virtual ~LLAvatarAppearance();
 
+	static void initClass(); // initializes static members
+	virtual BOOL		loadSkeletonNode();
+	virtual BOOL		loadMeshNodes();
+	virtual BOOL		loadLayersets();
+
+
 /**                    Initialization
  **                                                                            **
  *******************************************************************************/
@@ -69,16 +84,94 @@ public:
 	virtual bool 	isSelf() const { return false; } // True if this avatar is for this viewer's agent
 	virtual BOOL	isValid() const;
 	virtual BOOL	isUsingBakedTextures() const = 0;
+
+	bool isBuilt() const { return mIsBuilt; }
+
 	
 /**                    State
  **                                                                            **
  *******************************************************************************/
 
+/********************************************************************************
+ **                                                                            **
+ **                    SKELETON
+ **/
+
+public:
+	F32					getPelvisToFoot() const { return mPelvisToFoot; }
+
+	LLVector3			mHeadOffset; // current head position
+	LLAvatarJoint		*mRoot;
+
+	typedef std::map<std::string, LLJoint*> joint_map_t;
+	joint_map_t			mJointMap;
+
+protected:
+	static BOOL			parseSkeletonFile(const std::string& filename);
+	virtual void		buildCharacter();
+	virtual BOOL		loadAvatar();
+	virtual void		bodySizeChanged() = 0;
+	void 				computeBodySize();
+
+	BOOL				setupBone(const LLAvatarBoneInfo* info, LLJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
+	BOOL				buildSkeleton(const LLAvatarSkeletonInfo *info);
+protected:
+	BOOL				mIsBuilt; // state of deferred character building
+	S32					mNumJoints;
+	LLJoint*			mSkeleton;
+	
+	//--------------------------------------------------------------------
+	// Pelvis height adjustment members.
+	//--------------------------------------------------------------------
+public:
+	LLVector3			mBodySize;
+protected:
+	F32					mPelvisToFoot;
+
+	//--------------------------------------------------------------------
+	// Cached pointers to well known joints
+	//--------------------------------------------------------------------
+public:
+	LLJoint* 		mPelvisp;
+	LLJoint* 		mTorsop;
+	LLJoint* 		mChestp;
+	LLJoint* 		mNeckp;
+	LLJoint* 		mHeadp;
+	LLJoint* 		mSkullp;
+	LLJoint* 		mEyeLeftp;
+	LLJoint* 		mEyeRightp;
+	LLJoint* 		mHipLeftp;
+	LLJoint* 		mHipRightp;
+	LLJoint* 		mKneeLeftp;
+	LLJoint* 		mKneeRightp;
+	LLJoint* 		mAnkleLeftp;
+	LLJoint* 		mAnkleRightp;
+	LLJoint* 		mFootLeftp;
+	LLJoint* 		mFootRightp;
+	LLJoint* 		mWristLeftp;
+	LLJoint* 		mWristRightp;
+
+	//--------------------------------------------------------------------
+	// XML parse tree
+	//--------------------------------------------------------------------
+protected:
+	static LLXmlTree 	sXMLTree; // avatar config file
+	static LLXmlTree 	sSkeletonXMLTree; // avatar skeleton file
+
+	static LLAvatarSkeletonInfo* 					sAvatarSkeletonInfo;
+	static LLAvatarXmlInfo* 						sAvatarXmlInfo;
+
+
+/**                    Skeleton
+ **                                                                            **
+ *******************************************************************************/
+
 
 /********************************************************************************
  **                                                                            **
  **                    RENDERING
  **/
+public:
 	BOOL		mIsDummy; // for special views
 
 	//--------------------------------------------------------------------
@@ -109,6 +202,11 @@ public:
 protected:
 	virtual void	dirtyMesh(S32 priority) = 0; // Dirty the avatar mesh, with priority
 
+protected:
+	typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
+	polymesh_map_t 									mMeshes;
+	std::vector<LLAvatarJoint *> 					mMeshLOD;
+
 /**                    Meshes
  **                                                                            **
  *******************************************************************************/
@@ -182,12 +280,115 @@ protected:
 	typedef std::vector<BakedTextureData> 	bakedtexturedata_vec_t;
 	bakedtexturedata_vec_t 					mBakedTextureDatas;
 
+/********************************************************************************
+ **                                                                            **
+ **                    PHYSICS
+ **/
+
+	//--------------------------------------------------------------------
+	// Collision volumes
+	//--------------------------------------------------------------------
+public:
+  	S32			mNumCollisionVolumes;
+	LLAvatarJointCollisionVolume* mCollisionVolumes;
+protected:
+	BOOL		allocateCollisionVolumes(U32 num);
+
+/**                    Physics
+ **                                                                            **
+ *******************************************************************************/
 
 /********************************************************************************
  **                                                                            **
  **                    SUPPORT CLASSES
  **/
 
+	struct LLAvatarXmlInfo
+	{
+		LLAvatarXmlInfo();
+		~LLAvatarXmlInfo();
+
+		BOOL 	parseXmlSkeletonNode(LLXmlTreeNode* root);
+		BOOL 	parseXmlMeshNodes(LLXmlTreeNode* root);
+		BOOL 	parseXmlColorNodes(LLXmlTreeNode* root);
+		BOOL 	parseXmlLayerNodes(LLXmlTreeNode* root);
+		BOOL 	parseXmlDriverNodes(LLXmlTreeNode* root);
+		BOOL	parseXmlMorphNodes(LLXmlTreeNode* root);
+
+		struct LLAvatarMeshInfo
+		{
+			typedef std::pair<LLViewerVisualParamInfo*,BOOL> morph_info_pair_t; // LLPolyMorphTargetInfo stored here
+			typedef std::vector<morph_info_pair_t> morph_info_list_t;
+
+			LLAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {}
+			~LLAvatarMeshInfo()
+			{
+				morph_info_list_t::iterator iter;
+				for (iter = mPolyMorphTargetInfoList.begin(); iter != mPolyMorphTargetInfoList.end(); iter++)
+				{
+					delete iter->first;
+				}
+				mPolyMorphTargetInfoList.clear();
+			}
+
+			std::string mType;
+			S32			mLOD;
+			std::string	mMeshFileName;
+			std::string	mReferenceMeshName;
+			F32			mMinPixelArea;
+			morph_info_list_t mPolyMorphTargetInfoList;
+		};
+		typedef std::vector<LLAvatarMeshInfo*> mesh_info_list_t;
+		mesh_info_list_t mMeshInfoList;
+
+		typedef std::vector<LLViewerVisualParamInfo*> skeletal_distortion_info_list_t; // LLPolySkeletalDistortionInfo stored here
+		skeletal_distortion_info_list_t mSkeletalDistortionInfoList;
+
+		struct LLAvatarAttachmentInfo
+		{
+			LLAvatarAttachmentInfo()
+				: mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(FALSE),
+				  mIsHUDAttachment(FALSE), mHasPosition(FALSE), mHasRotation(FALSE) {}
+			std::string mName;
+			std::string mJointName;
+			LLVector3 mPosition;
+			LLVector3 mRotationEuler;
+			S32 mGroup;
+			S32 mAttachmentID;
+			S32 mPieMenuSlice;
+			BOOL mVisibleFirstPerson;
+			BOOL mIsHUDAttachment;
+			BOOL mHasPosition;
+			BOOL mHasRotation;
+		};
+		typedef std::vector<LLAvatarAttachmentInfo*> attachment_info_list_t;
+		attachment_info_list_t mAttachmentInfoList;
+
+		LLTexGlobalColorInfo *mTexSkinColorInfo;
+		LLTexGlobalColorInfo *mTexHairColorInfo;
+		LLTexGlobalColorInfo *mTexEyeColorInfo;
+
+		typedef std::vector<LLTexLayerSetInfo*> layer_info_list_t;
+		layer_info_list_t mLayerInfoList;
+
+		typedef std::vector<LLDriverParamInfo*> driver_info_list_t;
+		driver_info_list_t mDriverInfoList;
+
+		struct LLAvatarMorphInfo
+		{
+			LLAvatarMorphInfo()
+				: mInvert(FALSE) {}
+			std::string mName;
+			std::string mRegion;
+			std::string mLayer;
+			BOOL mInvert;
+		};
+
+		typedef std::vector<LLAvatarMorphInfo*> morph_info_list_t;
+		morph_info_list_t	mMorphMaskInfoList;
+	};
+
+
 	class LLMaskedMorph
 	{
 	public:
@@ -197,7 +398,9 @@ protected:
 		BOOL				mInvert;
 		std::string			mLayer;
 	};
-
+/**                    Support Classes
+ **                                                                            **
+ *******************************************************************************/
 };
 
 #endif // LL_AVATAR_APPEARANCE_H
diff --git a/indra/llappearance/llavatarjoint.cpp b/indra/llappearance/llavatarjoint.cpp
new file mode 100644
index 0000000000..809a261633
--- /dev/null
+++ b/indra/llappearance/llavatarjoint.cpp
@@ -0,0 +1,261 @@
+/** 
+ * @file llavatarjoint.cpp
+ * @brief Implementation of LLAvatarJoint class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "llavatarjoint.h"
+
+#include "llgl.h"
+#include "llrender.h"
+#include "llmath.h"
+#include "llglheaders.h"
+#include "llrendersphere.h"
+#include "llavatarappearance.h"
+//#include "pipeline.h"
+
+#define DEFAULT_LOD 0.0f
+
+const S32 MIN_PIXEL_AREA_3PASS_HAIR = 64*64;
+
+//-----------------------------------------------------------------------------
+// Static Data
+//-----------------------------------------------------------------------------
+BOOL					LLAvatarJoint::sDisableLOD = FALSE;
+
+//-----------------------------------------------------------------------------
+// LLAvatarJoint()
+// Class Constructor
+//-----------------------------------------------------------------------------
+LLAvatarJoint::LLAvatarJoint()
+	:       LLJoint()
+{
+	init();
+}
+
+
+//-----------------------------------------------------------------------------
+// LLAvatarJoint()
+// Class Constructor
+//-----------------------------------------------------------------------------
+LLAvatarJoint::LLAvatarJoint(const std::string &name, LLJoint *parent)
+	:	LLJoint(name, parent)
+{
+	init();
+}
+
+
+void LLAvatarJoint::init()
+{
+	mValid = FALSE;
+	mComponents = SC_JOINT | SC_BONE | SC_AXES;
+	mMinPixelArea = DEFAULT_LOD;
+	mPickName = PN_DEFAULT;
+	mVisible = TRUE;
+	mMeshID = 0;
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLAvatarJoint()
+// Class Destructor
+//-----------------------------------------------------------------------------
+LLAvatarJoint::~LLAvatarJoint()
+{
+}
+
+
+//--------------------------------------------------------------------
+// setValid()
+//--------------------------------------------------------------------
+void LLAvatarJoint::setValid( BOOL valid, BOOL recursive )
+{
+	//----------------------------------------------------------------
+	// set visibility for this joint
+	//----------------------------------------------------------------
+	mValid = valid;
+	
+	//----------------------------------------------------------------
+	// set visibility for children
+	//----------------------------------------------------------------
+	if (recursive)
+	{
+		for (child_list_t::iterator iter = mChildren.begin();
+			 iter != mChildren.end(); ++iter)
+		{
+			LLAvatarJoint* joint = (LLAvatarJoint*)(*iter);
+			joint->setValid(valid, TRUE);
+		}
+	}
+
+}
+
+//--------------------------------------------------------------------
+// isTransparent()
+//--------------------------------------------------------------------
+BOOL LLAvatarJoint::isTransparent()
+{
+	return FALSE;
+}
+
+//--------------------------------------------------------------------
+// setSkeletonComponents()
+//--------------------------------------------------------------------
+void LLAvatarJoint::setSkeletonComponents( U32 comp, BOOL recursive )
+{
+	mComponents = comp;
+	if (recursive)
+	{
+		for (child_list_t::iterator iter = mChildren.begin();
+			 iter != mChildren.end(); ++iter)
+		{
+			LLAvatarJoint* joint = (LLAvatarJoint*)(*iter);
+			joint->setSkeletonComponents(comp, recursive);
+		}
+	}
+}
+
+void LLAvatarJoint::setVisible(BOOL visible, BOOL recursive)
+{
+	mVisible = visible;
+
+	if (recursive)
+	{
+		for (child_list_t::iterator iter = mChildren.begin();
+			 iter != mChildren.end(); ++iter)
+		{
+			LLAvatarJoint* joint = (LLAvatarJoint*)(*iter);
+			joint->setVisible(visible, recursive);
+		}
+	}
+}
+
+
+void LLAvatarJoint::setMeshesToChildren()
+{
+	removeAllChildren();
+	for (std::vector<LLAvatarJointMesh*>::iterator iter = mMeshParts.begin();
+		iter != mMeshParts.end(); iter++)
+	{
+		addChild((LLAvatarJoint*) *iter);
+	}
+}
+//-----------------------------------------------------------------------------
+// LLAvatarJointCollisionVolume()
+//-----------------------------------------------------------------------------
+
+LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume()
+{
+	mUpdateXform = FALSE;
+}
+
+LLAvatarJointCollisionVolume::LLAvatarJointCollisionVolume(const std::string &name, LLJoint *parent) : LLAvatarJoint(name, parent)
+{
+	
+}
+
+LLVector3 LLAvatarJointCollisionVolume::getVolumePos(LLVector3 &offset)
+{
+	mUpdateXform = TRUE;
+	
+	LLVector3 result = offset;
+	result.scaleVec(getScale());
+	result.rotVec(getWorldRotation());
+	result += getWorldPosition();
+
+	return result;
+}
+
+void LLAvatarJointCollisionVolume::renderCollision()
+{
+	updateWorldMatrix();
+	
+	gGL.pushMatrix();
+	gGL.multMatrix( &mXform.getWorldMatrix().mMatrix[0][0] );
+
+	gGL.diffuseColor3f( 0.f, 0.f, 1.f );
+	
+	gGL.begin(LLRender::LINES);
+	
+	LLVector3 v[] = 
+	{
+		LLVector3(1,0,0),
+		LLVector3(-1,0,0),
+		LLVector3(0,1,0),
+		LLVector3(0,-1,0),
+
+		LLVector3(0,0,-1),
+		LLVector3(0,0,1),
+	};
+
+	//sides
+	gGL.vertex3fv(v[0].mV); 
+	gGL.vertex3fv(v[2].mV);
+
+	gGL.vertex3fv(v[0].mV); 
+	gGL.vertex3fv(v[3].mV);
+
+	gGL.vertex3fv(v[1].mV); 
+	gGL.vertex3fv(v[2].mV);
+
+	gGL.vertex3fv(v[1].mV); 
+	gGL.vertex3fv(v[3].mV);
+
+
+	//top
+	gGL.vertex3fv(v[0].mV); 
+	gGL.vertex3fv(v[4].mV);
+
+	gGL.vertex3fv(v[1].mV); 
+	gGL.vertex3fv(v[4].mV);
+
+	gGL.vertex3fv(v[2].mV); 
+	gGL.vertex3fv(v[4].mV);
+
+	gGL.vertex3fv(v[3].mV); 
+	gGL.vertex3fv(v[4].mV);
+
+
+	//bottom
+	gGL.vertex3fv(v[0].mV); 
+	gGL.vertex3fv(v[5].mV);
+
+	gGL.vertex3fv(v[1].mV); 
+	gGL.vertex3fv(v[5].mV);
+
+	gGL.vertex3fv(v[2].mV); 
+	gGL.vertex3fv(v[5].mV);
+
+	gGL.vertex3fv(v[3].mV); 
+	gGL.vertex3fv(v[5].mV);
+
+	gGL.end();
+
+	gGL.popMatrix();
+}
+
+
+// End
diff --git a/indra/llappearance/llavatarjoint.h b/indra/llappearance/llavatarjoint.h
new file mode 100644
index 0000000000..cbfc1b73ea
--- /dev/null
+++ b/indra/llappearance/llavatarjoint.h
@@ -0,0 +1,127 @@
+/** 
+ * @file llavatarjoint.h
+ * @brief Implementation of LLAvatarJoint class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLAVATARJOINT_H
+#define LL_LLAVATARJOINT_H
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "lljoint.h"
+#include "lljointpickname.h"
+
+class LLFace;
+class LLAvatarJointMesh;
+
+//-----------------------------------------------------------------------------
+// class LLViewerJoint
+//-----------------------------------------------------------------------------
+class LLAvatarJoint :
+	public LLJoint
+{
+public:
+	LLAvatarJoint();
+	LLAvatarJoint(const std::string &name, LLJoint *parent = NULL);
+	virtual ~LLAvatarJoint();
+
+	// Gets the validity of this joint
+	BOOL getValid() { return mValid; }
+
+	// Sets the validity of this joint
+	virtual void setValid( BOOL valid, BOOL recursive=FALSE );
+
+	// Returns true if this object is transparent.
+	// This is used to determine in which order to draw objects.
+	virtual BOOL isTransparent();
+
+	// Returns true if this object should inherit scale modifiers from its immediate parent
+	virtual BOOL inheritScale() { return FALSE; }
+
+
+	enum Components
+	{
+		SC_BONE		= 1,
+		SC_JOINT	= 2,
+		SC_AXES		= 4
+	};
+
+	// Selects which skeleton components to draw
+	void setSkeletonComponents( U32 comp, BOOL recursive = TRUE );
+
+	// Returns which skeleton components are enables for drawing
+	U32 getSkeletonComponents() { return mComponents; }
+
+	// Sets the level of detail for this node as a minimum
+	// pixel area threshold.  If the current pixel area for this
+	// object is less than the specified threshold, the node is
+	// not traversed.  In addition, if a value is specified (not
+	// default of 0.0), and the pixel area is larger than the
+	// specified minimum, the node is rendered, but no other siblings
+	// of this node under the same parent will be.
+	F32 getLOD() { return mMinPixelArea; }
+	void setLOD( F32 pixelArea ) { mMinPixelArea = pixelArea; }
+	
+	void setPickName(LLJointPickName name) { mPickName = name; }
+	LLJointPickName getPickName() { return mPickName; }
+
+	void setVisible( BOOL visible, BOOL recursive );
+
+	// Takes meshes in mMeshParts and sets each one as a child joint
+	void setMeshesToChildren();
+
+public:
+	static BOOL	sDisableLOD;
+	std::vector<LLAvatarJointMesh*> mMeshParts; //LLViewerJointMesh*
+	void setMeshID( S32 id ) {mMeshID = id;}
+
+protected:
+	void init();
+
+	BOOL		mValid;
+	U32			mComponents;
+	F32			mMinPixelArea;
+	LLJointPickName	mPickName;
+	BOOL		mVisible;
+	S32			mMeshID;
+};
+
+class LLAvatarJointCollisionVolume : public LLAvatarJoint
+{
+public:
+	LLAvatarJointCollisionVolume();
+	LLAvatarJointCollisionVolume(const std::string &name, LLJoint *parent = NULL);
+	virtual ~LLAvatarJointCollisionVolume() {};
+
+	virtual BOOL inheritScale() { return TRUE; }
+
+	void renderCollision();
+
+	LLVector3 getVolumePos(LLVector3 &offset);
+};
+
+#endif // LL_LLAVATARJOINT_H
+
+
diff --git a/indra/llappearance/llavatarjointmesh.cpp b/indra/llappearance/llavatarjointmesh.cpp
new file mode 100755
index 0000000000..92c213126a
--- /dev/null
+++ b/indra/llappearance/llavatarjointmesh.cpp
@@ -0,0 +1,359 @@
+/** 
+ * @file LLAvatarJointMesh.cpp
+ * @brief Implementation of LLAvatarJointMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "linden_common.h"
+#include "imageids.h"
+#include "llfasttimer.h"
+#include "llrender.h"
+
+#include "llavatarjointmesh.h"
+#include "llavatarappearance.h"
+//#include "llapr.h"
+//#include "llbox.h"
+//#include "lldrawable.h"
+//#include "lldrawpoolavatar.h"
+//#include "lldrawpoolbump.h"
+//#include "lldynamictexture.h"
+//#include "llface.h"
+//#include "llgldbg.h"
+//#include "llglheaders.h"
+#include "lltexlayer.h"
+//#include "llviewercamera.h"
+//#include "llviewercontrol.h"
+//#include "llviewertexturelist.h"
+//#include "llsky.h"
+//#include "pipeline.h"
+//#include "llviewershadermgr.h"
+#include "llmath.h"
+#include "v4math.h"
+#include "m3math.h"
+#include "m4math.h"
+#include "llmatrix4a.h"
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh::LLSkinJoint
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// LLSkinJoint
+//-----------------------------------------------------------------------------
+LLSkinJoint::LLSkinJoint()
+{
+	mJoint       = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// ~LLSkinJoint
+//-----------------------------------------------------------------------------
+LLSkinJoint::~LLSkinJoint()
+{
+	mJoint = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// LLSkinJoint::setupSkinJoint()
+//-----------------------------------------------------------------------------
+BOOL LLSkinJoint::setupSkinJoint( LLAvatarJoint *joint)
+{
+	// find the named joint
+	mJoint = joint;
+	if ( !mJoint )
+	{
+		llinfos << "Can't find joint" << llendl;
+	}
+
+	// compute the inverse root skin matrix
+	mRootToJointSkinOffset.clearVec();
+
+	LLVector3 rootSkinOffset;
+	while (joint)
+	{
+		rootSkinOffset += joint->getSkinOffset();
+		joint = (LLAvatarJoint*)joint->getParent();
+	}
+
+	mRootToJointSkinOffset = -rootSkinOffset;
+	mRootToParentJointSkinOffset = mRootToJointSkinOffset;
+	mRootToParentJointSkinOffset += mJoint->getSkinOffset();
+
+	return TRUE;
+}
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+
+BOOL LLAvatarJointMesh::sPipelineRender = FALSE;
+EAvatarRenderPass LLAvatarJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE;
+U32 LLAvatarJointMesh::sClothingMaskImageName = 0;
+LLColor4 LLAvatarJointMesh::sClothingInnerColor;
+
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh()
+//-----------------------------------------------------------------------------
+LLAvatarJointMesh::LLAvatarJointMesh()
+	:
+	mTexture( NULL ),
+	mLayerSet( NULL ),
+	mTestImageName( 0 ),
+	mFaceIndexCount(0),
+	mIsTransparent(FALSE)
+{
+
+	mColor[0] = 1.0f;
+	mColor[1] = 1.0f;
+	mColor[2] = 1.0f;
+	mColor[3] = 1.0f;
+	mShiny = 0.0f;
+	mCullBackFaces = TRUE;
+
+	mMesh = NULL;
+
+	mNumSkinJoints = 0;
+	mSkinJoints = NULL;
+
+	mFace = NULL;
+
+	mMeshID = 0;
+	mUpdateXform = FALSE;
+
+	mValid = FALSE;
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLAvatarJointMesh()
+// Class Destructor
+//-----------------------------------------------------------------------------
+LLAvatarJointMesh::~LLAvatarJointMesh()
+{
+	mMesh = NULL;
+	mTexture = NULL;
+	freeSkinData();
+}
+
+
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh::allocateSkinData()
+//-----------------------------------------------------------------------------
+BOOL LLAvatarJointMesh::allocateSkinData( U32 numSkinJoints )
+{
+	mSkinJoints = new LLSkinJoint[ numSkinJoints ];
+	mNumSkinJoints = numSkinJoints;
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh::freeSkinData()
+//-----------------------------------------------------------------------------
+void LLAvatarJointMesh::freeSkinData()
+{
+	mNumSkinJoints = 0;
+	delete [] mSkinJoints;
+	mSkinJoints = NULL;
+}
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::getColor()
+//--------------------------------------------------------------------
+void LLAvatarJointMesh::getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha )
+{
+	*red   = mColor[0];
+	*green = mColor[1];
+	*blue  = mColor[2];
+	*alpha = mColor[3];
+}
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::setColor()
+//--------------------------------------------------------------------
+void LLAvatarJointMesh::setColor( F32 red, F32 green, F32 blue, F32 alpha )
+{
+	mColor[0] = red;
+	mColor[1] = green;
+	mColor[2] = blue;
+	mColor[3] = alpha;
+}
+
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::getTexture()
+//--------------------------------------------------------------------
+//LLViewerTexture *LLAvatarJointMesh::getTexture()
+//{
+//	return mTexture;
+//}
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::setTexture()
+//--------------------------------------------------------------------
+void LLAvatarJointMesh::setTexture( LLGLTexture *texture )
+{
+	mTexture = texture;
+
+	// texture and dynamic_texture are mutually exclusive
+	if( texture )
+	{
+		mLayerSet = NULL;
+		//texture->bindTexture(0);
+		//texture->setClamp(TRUE, TRUE);
+	}
+}
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::setLayerSet()
+// Sets the shape texture (takes precedence over normal texture)
+//--------------------------------------------------------------------
+void LLAvatarJointMesh::setLayerSet( LLTexLayerSet* layer_set )
+{
+	mLayerSet = layer_set;
+	
+	// texture and dynamic_texture are mutually exclusive
+	if( layer_set )
+	{
+		mTexture = NULL;
+	}
+}
+
+
+
+//--------------------------------------------------------------------
+// LLAvatarJointMesh::getMesh()
+//--------------------------------------------------------------------
+LLPolyMesh *LLAvatarJointMesh::getMesh()
+{
+	return mMesh;
+}
+
+//-----------------------------------------------------------------------------
+// LLAvatarJointMesh::setMesh()
+//-----------------------------------------------------------------------------
+void LLAvatarJointMesh::setMesh( LLPolyMesh *mesh )
+{
+	// set the mesh pointer
+	mMesh = mesh;
+
+	// release any existing skin joints
+	freeSkinData();
+
+	if ( mMesh == NULL )
+	{
+		return;
+	}
+
+	// acquire the transform from the mesh object
+	setPosition( mMesh->getPosition() );
+	setRotation( mMesh->getRotation() );
+	setScale( mMesh->getScale() );
+
+	// create skin joints if necessary
+	if ( mMesh->hasWeights() && !mMesh->isLOD())
+	{
+		U32 numJointNames = mMesh->getNumJointNames();
+		
+		allocateSkinData( numJointNames );
+		std::string *jointNames = mMesh->getJointNames();
+
+		U32 jn;
+		for (jn = 0; jn < numJointNames; jn++)
+		{
+			//llinfos << "Setting up joint " << jointNames[jn] << llendl;
+			LLAvatarJoint* joint = (LLAvatarJoint*)(getRoot()->findJoint(jointNames[jn]) );
+			mSkinJoints[jn].setupSkinJoint( joint );
+		}
+	}
+
+	// setup joint array
+	if (!mMesh->isLOD())
+	{
+		setupJoint((LLAvatarJoint*)getRoot());
+	}
+
+//	llinfos << "joint render entries: " << mMesh->mJointRenderData.count() << llendl;
+}
+
+//-----------------------------------------------------------------------------
+// setupJoint()
+//-----------------------------------------------------------------------------
+void LLAvatarJointMesh::setupJoint(LLAvatarJoint* current_joint)
+{
+//	llinfos << "Mesh: " << getName() << llendl;
+
+//	S32 joint_count = 0;
+	U32 sj;
+	for (sj=0; sj<mNumSkinJoints; sj++)
+	{
+		LLSkinJoint &js = mSkinJoints[sj];
+
+		if (js.mJoint != current_joint)
+		{
+			continue;
+		}
+
+		// we've found a skinjoint for this joint..
+
+		// is the last joint in the array our parent?
+		if(mMesh->mJointRenderData.count() && mMesh->mJointRenderData[mMesh->mJointRenderData.count() - 1]->mWorldMatrix == &current_joint->getParent()->getWorldMatrix())
+		{
+			// ...then just add ourselves
+			LLAvatarJoint* jointp = js.mJoint;
+			mMesh->mJointRenderData.put(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
+//			llinfos << "joint " << joint_count << js.mJoint->getName() << llendl;
+//			joint_count++;
+		}
+		// otherwise add our parent and ourselves
+		else
+		{
+			mMesh->mJointRenderData.put(new LLJointRenderData(&current_joint->getParent()->getWorldMatrix(), NULL));
+//			llinfos << "joint " << joint_count << current_joint->getParent()->getName() << llendl;
+//			joint_count++;
+			mMesh->mJointRenderData.put(new LLJointRenderData(&current_joint->getWorldMatrix(), &js));
+//			llinfos << "joint " << joint_count << current_joint->getName() << llendl;
+//			joint_count++;
+		}
+	}
+
+	// depth-first traversal
+	for (LLJoint::child_list_t::iterator iter = current_joint->mChildren.begin();
+		 iter != current_joint->mChildren.end(); ++iter)
+	{
+		LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter);
+		setupJoint(child_joint);
+	}
+}
+
+
+// End
diff --git a/indra/llappearance/llavatarjointmesh.h b/indra/llappearance/llavatarjointmesh.h
new file mode 100755
index 0000000000..dcd202bdaf
--- /dev/null
+++ b/indra/llappearance/llavatarjointmesh.h
@@ -0,0 +1,140 @@
+/** 
+ * @file llavatarjointmesh.h
+ * @brief Implementation of LLAvatarJointMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLAVATARJOINTMESH_H
+#define LL_LLAVATARJOINTMESH_H
+
+#include "llavatarjoint.h"
+#include "llgltexture.h"
+#include "llpolymesh.h"
+#include "v4color.h"
+
+class LLDrawable;
+class LLFace;
+class LLCharacter;
+class LLTexLayerSet;
+
+typedef enum e_avatar_render_pass
+{
+	AVATAR_RENDER_PASS_SINGLE,
+	AVATAR_RENDER_PASS_CLOTHING_INNER,
+	AVATAR_RENDER_PASS_CLOTHING_OUTER
+} EAvatarRenderPass;
+
+class LLSkinJoint
+{
+public:
+	LLSkinJoint();
+	~LLSkinJoint();
+	BOOL setupSkinJoint( LLAvatarJoint *joint);
+
+	LLAvatarJoint	*mJoint;
+	LLVector3		mRootToJointSkinOffset;
+	LLVector3		mRootToParentJointSkinOffset;
+};
+
+//-----------------------------------------------------------------------------
+// class LLViewerJointMesh
+//-----------------------------------------------------------------------------
+class LLAvatarJointMesh : public LLAvatarJoint
+{
+	friend class LLAvatarAppearance;
+protected:
+	LLColor4					mColor;			// color value
+// 	LLColor4					mSpecular;		// specular color (always white for now)
+	F32							mShiny;			// shiny value
+	LLPointer<LLGLTexture>		mTexture;		// ptr to a global texture
+	LLTexLayerSet*				mLayerSet;		// ptr to a layer set owned by the avatar
+	U32 						mTestImageName;		// handle to a temporary texture for previewing uploads
+	LLPolyMesh*					mMesh;			// ptr to a global polymesh
+	BOOL						mCullBackFaces;	// true by default
+	LLFace*						mFace;			// ptr to a face w/ AGP copy of mesh
+
+	U32							mFaceIndexCount;
+	BOOL						mIsTransparent;
+
+	U32							mNumSkinJoints;
+	LLSkinJoint*				mSkinJoints;
+	S32							mMeshID;
+
+public:
+	static BOOL					sPipelineRender;
+	//RN: this is here for testing purposes
+	static U32					sClothingMaskImageName;
+	static EAvatarRenderPass	sRenderPass;
+	static LLColor4				sClothingInnerColor;
+
+public:
+	// Constructor
+	LLAvatarJointMesh();
+
+	// Destructor
+	virtual ~LLAvatarJointMesh();
+
+	// Gets the shape color
+	void getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha );
+
+	// Sets the shape color
+	void setColor( F32 red, F32 green, F32 blue, F32 alpha );
+
+	// Sets the shininess
+	void setSpecular( const LLColor4& color, F32 shiny ) { /*mSpecular = color;*/ mShiny = shiny; };
+
+	// Sets the shape texture
+	void setTexture( LLGLTexture *texture );
+
+	void setTestTexture( U32 name ) { mTestImageName = name; }
+
+	// Sets layer set responsible for a dynamic shape texture (takes precedence over normal texture)
+	void setLayerSet( LLTexLayerSet* layer_set );
+
+	// Gets the poly mesh
+	LLPolyMesh *getMesh();
+
+	// Sets the poly mesh
+	void setMesh( LLPolyMesh *mesh );
+
+	// Sets up joint matrix data for rendering
+	void setupJoint(LLAvatarJoint* current_joint);
+
+	// Render time method to upload batches of joint matrices
+	void uploadJointMatrices();
+
+	// Sets ID for picking
+	void setMeshID( S32 id ) {mMeshID = id;}
+
+	// Gets ID for picking
+	S32 getMeshID() { return mMeshID; }	
+
+private:
+	// Allocate skin data
+	BOOL allocateSkinData( U32 numSkinJoints );
+
+	// Free skin data
+	void freeSkinData();
+};
+
+#endif // LL_LLAVATARJOINTMESH_H
diff --git a/indra/llappearance/llpolymesh.cpp b/indra/llappearance/llpolymesh.cpp
new file mode 100644
index 0000000000..b1370ab1e3
--- /dev/null
+++ b/indra/llappearance/llpolymesh.cpp
@@ -0,0 +1,1050 @@
+/** 
+ * @file llpolymesh.cpp
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "linden_common.h"
+#include "llpolymesh.h"
+#include "llfasttimer.h"
+#include "llmemory.h"
+
+//#include "llviewercontrol.h"
+#include "llxmltree.h"
+#include "llavatarappearance.h"
+#include "llwearable.h"
+#include "lldir.h"
+#include "llvolume.h"
+#include "llendianswizzle.h"
+
+
+#define HEADER_ASCII "Linden Mesh 1.0"
+#define HEADER_BINARY "Linden Binary Mesh 1.0"
+
+//extern LLControlGroup gSavedSettings;                           // read only
+
+LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
+					     const std::string &name);
+LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
+					     const LLVector3 &direction,
+					     const std::string &name);
+LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
+                                            F32 scale,
+                                            const std::string &name);
+
+//-----------------------------------------------------------------------------
+// Global table of loaded LLPolyMeshes
+//-----------------------------------------------------------------------------
+LLPolyMesh::LLPolyMeshSharedDataTable LLPolyMesh::sGlobalSharedMeshList;
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData()
+//-----------------------------------------------------------------------------
+LLPolyMeshSharedData::LLPolyMeshSharedData()
+{
+        mNumVertices = 0;
+        mBaseCoords = NULL;
+        mBaseNormals = NULL;
+        mBaseBinormals = NULL;
+        mTexCoords = NULL;
+        mDetailTexCoords = NULL;
+        mWeights = NULL;
+        mHasWeights = FALSE;
+        mHasDetailTexCoords = FALSE;
+
+        mNumFaces = 0;
+        mFaces = NULL;
+
+        mNumJointNames = 0;
+        mJointNames = NULL;
+
+        mTriangleIndices = NULL;
+        mNumTriangleIndices = 0;
+
+        mReferenceData = NULL;
+
+        mLastIndexOffset = -1;
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMeshSharedData()
+//-----------------------------------------------------------------------------
+LLPolyMeshSharedData::~LLPolyMeshSharedData()
+{
+        freeMeshData();
+        for_each(mMorphData.begin(), mMorphData.end(), DeletePointer());
+        mMorphData.clear();
+}
+
+//-----------------------------------------------------------------------------
+// setupLOD()
+//-----------------------------------------------------------------------------
+void LLPolyMeshSharedData::setupLOD(LLPolyMeshSharedData* reference_data)
+{
+        mReferenceData = reference_data;
+
+        if (reference_data)
+        {
+                mBaseCoords = reference_data->mBaseCoords;
+                mBaseNormals = reference_data->mBaseNormals;
+                mBaseBinormals = reference_data->mBaseBinormals;
+                mTexCoords = reference_data->mTexCoords;
+                mDetailTexCoords = reference_data->mDetailTexCoords;
+                mWeights = reference_data->mWeights;
+                mHasWeights = reference_data->mHasWeights;
+                mHasDetailTexCoords = reference_data->mHasDetailTexCoords;
+        }
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::freeMeshData()
+//-----------------------------------------------------------------------------
+void LLPolyMeshSharedData::freeMeshData()
+{
+        if (!mReferenceData)
+        {
+                mNumVertices = 0;
+
+                ll_aligned_free_16(mBaseCoords);
+                mBaseCoords = NULL;
+
+                ll_aligned_free_16(mBaseNormals);
+                mBaseNormals = NULL;
+
+                ll_aligned_free_16(mBaseBinormals);
+                mBaseBinormals = NULL;
+
+                ll_aligned_free_16(mTexCoords);
+                mTexCoords = NULL;
+
+                ll_aligned_free_16(mDetailTexCoords);
+                mDetailTexCoords = NULL;
+
+                ll_aligned_free_16(mWeights);
+                mWeights = NULL;
+        }
+
+        mNumFaces = 0;
+        delete [] mFaces;
+        mFaces = NULL;
+
+        mNumJointNames = 0;
+        delete [] mJointNames;
+        mJointNames = NULL;
+
+        delete [] mTriangleIndices;
+        mTriangleIndices = NULL;
+
+//      mVertFaceMap.deleteAllData();
+}
+
+// compate_int is used by the qsort function to sort the index array
+int compare_int(const void *a, const void *b);
+
+//-----------------------------------------------------------------------------
+// genIndices()
+//-----------------------------------------------------------------------------
+void LLPolyMeshSharedData::genIndices(S32 index_offset)
+{
+        if (index_offset == mLastIndexOffset)
+        {
+                return;
+        }
+
+        delete []mTriangleIndices;
+        mTriangleIndices = new U32[mNumTriangleIndices];
+
+        S32 cur_index = 0;
+        for (S32 i = 0; i < mNumFaces; i++)
+        {
+                mTriangleIndices[cur_index] = mFaces[i][0] + index_offset;
+                cur_index++;
+                mTriangleIndices[cur_index] = mFaces[i][1] + index_offset;
+                cur_index++;
+                mTriangleIndices[cur_index] = mFaces[i][2] + index_offset;
+                cur_index++;
+        }
+
+        mLastIndexOffset = index_offset;
+}
+
+//--------------------------------------------------------------------
+// LLPolyMeshSharedData::getNumKB()
+//--------------------------------------------------------------------
+U32 LLPolyMeshSharedData::getNumKB()
+{
+        U32 num_kb = sizeof(LLPolyMesh);
+
+        if (!isLOD())
+        {
+                num_kb += mNumVertices *
+                        ( sizeof(LLVector3) +   // coords
+                          sizeof(LLVector3) +             // normals
+                          sizeof(LLVector2) );    // texCoords
+        }
+
+        if (mHasDetailTexCoords && !isLOD())
+        {
+                num_kb += mNumVertices * sizeof(LLVector2);     // detailTexCoords
+        }
+
+        if (mHasWeights && !isLOD())
+        {
+                num_kb += mNumVertices * sizeof(float);         // weights
+        }
+
+        num_kb += mNumFaces * sizeof(LLPolyFace);       // faces
+
+        num_kb /= 1024;
+        return num_kb;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::allocateVertexData()
+//-----------------------------------------------------------------------------
+BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices )
+{
+        U32 i;
+        mBaseCoords = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
+        mBaseNormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
+        mBaseBinormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
+        mTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
+        mDetailTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
+        mWeights = (F32*) ll_aligned_malloc_16(numVertices*sizeof(F32));
+        for (i = 0; i < numVertices; i++)
+        {
+			mBaseCoords[i].clear();
+			mBaseNormals[i].clear();
+			mBaseBinormals[i].clear();
+			mTexCoords[i].clear();
+            mWeights[i] = 0.f;
+        }
+        mNumVertices = numVertices;
+        return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::allocateFaceData()
+//-----------------------------------------------------------------------------
+BOOL LLPolyMeshSharedData::allocateFaceData( U32 numFaces )
+{
+        mFaces = new LLPolyFace[ numFaces ];
+        mNumFaces = numFaces;
+        mNumTriangleIndices = mNumFaces * 3;
+        return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMeshSharedData::allocateJointNames()
+//-----------------------------------------------------------------------------
+BOOL LLPolyMeshSharedData::allocateJointNames( U32 numJointNames )
+{
+        mJointNames = new std::string[ numJointNames ];
+        mNumJointNames = numJointNames;
+        return TRUE;
+}
+
+//--------------------------------------------------------------------
+// LLPolyMeshSharedData::loadMesh()
+//--------------------------------------------------------------------
+BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
+{
+        //-------------------------------------------------------------------------
+        // Open the file
+        //-------------------------------------------------------------------------
+        if(fileName.empty())
+        {
+                llerrs << "Filename is Empty!" << llendl;
+                return FALSE;
+        }
+        LLFILE* fp = LLFile::fopen(fileName, "rb");                     /*Flawfinder: ignore*/
+        if (!fp)
+        {
+                llerrs << "can't open: " << fileName << llendl;
+                return FALSE;
+        }
+
+        //-------------------------------------------------------------------------
+        // Read a chunk
+        //-------------------------------------------------------------------------
+        char header[128];               /*Flawfinder: ignore*/
+        if (fread(header, sizeof(char), 128, fp) != 128)
+        {
+                llwarns << "Short read" << llendl;
+        }
+
+        //-------------------------------------------------------------------------
+        // Check for proper binary header
+        //-------------------------------------------------------------------------
+        BOOL status = FALSE;
+        if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 )       /*Flawfinder: ignore*/
+        {
+                lldebugs << "Loading " << fileName << llendl;
+
+                //----------------------------------------------------------------
+                // File Header (seek past it)
+                //----------------------------------------------------------------
+                fseek(fp, 24, SEEK_SET);
+
+                //----------------------------------------------------------------
+                // HasWeights
+                //----------------------------------------------------------------
+                U8 hasWeights;
+                size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
+                if (numRead != 1)
+                {
+                        llerrs << "can't read HasWeights flag from " << fileName << llendl;
+                        return FALSE;
+                }
+                if (!isLOD())
+                {
+                        mHasWeights = (hasWeights==0) ? FALSE : TRUE;
+                }
+
+                //----------------------------------------------------------------
+                // HasDetailTexCoords
+                //----------------------------------------------------------------
+                U8 hasDetailTexCoords;
+                numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
+                if (numRead != 1)
+                {
+                        llerrs << "can't read HasDetailTexCoords flag from " << fileName << llendl;
+                        return FALSE;
+                }
+
+                //----------------------------------------------------------------
+                // Position
+                //----------------------------------------------------------------
+                LLVector3 position;
+                numRead = fread(position.mV, sizeof(float), 3, fp);
+                llendianswizzle(position.mV, sizeof(float), 3);
+                if (numRead != 3)
+                {
+                        llerrs << "can't read Position from " << fileName << llendl;
+                        return FALSE;
+                }
+                setPosition( position );
+
+                //----------------------------------------------------------------
+                // Rotation
+                //----------------------------------------------------------------
+                LLVector3 rotationAngles;
+                numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
+                llendianswizzle(rotationAngles.mV, sizeof(float), 3);
+                if (numRead != 3)
+                {
+                        llerrs << "can't read RotationAngles from " << fileName << llendl;
+                        return FALSE;
+                }
+
+                U8 rotationOrder;
+                numRead = fread(&rotationOrder, sizeof(U8), 1, fp);
+
+                if (numRead != 1)
+                {
+                        llerrs << "can't read RotationOrder from " << fileName << llendl;
+                        return FALSE;
+                }
+
+                rotationOrder = 0;
+
+                setRotation( mayaQ(     rotationAngles.mV[0],
+                                        rotationAngles.mV[1],
+                                        rotationAngles.mV[2],
+                                        (LLQuaternion::Order)rotationOrder ) );
+
+                //----------------------------------------------------------------
+                // Scale
+                //----------------------------------------------------------------
+                LLVector3 scale;
+                numRead = fread(scale.mV, sizeof(float), 3, fp);
+                llendianswizzle(scale.mV, sizeof(float), 3);
+                if (numRead != 3)
+                {
+                        llerrs << "can't read Scale from " << fileName << llendl;
+                        return FALSE;
+                }
+                setScale( scale );
+
+                //-------------------------------------------------------------------------
+                // Release any existing mesh geometry
+                //-------------------------------------------------------------------------
+                freeMeshData();
+
+                U16 numVertices = 0;
+
+                //----------------------------------------------------------------
+                // NumVertices
+                //----------------------------------------------------------------
+                if (!isLOD())
+                {
+                        numRead = fread(&numVertices, sizeof(U16), 1, fp);
+                        llendianswizzle(&numVertices, sizeof(U16), 1);
+                        if (numRead != 1)
+                        {
+                                llerrs << "can't read NumVertices from " << fileName << llendl;
+                                return FALSE;
+                        }
+
+                        allocateVertexData( numVertices );      
+
+						for (U16 i = 0; i < numVertices; ++i)
+						{
+							//----------------------------------------------------------------
+							// Coords
+							//----------------------------------------------------------------
+							numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp);
+							llendianswizzle(&mBaseCoords[i], sizeof(float), 3);
+							if (numRead != 3)
+							{
+									llerrs << "can't read Coordinates from " << fileName << llendl;
+									return FALSE;
+							}
+						}
+
+						for (U16 i = 0; i < numVertices; ++i)
+						{
+							//----------------------------------------------------------------
+							// Normals
+							//----------------------------------------------------------------
+							numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp);
+							llendianswizzle(&mBaseNormals[i], sizeof(float), 3);
+							if (numRead != 3)
+							{
+									llerrs << " can't read Normals from " << fileName << llendl;
+									return FALSE;
+							}
+						}
+
+						for (U16 i = 0; i < numVertices; ++i)
+						{
+							//----------------------------------------------------------------
+							// Binormals
+							//----------------------------------------------------------------
+							numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp);
+							llendianswizzle(&mBaseBinormals[i], sizeof(float), 3);
+							if (numRead != 3)
+							{
+									llerrs << " can't read Binormals from " << fileName << llendl;
+									return FALSE;
+							}
+						}
+
+                        //----------------------------------------------------------------
+                        // TexCoords
+                        //----------------------------------------------------------------
+                        numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
+                        llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
+                        if (numRead != numVertices)
+                        {
+                                llerrs << "can't read TexCoords from " << fileName << llendl;
+                                return FALSE;
+                        }
+
+                        //----------------------------------------------------------------
+                        // DetailTexCoords
+                        //----------------------------------------------------------------
+                        if (mHasDetailTexCoords)
+                        {
+                                numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
+                                llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
+                                if (numRead != numVertices)
+                                {
+                                        llerrs << "can't read DetailTexCoords from " << fileName << llendl;
+                                        return FALSE;
+                                }
+                        }
+
+                        //----------------------------------------------------------------
+                        // Weights
+                        //----------------------------------------------------------------
+                        if (mHasWeights)
+                        {
+                                numRead = fread(mWeights, sizeof(float), numVertices, fp);
+                                llendianswizzle(mWeights, sizeof(float), numVertices);
+                                if (numRead != numVertices)
+                                {
+                                        llerrs << "can't read Weights from " << fileName << llendl;
+                                        return FALSE;
+                                }
+                        }
+                }
+
+                //----------------------------------------------------------------
+                // NumFaces
+                //----------------------------------------------------------------
+                U16 numFaces;
+                numRead = fread(&numFaces, sizeof(U16), 1, fp);
+                llendianswizzle(&numFaces, sizeof(U16), 1);
+                if (numRead != 1)
+                {
+                        llerrs << "can't read NumFaces from " << fileName << llendl;
+                        return FALSE;
+                }
+                allocateFaceData( numFaces );
+
+
+                //----------------------------------------------------------------
+                // Faces
+                //----------------------------------------------------------------
+                U32 i;
+                U32 numTris = 0;
+                for (i = 0; i < numFaces; i++)
+                {
+                        S16 face[3];
+                        numRead = fread(face, sizeof(U16), 3, fp);
+                        llendianswizzle(face, sizeof(U16), 3);
+                        if (numRead != 3)
+                        {
+                                llerrs << "can't read Face[" << i << "] from " << fileName << llendl;
+                                return FALSE;
+                        }
+                        if (mReferenceData)
+                        {
+                                llassert(face[0] < mReferenceData->mNumVertices);
+                                llassert(face[1] < mReferenceData->mNumVertices);
+                                llassert(face[2] < mReferenceData->mNumVertices);
+                        }
+                        
+                        if (isLOD())
+                        {
+                                // store largest index in case of LODs
+                                for (S32 j = 0; j < 3; j++)
+                                {
+                                        if (face[j] > mNumVertices - 1)
+                                        {
+                                                mNumVertices = face[j] + 1;
+                                        }
+                                }
+                        }
+                        mFaces[i][0] = face[0];
+                        mFaces[i][1] = face[1];
+                        mFaces[i][2] = face[2];
+
+//                      S32 j;
+//                      for(j = 0; j < 3; j++)
+//                      {
+//                              LLDynamicArray<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
+//                              if (!face_list)
+//                              {
+//                                      face_list = new LLDynamicArray<S32>;
+//                                      mVertFaceMap.addData(face[j], face_list);
+//                              }
+//                              face_list->put(i);
+//                      }
+
+                        numTris++;
+                }
+
+                lldebugs << "verts: " << numVertices 
+                         << ", faces: "   << numFaces
+                         << ", tris: "    << numTris
+                         << llendl;
+
+                //----------------------------------------------------------------
+                // NumSkinJoints
+                //----------------------------------------------------------------
+                if (!isLOD())
+                {
+                        U16 numSkinJoints = 0;
+                        if ( mHasWeights )
+                        {
+                                numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
+                                llendianswizzle(&numSkinJoints, sizeof(U16), 1);
+                                if (numRead != 1)
+                                {
+                                        llerrs << "can't read NumSkinJoints from " << fileName << llendl;
+                                        return FALSE;
+                                }
+                                allocateJointNames( numSkinJoints );
+                        }
+
+                        //----------------------------------------------------------------
+                        // SkinJoints
+                        //----------------------------------------------------------------
+                        for (i=0; i < numSkinJoints; i++)
+                        {
+                                char jointName[64+1];
+                                numRead = fread(jointName, sizeof(jointName)-1, 1, fp);
+                                jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination
+                                if (numRead != 1)
+                                {
+                                        llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl;
+                                        return FALSE;
+                                }
+
+                                std::string *jn = &mJointNames[i];
+                                *jn = jointName;
+                        }
+
+                        //-------------------------------------------------------------------------
+                        // look for morph section
+                        //-------------------------------------------------------------------------
+                        char morphName[64+1];
+                        morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
+                        while(fread(&morphName, sizeof(char), 64, fp) == 64)
+                        {
+                                if (!strcmp(morphName, "End Morphs"))
+                                {
+                                        // we reached the end of the morphs
+                                        break;
+                                }
+                                LLPolyMorphData* morph_data = new LLPolyMorphData(std::string(morphName));
+
+                                BOOL result = morph_data->loadBinary(fp, this);
+
+                                if (!result)
+                                {
+                                        delete morph_data;
+                                        continue;
+                                }
+
+                                mMorphData.insert(morph_data);
+
+                                if (!strcmp(morphName, "Breast_Female_Cleavage"))
+                                {
+                                        mMorphData.insert(clone_morph_param_cleavage(morph_data,
+                                                                                     .75f,
+                                                                                     "Breast_Physics_LeftRight_Driven"));
+                                }
+
+                                if (!strcmp(morphName, "Breast_Female_Cleavage"))
+                                {
+                                        mMorphData.insert(clone_morph_param_duplicate(morph_data,
+										      "Breast_Physics_InOut_Driven"));
+                                }
+                                if (!strcmp(morphName, "Breast_Gravity"))
+                                {
+                                        mMorphData.insert(clone_morph_param_duplicate(morph_data,
+										      "Breast_Physics_UpDown_Driven"));
+                                }
+
+                                if (!strcmp(morphName, "Big_Belly_Torso"))
+                                {
+                                        mMorphData.insert(clone_morph_param_direction(morph_data,
+										      LLVector3(0,0,0.05f),
+										      "Belly_Physics_Torso_UpDown_Driven"));
+                                }
+
+                                if (!strcmp(morphName, "Big_Belly_Legs"))
+                                {
+                                        mMorphData.insert(clone_morph_param_direction(morph_data,
+										      LLVector3(0,0,0.05f),
+										      "Belly_Physics_Legs_UpDown_Driven"));
+                                }
+
+                                if (!strcmp(morphName, "skirt_belly"))
+                                {
+                                        mMorphData.insert(clone_morph_param_direction(morph_data,
+										      LLVector3(0,0,0.05f),
+										      "Belly_Physics_Skirt_UpDown_Driven"));
+                                }
+
+                                if (!strcmp(morphName, "Small_Butt"))
+                                {
+                                        mMorphData.insert(clone_morph_param_direction(morph_data,
+										      LLVector3(0,0,0.05f),
+										      "Butt_Physics_UpDown_Driven"));
+                                }
+                                if (!strcmp(morphName, "Small_Butt"))
+                                {
+                                        mMorphData.insert(clone_morph_param_direction(morph_data,
+										      LLVector3(0,0.03f,0),
+										      "Butt_Physics_LeftRight_Driven"));
+                                }
+                        }
+
+                        S32 numRemaps;
+                        if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
+                        {
+                                llendianswizzle(&numRemaps, sizeof(S32), 1);
+                                for (S32 i = 0; i < numRemaps; i++)
+                                {
+                                        S32 remapSrc;
+                                        S32 remapDst;
+                                        if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
+                                        {
+                                                llerrs << "can't read source vertex in vertex remap data" << llendl;
+                                                break;
+                                        }
+                                        if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
+                                        {
+                                                llerrs << "can't read destination vertex in vertex remap data" << llendl;
+                                                break;
+                                        }
+                                        llendianswizzle(&remapSrc, sizeof(S32), 1);
+                                        llendianswizzle(&remapDst, sizeof(S32), 1);
+
+                                        mSharedVerts[remapSrc] = remapDst;
+                                }
+                        }
+                }
+
+                status = TRUE;
+        }
+        else
+        {
+                llerrs << "invalid mesh file header: " << fileName << llendl;
+                status = FALSE;
+        }
+
+        if (0 == mNumJointNames)
+        {
+                allocateJointNames(1);
+        }
+
+        fclose( fp );
+
+        return status;
+}
+
+//-----------------------------------------------------------------------------
+// getSharedVert()
+//-----------------------------------------------------------------------------
+const S32 *LLPolyMeshSharedData::getSharedVert(S32 vert)
+{
+        if (mSharedVerts.count(vert) > 0)
+        {
+                return &mSharedVerts[vert];
+        }
+        return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// getUV()
+//-----------------------------------------------------------------------------
+const LLVector2 &LLPolyMeshSharedData::getUVs(U32 index)
+{
+        // TODO: convert all index variables to S32
+        llassert((S32)index < mNumVertices);
+
+        return mTexCoords[index];
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh)
+{       
+	LLMemType mt(LLMemType::MTYPE_AVATAR_MESH);
+
+	llassert(shared_data);
+
+	mSharedData = shared_data;
+	mReferenceMesh = reference_mesh;
+	mAvatarp = NULL;
+	mVertexData = NULL;
+
+	mCurVertexCount = 0;
+	mFaceIndexCount = 0;
+	mFaceIndexOffset = 0;
+	mFaceVertexCount = 0;
+	mFaceVertexOffset = 0;
+
+	if (shared_data->isLOD() && reference_mesh)
+	{
+		mCoords = reference_mesh->mCoords;
+		mNormals = reference_mesh->mNormals;
+		mScaledNormals = reference_mesh->mScaledNormals;
+		mBinormals = reference_mesh->mBinormals;
+		mScaledBinormals = reference_mesh->mScaledBinormals;
+		mTexCoords = reference_mesh->mTexCoords;
+		mClothingWeights = reference_mesh->mClothingWeights;
+	}
+	else
+	{
+		// Allocate memory without initializing every vector
+		// NOTE: This makes asusmptions about the size of LLVector[234]
+		S32 nverts = mSharedData->mNumVertices;
+		//make sure it's an even number of verts for alignment
+		nverts += nverts%2;
+		S32 nfloats = nverts * (
+					4 + //coords
+					4 + //normals
+					4 + //weights
+					2 + //coords
+					4 + //scaled normals
+					4 + //binormals
+					4); //scaled binormals
+
+		//use 16 byte aligned vertex data to make LLPolyMesh SSE friendly
+		mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4);
+		S32 offset = 0;
+		mCoords				= 	(LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mNormals			=	(LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mClothingWeights	= 	(LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mTexCoords			= 	(LLVector2*)(mVertexData + offset);  offset += 2*nverts;
+		mScaledNormals		=   (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mBinormals			=   (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
+		mScaledBinormals	=   (LLVector4a*)(mVertexData + offset); offset += 4*nverts; 
+		initializeForMorph();
+	}
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh::~LLPolyMesh()
+{
+        S32 i;
+        for (i = 0; i < mJointRenderData.count(); i++)
+        {
+                delete mJointRenderData[i];
+                mJointRenderData[i] = NULL;
+        }
+
+		ll_aligned_free_16(mVertexData);
+
+}
+
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh::getMesh()
+//-----------------------------------------------------------------------------
+LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_mesh)
+{
+        //-------------------------------------------------------------------------
+        // search for an existing mesh by this name
+        //-------------------------------------------------------------------------
+        LLPolyMeshSharedData* meshSharedData = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL);
+        if (meshSharedData)
+        {
+//              llinfos << "Polymesh " << name << " found in global mesh table." << llendl;
+                LLPolyMesh *poly_mesh = new LLPolyMesh(meshSharedData, reference_mesh);
+                return poly_mesh;
+        }
+
+        //-------------------------------------------------------------------------
+        // if not found, create a new one, add it to the list
+        //-------------------------------------------------------------------------
+        std::string full_path;
+        full_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,name);
+
+        LLPolyMeshSharedData *mesh_data = new LLPolyMeshSharedData();
+        if (reference_mesh)
+        {
+                mesh_data->setupLOD(reference_mesh->getSharedData());
+        }
+        if ( ! mesh_data->loadMesh( full_path ) )
+        {
+                delete mesh_data;
+                return NULL;
+        }
+
+        LLPolyMesh *poly_mesh = new LLPolyMesh(mesh_data, reference_mesh);
+
+//      llinfos << "Polymesh " << name << " added to global mesh table." << llendl;
+        sGlobalSharedMeshList[name] = poly_mesh->mSharedData;
+
+        return poly_mesh;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh::freeAllMeshes()
+//-----------------------------------------------------------------------------
+void LLPolyMesh::freeAllMeshes()
+{
+        // delete each item in the global lists
+        for_each(sGlobalSharedMeshList.begin(), sGlobalSharedMeshList.end(), DeletePairedPointer());
+        sGlobalSharedMeshList.clear();
+}
+
+LLPolyMeshSharedData *LLPolyMesh::getSharedData() const
+{
+        return mSharedData;
+}
+
+
+//--------------------------------------------------------------------
+// LLPolyMesh::dumpDiagInfo()
+//--------------------------------------------------------------------
+void LLPolyMesh::dumpDiagInfo()
+{
+        // keep track of totals
+        U32 total_verts = 0;
+        U32 total_faces = 0;
+        U32 total_kb = 0;
+
+        std::string buf;
+
+        llinfos << "-----------------------------------------------------" << llendl;
+        llinfos << "       Global PolyMesh Table (DEBUG only)" << llendl;
+        llinfos << "   Verts    Faces  Mem(KB) Name" << llendl;
+        llinfos << "-----------------------------------------------------" << llendl;
+
+        // print each loaded mesh, and it's memory usage
+        for(LLPolyMeshSharedDataTable::iterator iter = sGlobalSharedMeshList.begin();
+            iter != sGlobalSharedMeshList.end(); ++iter)
+        {
+                const std::string& mesh_name = iter->first;
+                LLPolyMeshSharedData* mesh = iter->second;
+
+                S32 num_verts = mesh->mNumVertices;
+                S32 num_faces = mesh->mNumFaces;
+                U32 num_kb = mesh->getNumKB();
+
+                buf = llformat("%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name.c_str());
+                llinfos << buf << llendl;
+
+                total_verts += num_verts;
+                total_faces += num_faces;
+                total_kb += num_kb;
+        }
+
+        llinfos << "-----------------------------------------------------" << llendl;
+        buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb );
+        llinfos << buf << llendl;
+        llinfos << "-----------------------------------------------------" << llendl;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableCoords()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getWritableCoords()
+{
+        return mCoords;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableNormals()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getWritableNormals()
+{
+        return mNormals;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableBinormals()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getWritableBinormals()
+{
+        return mBinormals;
+}
+
+
+//-----------------------------------------------------------------------------
+// getWritableClothingWeights()
+//-----------------------------------------------------------------------------
+LLVector4a       *LLPolyMesh::getWritableClothingWeights()
+{
+        return mClothingWeights;
+}
+
+//-----------------------------------------------------------------------------
+// getWritableTexCoords()
+//-----------------------------------------------------------------------------
+LLVector2       *LLPolyMesh::getWritableTexCoords()
+{
+        return mTexCoords;
+}
+
+//-----------------------------------------------------------------------------
+// getScaledNormals()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getScaledNormals()
+{
+        return mScaledNormals;
+}
+
+//-----------------------------------------------------------------------------
+// getScaledBinormals()
+//-----------------------------------------------------------------------------
+LLVector4a *LLPolyMesh::getScaledBinormals()
+{
+        return mScaledBinormals;
+}
+
+
+//-----------------------------------------------------------------------------
+// initializeForMorph()
+//-----------------------------------------------------------------------------
+void LLPolyMesh::initializeForMorph()
+{
+    LLVector4a::memcpyNonAliased16((F32*) mCoords, (F32*) mSharedData->mBaseCoords, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
+	LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2));
+
+	for (U32 i = 0; i < mSharedData->mNumVertices; ++i)
+	{
+		mClothingWeights[i].clear();
+	}
+}
+
+//-----------------------------------------------------------------------------
+// getMorphData()
+//-----------------------------------------------------------------------------
+LLPolyMorphData*        LLPolyMesh::getMorphData(const std::string& morph_name)
+{
+        if (!mSharedData)
+                return NULL;
+        for (LLPolyMeshSharedData::morphdata_list_t::iterator iter = mSharedData->mMorphData.begin();
+             iter != mSharedData->mMorphData.end(); ++iter)
+        {
+                LLPolyMorphData *morph_data = *iter;
+                if (morph_data->getName() == morph_name)
+                {
+                        return morph_data;
+                }
+        }
+        return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// removeMorphData()
+//-----------------------------------------------------------------------------
+// // erasing but not deleting seems bad, but fortunately we don't actually use this...
+// void LLPolyMesh::removeMorphData(LLPolyMorphData *morph_target)
+// {
+//      if (!mSharedData)
+//              return;
+//      mSharedData->mMorphData.erase(morph_target);
+// }
+
+//-----------------------------------------------------------------------------
+// deleteAllMorphData()
+//-----------------------------------------------------------------------------
+// void LLPolyMesh::deleteAllMorphData()
+// {
+//      if (!mSharedData)
+//              return;
+
+//      for_each(mSharedData->mMorphData.begin(), mSharedData->mMorphData.end(), DeletePointer());
+//      mSharedData->mMorphData.clear();
+// }
+
+//-----------------------------------------------------------------------------
+// getWritableWeights()
+//-----------------------------------------------------------------------------
+F32*    LLPolyMesh::getWritableWeights() const
+{
+        return mSharedData->mWeights;
+}
+
+// End
diff --git a/indra/llappearance/llpolymesh.h b/indra/llappearance/llpolymesh.h
new file mode 100644
index 0000000000..ef1dfb1adb
--- /dev/null
+++ b/indra/llappearance/llpolymesh.h
@@ -0,0 +1,369 @@
+/** 
+ * @file llpolymesh.h
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPOLYMESHINTERFACE_H
+#define LL_LLPOLYMESHINTERFACE_H
+
+#include <string>
+#include <map>
+#include "llstl.h"
+
+#include "v3math.h"
+#include "v2math.h"
+#include "llquaternion.h"
+#include "llpolymorph.h"
+#include "lljoint.h"
+//#include "lldarray.h"
+
+class LLSkinJoint;
+class LLAvatarAppearance;
+class LLWearable;
+
+//#define USE_STRIPS	// Use tri-strips for rendering.
+
+//-----------------------------------------------------------------------------
+// LLPolyFace
+// A set of 4 vertex indices.
+// An LLPolyFace can represent either a triangle or quad.
+// If the last index is -1, it's a triangle.
+//-----------------------------------------------------------------------------
+typedef S32 LLPolyFace[3];
+
+//struct PrimitiveGroup;
+
+//-----------------------------------------------------------------------------
+// LLPolyMesh
+// A polyhedra consisting of any number of triangles and quads.
+// All instances contain a set of faces, and optionally may include
+// faces grouped into named face sets.
+//-----------------------------------------------------------------------------
+class LLPolyMorphTarget;
+
+class LLPolyMeshSharedData
+{
+	friend class LLPolyMesh;
+private:
+	// transform data
+	LLVector3				mPosition;
+	LLQuaternion			mRotation;
+	LLVector3				mScale;
+							
+	// vertex data			
+	S32						mNumVertices;
+	LLVector4a				*mBaseCoords;
+	LLVector4a				*mBaseNormals;
+	LLVector4a				*mBaseBinormals;
+	LLVector2				*mTexCoords;
+	LLVector2				*mDetailTexCoords;
+	F32						*mWeights;
+	
+	BOOL					mHasWeights;
+	BOOL					mHasDetailTexCoords;
+
+	// face data			
+	S32						mNumFaces;
+	LLPolyFace				*mFaces;
+							
+	// face set data		
+	U32						mNumJointNames;
+	std::string*			mJointNames;
+
+	// morph targets
+	typedef std::set<LLPolyMorphData*> morphdata_list_t;
+	morphdata_list_t			mMorphData;
+
+	std::map<S32, S32> 			mSharedVerts;
+	
+	LLPolyMeshSharedData*		mReferenceData;
+	S32							mLastIndexOffset;
+
+public:
+	// Temporarily...
+	// Triangle indices
+	U32				mNumTriangleIndices;
+	U32				*mTriangleIndices;
+
+public:
+	LLPolyMeshSharedData();
+	~LLPolyMeshSharedData();
+
+private:
+	void setupLOD(LLPolyMeshSharedData* reference_data);
+
+	// Frees all mesh memory resources 
+	void freeMeshData();
+
+	void setPosition( const LLVector3 &pos ) { 	mPosition = pos; }
+	void setRotation( const LLQuaternion &rot ) { mRotation = rot; }
+	void setScale( const LLVector3 &scale ) { mScale = scale; }
+
+	BOOL allocateVertexData( U32 numVertices );
+
+	BOOL allocateFaceData( U32 numFaces );
+
+	BOOL allocateJointNames( U32 numJointNames );
+
+	// Retrieve the number of KB of memory used by this instance
+	U32 getNumKB();
+
+	// Load mesh data from file
+	BOOL loadMesh( const std::string& fileName );
+
+public:
+	void genIndices(S32 offset);
+
+	const LLVector2 &getUVs(U32 index);
+
+	const S32	*getSharedVert(S32 vert);
+
+	BOOL isLOD() { return (mReferenceData != NULL); }
+};
+
+
+class LLJointRenderData
+{
+public:
+	LLJointRenderData(const LLMatrix4* world_matrix, LLSkinJoint* skin_joint) : mWorldMatrix(world_matrix), mSkinJoint(skin_joint) {}
+	~LLJointRenderData(){}
+
+	const LLMatrix4*		mWorldMatrix;
+	LLSkinJoint*			mSkinJoint;
+};
+
+
+class LLPolyMesh
+{
+public:
+	
+	// Constructor
+	LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh);
+
+	// Destructor 
+	~LLPolyMesh();
+
+	// Requests a mesh by name.
+	// If the mesh already exists in the global mesh table, it is returned,
+	// otherwise it is loaded from file, added to the table, and returned.
+	static LLPolyMesh *getMesh( const std::string &name, LLPolyMesh* reference_mesh = NULL);
+
+	// Frees all loaded meshes.
+	// This should only be called once you know there are no outstanding
+	// references to these objects.  Generally, upon exit of the application.
+	static void freeAllMeshes();
+
+	//--------------------------------------------------------------------
+	// Transform Data Access
+	//--------------------------------------------------------------------
+	// Get position
+	const LLVector3 &getPosition() { 
+		llassert (mSharedData);
+		return mSharedData->mPosition; 
+	}
+
+	// Get rotation
+	const LLQuaternion &getRotation() { 
+		llassert (mSharedData);
+		return mSharedData->mRotation; 
+	}
+
+	// Get scale
+	const LLVector3 &getScale() { 
+		llassert (mSharedData);
+		return mSharedData->mScale; 
+	}
+
+	//--------------------------------------------------------------------
+	// Vertex Data Access
+	//--------------------------------------------------------------------
+	// Get number of vertices
+	U32 getNumVertices() { 
+		llassert (mSharedData);
+		return mSharedData->mNumVertices; 
+	}
+
+	// Returns whether or not the mesh has detail texture coords
+	BOOL hasDetailTexCoords() { 
+		llassert (mSharedData);
+		return mSharedData->mHasDetailTexCoords; 
+	}
+
+	// Returns whether or not the mesh has vertex weights
+	BOOL hasWeights() const{ 
+		llassert (mSharedData);
+		return mSharedData->mHasWeights; 
+	}
+
+	// Get coords
+	const LLVector4a	*getCoords() const{
+		return mCoords;
+	}
+
+	// non const version
+	LLVector4a *getWritableCoords();
+
+	// Get normals
+	const LLVector4a	*getNormals() const{ 
+		return mNormals; 
+	}
+
+	// Get normals
+	const LLVector4a	*getBinormals() const{ 
+		return mBinormals; 
+	}
+
+	// Get base mesh normals
+	const LLVector4a *getBaseNormals() const{
+		llassert(mSharedData);
+		return mSharedData->mBaseNormals;
+	}
+
+	// Get base mesh normals
+	const LLVector4a *getBaseBinormals() const{
+		llassert(mSharedData);
+		return mSharedData->mBaseBinormals;
+	}
+
+	// intermediate morphed normals and output normals
+	LLVector4a *getWritableNormals();
+	LLVector4a *getScaledNormals();
+
+	LLVector4a *getWritableBinormals();
+	LLVector4a *getScaledBinormals();
+
+	// Get texCoords
+	const LLVector2	*getTexCoords() const { 
+		return mTexCoords; 
+	}
+
+	// non const version
+	LLVector2 *getWritableTexCoords();
+
+	// Get detailTexCoords
+	const LLVector2	*getDetailTexCoords() const { 
+		llassert (mSharedData);
+		return mSharedData->mDetailTexCoords; 
+	}
+
+	// Get weights
+	const F32 *getWeights() const {
+		llassert (mSharedData);
+		return mSharedData->mWeights;
+	}
+
+	F32			*getWritableWeights() const;
+
+	LLVector4a	*getWritableClothingWeights();
+
+	const LLVector4a		*getClothingWeights()
+	{
+		return mClothingWeights;	
+	}
+
+	//--------------------------------------------------------------------
+	// Face Data Access
+	//--------------------------------------------------------------------
+	// Get number of faces
+	S32 getNumFaces() { 
+		llassert (mSharedData);
+		return mSharedData->mNumFaces; 
+	}
+
+	// Get faces
+	LLPolyFace *getFaces() { 
+		llassert (mSharedData);
+		return mSharedData->mFaces;
+	}
+
+	U32 getNumJointNames() { 
+		llassert (mSharedData);
+		return mSharedData->mNumJointNames; 
+	}
+
+	std::string *getJointNames() { 
+		llassert (mSharedData);
+		return mSharedData->mJointNames;
+	}
+
+	LLPolyMorphData*	getMorphData(const std::string& morph_name);
+// 	void	removeMorphData(LLPolyMorphData *morph_target);
+// 	void	deleteAllMorphData();
+
+	LLPolyMeshSharedData *getSharedData() const;
+	LLPolyMesh *getReferenceMesh() { return mReferenceMesh ? mReferenceMesh : this; }
+
+	// Get indices
+	U32*	getIndices() { return mSharedData ? mSharedData->mTriangleIndices : NULL; }
+
+	BOOL	isLOD() { return mSharedData && mSharedData->isLOD(); }
+
+	void setAvatar(LLAvatarAppearance* avatarp) { mAvatarp = avatarp; }
+	LLAvatarAppearance* getAvatar() { return mAvatarp; }
+
+	LLDynamicArray<LLJointRenderData*>	mJointRenderData;
+
+	U32				mFaceVertexOffset;
+	U32				mFaceVertexCount;
+	U32				mFaceIndexOffset;
+	U32				mFaceIndexCount;
+	U32				mCurVertexCount;
+private:
+	void initializeForMorph();
+
+	// Dumps diagnostic information about the global mesh table
+	static void dumpDiagInfo();
+
+protected:
+	// mesh data shared across all instances of a given mesh
+	LLPolyMeshSharedData	*mSharedData;
+	// Single array of floats for allocation / deletion
+	F32						*mVertexData;
+	// deformed vertices (resulting from application of morph targets)
+	LLVector4a				*mCoords;
+	// deformed normals (resulting from application of morph targets)
+	LLVector4a				*mScaledNormals;
+	// output normals (after normalization)
+	LLVector4a				*mNormals;
+	// deformed binormals (resulting from application of morph targets)
+	LLVector4a				*mScaledBinormals;
+	// output binormals (after normalization)
+	LLVector4a				*mBinormals;
+	// weight values that mark verts as clothing/skin
+	LLVector4a				*mClothingWeights;
+	// output texture coordinates
+	LLVector2				*mTexCoords;
+	
+	LLPolyMesh				*mReferenceMesh;
+
+	// global mesh list
+	typedef std::map<std::string, LLPolyMeshSharedData*> LLPolyMeshSharedDataTable; 
+	static LLPolyMeshSharedDataTable sGlobalSharedMeshList;
+
+	// Backlink only; don't make this an LLPointer.
+	LLAvatarAppearance* mAvatarp;
+};
+
+#endif // LL_LLPOLYMESHINTERFACE_H
+
diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp
new file mode 100644
index 0000000000..aa680894ff
--- /dev/null
+++ b/indra/llappearance/llpolymorph.cpp
@@ -0,0 +1,748 @@
+/** 
+ * @file llpolymorph.cpp
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+
+#include "llpolymorph.h"
+#include "llavatarappearance.h"
+#include "llavatarjoint.h"
+#include "llwearable.h"
+#include "llxmltree.h"
+#include "llendianswizzle.h"
+#include "llpolymesh.h"
+
+//#include "../tools/imdebug/imdebug.h"
+
+const F32 NORMAL_SOFTEN_FACTOR = 0.65f;
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphData()
+//-----------------------------------------------------------------------------
+LLPolyMorphData::LLPolyMorphData(const std::string& morph_name)
+	: mName(morph_name)
+{
+	mNumIndices = 0;
+	mCurrentIndex = 0;
+	mTotalDistortion = 0.f;
+	mAvgDistortion.clear();
+	mMaxDistortion = 0.f;
+	mVertexIndices = NULL;
+	mCoords = NULL;
+	mNormals = NULL;
+	mBinormals = NULL;
+	mTexCoords = NULL;
+
+	mMesh = NULL;
+}
+
+LLPolyMorphData::LLPolyMorphData(const LLPolyMorphData &rhs) :
+	mName(rhs.mName),
+	mNumIndices(rhs.mNumIndices),
+	mTotalDistortion(rhs.mTotalDistortion),
+	mAvgDistortion(rhs.mAvgDistortion),
+	mMaxDistortion(rhs.mMaxDistortion),
+	mVertexIndices(NULL),
+	mCoords(NULL),
+	mNormals(NULL),
+	mBinormals(NULL),
+	mTexCoords(NULL)
+{
+	const S32 numVertices = mNumIndices;
+
+	mCoords = new LLVector4a[numVertices];
+	mNormals = new LLVector4a[numVertices];
+	mBinormals = new LLVector4a[numVertices];
+	mTexCoords = new LLVector2[numVertices];
+	mVertexIndices = new U32[numVertices];
+	
+	for (S32 v=0; v < numVertices; v++)
+	{
+		mCoords[v] = rhs.mCoords[v];
+		mNormals[v] = rhs.mNormals[v];
+		mBinormals[v] = rhs.mBinormals[v];
+		mTexCoords[v] = rhs.mTexCoords[v];
+		mVertexIndices[v] = rhs.mVertexIndices[v];
+	}
+}
+
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMorphData()
+//-----------------------------------------------------------------------------
+LLPolyMorphData::~LLPolyMorphData()
+{
+	delete [] mVertexIndices;
+	delete [] mCoords;
+	delete [] mNormals;
+	delete [] mBinormals;
+	delete [] mTexCoords;
+}
+
+//-----------------------------------------------------------------------------
+// loadBinary()
+//-----------------------------------------------------------------------------
+BOOL LLPolyMorphData::loadBinary(LLFILE *fp, LLPolyMeshSharedData *mesh)
+{
+	S32 numVertices;
+	S32 numRead;
+
+	numRead = fread(&numVertices, sizeof(S32), 1, fp);
+	llendianswizzle(&numVertices, sizeof(S32), 1);
+	if (numRead != 1)
+	{
+		llwarns << "Can't read number of morph target vertices" << llendl;
+		return FALSE;
+	}
+
+	//-------------------------------------------------------------------------
+	// allocate vertices
+	//-------------------------------------------------------------------------
+	mCoords = new LLVector4a[numVertices];
+	mNormals = new LLVector4a[numVertices];
+	mBinormals = new LLVector4a[numVertices];
+	mTexCoords = new LLVector2[numVertices];
+	// Actually, we are allocating more space than we need for the skiplist
+	mVertexIndices = new U32[numVertices];
+	mNumIndices = 0;
+	mTotalDistortion = 0.f;
+	mMaxDistortion = 0.f;
+	mAvgDistortion.clear();
+	mMesh = mesh;
+
+	//-------------------------------------------------------------------------
+	// read vertices
+	//-------------------------------------------------------------------------
+	for(S32 v = 0; v < numVertices; v++)
+	{
+		numRead = fread(&mVertexIndices[v], sizeof(U32), 1, fp);
+		llendianswizzle(&mVertexIndices[v], sizeof(U32), 1);
+		if (numRead != 1)
+		{
+			llwarns << "Can't read morph target vertex number" << llendl;
+			return FALSE;
+		}
+
+		if (mVertexIndices[v] > 10000)
+		{
+			llerrs << "Bad morph index: " << mVertexIndices[v] << llendl;
+		}
+
+
+		numRead = fread(&mCoords[v], sizeof(F32), 3, fp);
+		llendianswizzle(&mCoords[v], sizeof(F32), 3);
+		if (numRead != 3)
+		{
+			llwarns << "Can't read morph target vertex coordinates" << llendl;
+			return FALSE;
+		}
+
+		F32 magnitude = mCoords[v].getLength3().getF32();
+		
+		mTotalDistortion += magnitude;
+		LLVector4a t;
+		t.setAbs(mCoords[v]);
+		mAvgDistortion.add(t);
+		
+		if (magnitude > mMaxDistortion)
+		{
+			mMaxDistortion = magnitude;
+		}
+
+		numRead = fread(&mNormals[v], sizeof(F32), 3, fp);
+		llendianswizzle(&mNormals[v], sizeof(F32), 3);
+		if (numRead != 3)
+		{
+			llwarns << "Can't read morph target normal" << llendl;
+			return FALSE;
+		}
+
+		numRead = fread(&mBinormals[v], sizeof(F32), 3, fp);
+		llendianswizzle(&mBinormals[v], sizeof(F32), 3);
+		if (numRead != 3)
+		{
+			llwarns << "Can't read morph target binormal" << llendl;
+			return FALSE;
+		}
+
+
+		numRead = fread(&mTexCoords[v].mV, sizeof(F32), 2, fp);
+		llendianswizzle(&mTexCoords[v].mV, sizeof(F32), 2);
+		if (numRead != 2)
+		{
+			llwarns << "Can't read morph target uv" << llendl;
+			return FALSE;
+		}
+
+		mNumIndices++;
+	}
+
+	mAvgDistortion.mul(1.f/(F32)mNumIndices);
+	mAvgDistortion.normalize3fast();
+
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTargetInfo()
+//-----------------------------------------------------------------------------
+LLPolyMorphTargetInfo::LLPolyMorphTargetInfo()
+	: mIsClothingMorph(FALSE)
+{
+}
+
+BOOL LLPolyMorphTargetInfo::parseXml(LLXmlTreeNode* node)
+{
+	llassert( node->hasName( "param" ) && node->getChildByName( "param_morph" ) );
+
+	if (!LLViewerVisualParamInfo::parseXml(node))
+		return FALSE;
+
+	// Get mixed-case name
+	static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+	if( !node->getFastAttributeString( name_string, mMorphName ) )
+	{
+		llwarns << "Avatar file: <param> is missing name attribute" << llendl;
+		return FALSE;  // Continue, ignoring this tag
+	}
+
+	static LLStdStringHandle clothing_morph_string = LLXmlTree::addAttributeString("clothing_morph");
+	node->getFastAttributeBOOL(clothing_morph_string, mIsClothingMorph);
+
+	LLXmlTreeNode *paramNode = node->getChildByName("param_morph");
+
+        if (NULL == paramNode)
+        {
+                llwarns << "Failed to getChildByName(\"param_morph\")"
+                        << llendl;
+                return FALSE;
+        }
+
+	for (LLXmlTreeNode* child_node = paramNode->getFirstChild();
+		 child_node;
+		 child_node = paramNode->getNextChild())
+	{
+		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+		if (child_node->hasName("volume_morph"))
+		{
+			std::string volume_name;
+			if (child_node->getFastAttributeString(name_string, volume_name))
+			{
+				LLVector3 scale;
+				static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+				child_node->getFastAttributeVector3(scale_string, scale);
+				
+				LLVector3 pos;
+				static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
+				child_node->getFastAttributeVector3(pos_string, pos);
+
+				mVolumeInfoList.push_back(LLPolyVolumeMorphInfo(volume_name,scale,pos));
+			}
+		}
+	}
+	
+	return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTarget()
+//-----------------------------------------------------------------------------
+LLPolyMorphTarget::LLPolyMorphTarget(LLPolyMesh *poly_mesh)
+	: mMorphData(NULL), mMesh(poly_mesh),
+	  mVertMask(NULL),
+	  mLastSex(SEX_FEMALE),
+	  mNumMorphMasksPending(0)
+{
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolyMorphTarget()
+//-----------------------------------------------------------------------------
+LLPolyMorphTarget::~LLPolyMorphTarget()
+{
+	if (mVertMask)
+	{
+		delete mVertMask;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// setInfo()
+//-----------------------------------------------------------------------------
+BOOL LLPolyMorphTarget::setInfo(LLPolyMorphTargetInfo* info)
+{
+	llassert(mInfo == NULL);
+	if (info->mID < 0)
+		return FALSE;
+	mInfo = info;
+	mID = info->mID;
+	setWeight(getDefaultWeight(), FALSE );
+
+	LLAvatarAppearance* avatarp = mMesh->getAvatar();
+	LLPolyMorphTargetInfo::volume_info_list_t::iterator iter;
+	for (iter = getInfo()->mVolumeInfoList.begin(); iter != getInfo()->mVolumeInfoList.end(); iter++)
+	{
+		LLPolyVolumeMorphInfo *volume_info = &(*iter);
+		for (S32 i = 0; i < avatarp->mNumCollisionVolumes; i++)
+		{
+			if (avatarp->mCollisionVolumes[i].getName() == volume_info->mName)
+			{
+				mVolumeMorphs.push_back(LLPolyVolumeMorph(&avatarp->mCollisionVolumes[i],
+														  volume_info->mScale,
+														  volume_info->mPos));
+				break;
+			}
+		}
+	}
+
+	std::string morph_param_name = getInfo()->mMorphName;
+	
+	mMorphData = mMesh->getMorphData(morph_param_name);
+	if (!mMorphData)
+	{
+		const std::string driven_tag = "_Driven";
+		U32 pos = morph_param_name.find(driven_tag);
+		if (pos > 0)
+		{
+			morph_param_name = morph_param_name.substr(0,pos);
+			mMorphData = mMesh->getMorphData(morph_param_name);
+		}
+	}
+	if (!mMorphData)
+	{
+		llwarns << "No morph target named " << morph_param_name << " found in mesh." << llendl;
+		return FALSE;  // Continue, ignoring this tag
+	}
+	return TRUE;
+}
+
+/*virtual*/ LLViewerVisualParam* LLPolyMorphTarget::cloneParam(LLWearable* wearable) const
+{
+	LLPolyMorphTarget *new_param = new LLPolyMorphTarget(mMesh);
+	*new_param = *this;
+	return new_param;
+}
+
+#if 0 // obsolete
+//-----------------------------------------------------------------------------
+// parseData()
+//-----------------------------------------------------------------------------
+BOOL LLPolyMorphTarget::parseData(LLXmlTreeNode* node)
+{
+	LLPolyMorphTargetInfo* info = new LLPolyMorphTargetInfo;
+
+	info->parseXml(node);
+	if (!setInfo(info))
+	{
+		delete info;
+		return FALSE;
+	}
+	return TRUE;
+}
+#endif
+
+//-----------------------------------------------------------------------------
+// getVertexDistortion()
+//-----------------------------------------------------------------------------
+LLVector4a LLPolyMorphTarget::getVertexDistortion(S32 requested_index, LLPolyMesh *mesh)
+{
+	if (!mMorphData || mMesh != mesh) return LLVector4a::getZero();
+
+	for(U32 index = 0; index < mMorphData->mNumIndices; index++)
+	{
+		if (mMorphData->mVertexIndices[index] == (U32)requested_index)
+		{
+			return mMorphData->mCoords[index];
+		}
+	}
+
+	return LLVector4a::getZero();
+}
+
+//-----------------------------------------------------------------------------
+// getFirstDistortion()
+//-----------------------------------------------------------------------------
+const LLVector4a *LLPolyMorphTarget::getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh)
+{
+	if (!mMorphData) return &LLVector4a::getZero();
+
+	LLVector4a* resultVec;
+	mMorphData->mCurrentIndex = 0;
+	if (mMorphData->mNumIndices)
+	{
+		resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
+		if (index != NULL)
+		{
+			*index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
+		}
+		if (poly_mesh != NULL)
+		{
+			*poly_mesh = mMesh;
+		}
+
+		return resultVec;
+	}
+	return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// getNextDistortion()
+//-----------------------------------------------------------------------------
+const LLVector4a *LLPolyMorphTarget::getNextDistortion(U32 *index, LLPolyMesh **poly_mesh)
+{
+	if (!mMorphData) return &LLVector4a::getZero();
+
+	LLVector4a* resultVec;
+	mMorphData->mCurrentIndex++;
+	if (mMorphData->mCurrentIndex < mMorphData->mNumIndices)
+	{
+		resultVec = &mMorphData->mCoords[mMorphData->mCurrentIndex];
+		if (index != NULL)
+		{
+			*index = mMorphData->mVertexIndices[mMorphData->mCurrentIndex];
+		}
+		if (poly_mesh != NULL)
+		{
+			*poly_mesh = mMesh;
+		}
+		return resultVec;
+	}
+	return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// getTotalDistortion()
+//-----------------------------------------------------------------------------
+F32	LLPolyMorphTarget::getTotalDistortion() 
+{ 
+	if (mMorphData) 
+	{
+		return mMorphData->mTotalDistortion; 
+	}
+	else 
+	{
+		return 0.f;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// getAvgDistortion()
+//-----------------------------------------------------------------------------
+const LLVector4a& LLPolyMorphTarget::getAvgDistortion()	
+{
+	if (mMorphData) 
+	{
+		return mMorphData->mAvgDistortion; 
+	}
+	else 
+	{
+		return LLVector4a::getZero();
+	}
+}
+
+//-----------------------------------------------------------------------------
+// getMaxDistortion()
+//-----------------------------------------------------------------------------
+F32	LLPolyMorphTarget::getMaxDistortion() 
+{
+	if (mMorphData) 
+	{
+		return mMorphData->mMaxDistortion; 
+	}
+	else
+	{
+		return 0.f;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// apply()
+//-----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_APPLY_MORPH_TARGET("Apply Morph");
+
+void LLPolyMorphTarget::apply( ESex avatar_sex )
+{
+	if (!mMorphData || mNumMorphMasksPending > 0)
+	{
+		return;
+	}
+
+	LLFastTimer t(FTM_APPLY_MORPH_TARGET);
+
+	mLastSex = avatar_sex;
+
+	// Check for NaN condition (NaN is detected if a variable doesn't equal itself.
+	if (mCurWeight != mCurWeight)
+	{
+		mCurWeight = 0.0;
+	}
+	if (mLastWeight != mLastWeight)
+	{
+		mLastWeight = mCurWeight+.001;
+	}
+
+	// perform differential update of morph
+	F32 delta_weight = ( getSex() & avatar_sex ) ? (mCurWeight - mLastWeight) : (getDefaultWeight() - mLastWeight);
+	// store last weight
+	mLastWeight += delta_weight;
+
+	if (delta_weight != 0.f)
+	{
+		llassert(!mMesh->isLOD());
+		LLVector4a *coords = mMesh->getWritableCoords();
+
+		LLVector4a *scaled_normals = mMesh->getScaledNormals();
+		LLVector4a *normals = mMesh->getWritableNormals();
+
+		LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
+		LLVector4a *binormals = mMesh->getWritableBinormals();
+
+		LLVector4a *clothing_weights = mMesh->getWritableClothingWeights();
+		LLVector2 *tex_coords = mMesh->getWritableTexCoords();
+
+		F32 *maskWeightArray = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
+
+		for(U32 vert_index_morph = 0; vert_index_morph < mMorphData->mNumIndices; vert_index_morph++)
+		{
+			S32 vert_index_mesh = mMorphData->mVertexIndices[vert_index_morph];
+
+			F32 maskWeight = 1.f;
+			if (maskWeightArray)
+			{
+				maskWeight = maskWeightArray[vert_index_morph];
+			}
+
+
+			LLVector4a pos = mMorphData->mCoords[vert_index_morph];
+			pos.mul(delta_weight*maskWeight);
+			coords[vert_index_mesh].add(pos);
+
+			if (getInfo()->mIsClothingMorph && clothing_weights)
+			{
+				LLVector4a clothing_offset = mMorphData->mCoords[vert_index_morph];
+				clothing_offset.mul(delta_weight * maskWeight);
+				LLVector4a* clothing_weight = &clothing_weights[vert_index_mesh];
+				clothing_weight->add(clothing_offset);
+				clothing_weight->getF32ptr()[VW] = maskWeight;
+			}
+
+			// calculate new normals based on half angles
+			LLVector4a norm = mMorphData->mNormals[vert_index_morph];
+			norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
+			scaled_normals[vert_index_mesh].add(norm);
+			norm = scaled_normals[vert_index_mesh];
+			norm.normalize3fast();
+			normals[vert_index_mesh] = norm;
+
+			// calculate new binormals
+			LLVector4a binorm = mMorphData->mBinormals[vert_index_morph];
+			binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
+			scaled_binormals[vert_index_mesh].add(binorm);
+			LLVector4a tangent;
+			tangent.setCross3(scaled_binormals[vert_index_mesh], norm);
+			LLVector4a& normalized_binormal = binormals[vert_index_mesh];
+			normalized_binormal.setCross3(norm, tangent); 
+			normalized_binormal.normalize3fast();
+			
+			tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight;
+		}
+
+		// now apply volume changes
+		for( volume_list_t::iterator iter = mVolumeMorphs.begin(); iter != mVolumeMorphs.end(); iter++ )
+		{
+			LLPolyVolumeMorph* volume_morph = &(*iter);
+			LLVector3 scale_delta = volume_morph->mScale * delta_weight;
+			LLVector3 pos_delta = volume_morph->mPos * delta_weight;
+			
+			volume_morph->mVolume->setScale(volume_morph->mVolume->getScale() + scale_delta);
+			volume_morph->mVolume->setPosition(volume_morph->mVolume->getPosition() + pos_delta);
+		}
+	}
+
+	if (mNext)
+	{
+		mNext->apply(avatar_sex);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// applyMask()
+//-----------------------------------------------------------------------------
+void	LLPolyMorphTarget::applyMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert)
+{
+	LLVector4a *clothing_weights = getInfo()->mIsClothingMorph ? mMesh->getWritableClothingWeights() : NULL;
+
+	if (!mVertMask)
+	{
+		mVertMask = new LLPolyVertexMask(mMorphData);
+		mNumMorphMasksPending--;
+	}
+	else
+	{
+		// remove effect of previous mask
+		F32 *maskWeights = (mVertMask) ? mVertMask->getMorphMaskWeights() : NULL;
+
+		if (maskWeights)
+		{
+			LLVector4a *coords = mMesh->getWritableCoords();
+			LLVector4a *scaled_normals = mMesh->getScaledNormals();
+			LLVector4a *scaled_binormals = mMesh->getScaledBinormals();
+			LLVector2 *tex_coords = mMesh->getWritableTexCoords();
+
+			LLVector4Logical clothing_mask;
+			clothing_mask.clear();
+			clothing_mask.setElement<0>();
+			clothing_mask.setElement<1>();
+			clothing_mask.setElement<2>();
+
+
+			for(U32 vert = 0; vert < mMorphData->mNumIndices; vert++)
+			{
+				F32 lastMaskWeight = mLastWeight * maskWeights[vert];
+				S32 out_vert = mMorphData->mVertexIndices[vert];
+
+				// remove effect of existing masked morph
+				LLVector4a t;
+				t = mMorphData->mCoords[vert];
+				t.mul(lastMaskWeight);
+				coords[out_vert].sub(t);
+
+				t = mMorphData->mNormals[vert];
+				t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
+				scaled_normals[out_vert].sub(t);
+
+				t = mMorphData->mBinormals[vert];
+				t.mul(lastMaskWeight*NORMAL_SOFTEN_FACTOR);
+				scaled_binormals[out_vert].sub(t);
+
+				tex_coords[out_vert] -= mMorphData->mTexCoords[vert] * lastMaskWeight;
+
+				if (clothing_weights)
+				{
+					LLVector4a clothing_offset = mMorphData->mCoords[vert];
+					clothing_offset.mul(lastMaskWeight);
+					LLVector4a* clothing_weight = &clothing_weights[out_vert];
+					LLVector4a t;
+					t.setSub(*clothing_weight, clothing_offset);
+					clothing_weight->setSelectWithMask(clothing_mask, t, *clothing_weight);
+				}
+			}
+		}
+	}
+
+	// set last weight to 0, since we've removed the effect of this morph
+	mLastWeight = 0.f;
+
+	mVertMask->generateMask(maskTextureData, width, height, num_components, invert, clothing_weights);
+
+	apply(mLastSex);
+}
+
+
+//-----------------------------------------------------------------------------
+// LLPolyVertexMask()
+//-----------------------------------------------------------------------------
+LLPolyVertexMask::LLPolyVertexMask(LLPolyMorphData* morph_data)
+{
+	mWeights = new F32[morph_data->mNumIndices];
+	mMorphData = morph_data;
+	mWeightsGenerated = FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolyVertexMask()
+//-----------------------------------------------------------------------------
+LLPolyVertexMask::~LLPolyVertexMask()
+{
+	delete[] mWeights;
+}
+
+//-----------------------------------------------------------------------------
+// generateMask()
+//-----------------------------------------------------------------------------
+void LLPolyVertexMask::generateMask(U8 *maskTextureData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights)
+{
+// RN debug output that uses Image Debugger (http://www.cs.unc.edu/~baxter/projects/imdebug/)
+//	BOOL debugImg = FALSE; 
+//	if (debugImg)
+//	{
+//		if (invert)
+//		{
+//			imdebug("lum rbga=rgba b=8 w=%d h=%d *-1 %p", width, height, maskTextureData);
+//		}
+//		else
+//		{
+//			imdebug("lum rbga=rgba b=8 w=%d h=%d %p", width, height, maskTextureData);
+//		}
+//	}
+	for (U32 index = 0; index < mMorphData->mNumIndices; index++)
+	{
+		S32 vertIndex = mMorphData->mVertexIndices[index];
+		const S32 *sharedVertIndex = mMorphData->mMesh->getSharedVert(vertIndex);
+		LLVector2 uvCoords;
+
+		if (sharedVertIndex)
+		{
+			uvCoords = mMorphData->mMesh->getUVs(*sharedVertIndex);
+		}
+		else
+		{
+			uvCoords = mMorphData->mMesh->getUVs(vertIndex);
+		}
+		U32 s = llclamp((U32)(uvCoords.mV[VX] * (F32)(width - 1)), (U32)0, (U32)width - 1);
+		U32 t = llclamp((U32)(uvCoords.mV[VY] * (F32)(height - 1)), (U32)0, (U32)height - 1);
+		
+		mWeights[index] = ((F32) maskTextureData[((t * width + s) * num_components) + (num_components - 1)]) / 255.f;
+		
+		if (invert) 
+		{
+			mWeights[index] = 1.f - mWeights[index];
+		}
+
+		// now apply step function
+		// mWeights[index] = mWeights[index] > 0.95f ? 1.f : 0.f;
+
+		if (clothing_weights)
+		{
+			clothing_weights[vertIndex].getF32ptr()[VW] = mWeights[index];
+		}
+	}
+	mWeightsGenerated = TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// getMaskForMorphIndex()
+//-----------------------------------------------------------------------------
+F32* LLPolyVertexMask::getMorphMaskWeights()
+{
+	if (!mWeightsGenerated)
+	{
+		return NULL;
+	}
+	
+	return mWeights;
+}
diff --git a/indra/llappearance/llpolymorph.h b/indra/llappearance/llpolymorph.h
new file mode 100644
index 0000000000..d6cf9e52ca
--- /dev/null
+++ b/indra/llappearance/llpolymorph.h
@@ -0,0 +1,182 @@
+/** 
+ * @file llpolymorph.h
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPOLYMORPH_H
+#define LL_LLPOLYMORPH_H
+
+#include <string>
+#include <vector>
+
+#include "llviewervisualparam.h"
+
+class LLAvatarJointCollisionVolume;
+class LLPolyMeshSharedData;
+class LLVector2;
+class LLAvatarJointCollisionVolume;
+class LLWearable;
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphData()
+//-----------------------------------------------------------------------------
+class LLPolyMorphData
+{
+public:
+	LLPolyMorphData(const std::string& morph_name);
+	~LLPolyMorphData();
+	LLPolyMorphData(const LLPolyMorphData &rhs);
+
+	BOOL			loadBinary(LLFILE* fp, LLPolyMeshSharedData *mesh);
+	const std::string& getName() { return mName; }
+
+public:
+	std::string			mName;
+
+	// morphology
+	U32					mNumIndices;
+	U32*				mVertexIndices;
+	U32					mCurrentIndex;
+	LLVector4a*			mCoords;
+	LLVector4a*			mNormals;
+	LLVector4a*			mBinormals;
+	LLVector2*			mTexCoords;
+
+	F32					mTotalDistortion;	// vertex distortion summed over entire morph
+	F32					mMaxDistortion;		// maximum single vertex distortion in a given morph
+	LLVector4a			mAvgDistortion;		// average vertex distortion, to infer directionality of the morph
+	LLPolyMeshSharedData*	mMesh;
+};
+
+//-----------------------------------------------------------------------------
+// LLPolyVertexMask()
+//-----------------------------------------------------------------------------
+class LLPolyVertexMask
+{
+public:
+	LLPolyVertexMask(LLPolyMorphData* morph_data);
+	~LLPolyVertexMask();
+
+	void generateMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert, LLVector4a *clothing_weights);
+	F32* getMorphMaskWeights();
+
+
+protected:
+	F32*		mWeights;
+	LLPolyMorphData *mMorphData;
+	BOOL			mWeightsGenerated;
+
+};
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTarget Data structs
+//-----------------------------------------------------------------------------
+struct LLPolyVolumeMorphInfo
+{
+	LLPolyVolumeMorphInfo(std::string &name, LLVector3 &scale, LLVector3 &pos)
+		: mName(name), mScale(scale), mPos(pos) {};
+
+	std::string						mName;
+	LLVector3						mScale;
+	LLVector3						mPos;
+};
+
+struct LLPolyVolumeMorph
+{
+	LLPolyVolumeMorph(LLAvatarJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos)
+		: mVolume(volume), mScale(scale), mPos(pos) {};
+
+	LLAvatarJointCollisionVolume*	mVolume;
+	LLVector3						mScale;
+	LLVector3						mPos;
+};
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTargetInfo
+// Shared information for LLPolyMorphTargets
+//-----------------------------------------------------------------------------
+class LLPolyMorphTargetInfo : public LLViewerVisualParamInfo
+{
+	friend class LLPolyMorphTarget;
+public:
+	LLPolyMorphTargetInfo();
+	/*virtual*/ ~LLPolyMorphTargetInfo() {};
+	
+	/*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
+
+protected:
+	std::string		mMorphName;
+	BOOL			mIsClothingMorph;
+	typedef std::vector<LLPolyVolumeMorphInfo> volume_info_list_t;
+	volume_info_list_t mVolumeInfoList;	
+};
+
+//-----------------------------------------------------------------------------
+// LLPolyMorphTarget
+// A set of vertex data associated with morph target.
+// These morph targets must be topologically consistent with a given Polymesh
+// (share face sets)
+//-----------------------------------------------------------------------------
+class LLPolyMorphTarget : public LLViewerVisualParam
+{
+public:
+	LLPolyMorphTarget(LLPolyMesh *poly_mesh);
+	~LLPolyMorphTarget();
+
+	// Special: These functions are overridden by child classes
+	LLPolyMorphTargetInfo*	getInfo() const { return (LLPolyMorphTargetInfo*)mInfo; }
+	//   This sets mInfo and calls initialization functions
+	BOOL					setInfo(LLPolyMorphTargetInfo *info);
+
+	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
+
+	// LLVisualParam Virtual functions
+	///*virtual*/ BOOL				parseData(LLXmlTreeNode* node);
+	/*virtual*/ void				apply( ESex sex );
+	
+	// LLViewerVisualParam Virtual functions
+	/*virtual*/ F32					getTotalDistortion();
+	/*virtual*/ const LLVector4a&	getAvgDistortion();
+	/*virtual*/ F32					getMaxDistortion();
+	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh);
+	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh);
+	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh);
+
+	void	applyMask(U8 *maskData, S32 width, S32 height, S32 num_components, BOOL invert);
+	void	addPendingMorphMask() { mNumMorphMasksPending++; }
+
+protected:
+	LLPolyMorphData*				mMorphData;
+	LLPolyMesh*						mMesh;
+	LLPolyVertexMask *				mVertMask;
+	ESex							mLastSex;
+	// number of morph masks that haven't been generated, must be 0 before this morph is applied
+	BOOL							mNumMorphMasksPending;	
+
+	typedef std::vector<LLPolyVolumeMorph> volume_list_t;
+	volume_list_t 					mVolumeMorphs;
+
+};
+
+#endif // LL_LLPOLYMORPH_H
diff --git a/indra/llappearance/llpolyskeletaldistortion.cpp b/indra/llappearance/llpolyskeletaldistortion.cpp
new file mode 100644
index 0000000000..4ba16691c2
--- /dev/null
+++ b/indra/llappearance/llpolyskeletaldistortion.cpp
@@ -0,0 +1,293 @@
+/** 
+ * @file llpolyskeletaldistortion.cpp
+ * @brief Implementation of LLPolySkeletalDistortion classes
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+//-----------------------------------------------------------------------------
+// Header Files
+//-----------------------------------------------------------------------------
+#include "llpreprocessor.h"
+#include "llerrorlegacy.h"
+//#include "llcommon.h"
+//#include "llmemory.h"
+#include "llavatarappearance.h"
+#include "llavatarjoint.h"
+#include "llpolymorph.h"
+//#include "llviewercontrol.h"
+//#include "llxmltree.h"
+//#include "llvoavatar.h"
+#include "llwearable.h"
+//#include "lldir.h"
+//#include "llvolume.h"
+//#include "llendianswizzle.h"
+
+#include "llpolyskeletaldistortion.h"
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDistortionInfo()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
+{
+}
+
+BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
+{
+        llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
+        
+        if (!LLViewerVisualParamInfo::parseXml(node))
+                return FALSE;
+
+        LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
+
+        if (NULL == skeletalParam)
+        {
+                llwarns << "Failed to getChildByName(\"param_skeleton\")"
+                        << llendl;
+                return FALSE;
+        }
+
+        for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
+        {
+                if (bone->hasName("bone"))
+                {
+                        std::string name;
+                        LLVector3 scale;
+                        LLVector3 pos;
+                        BOOL haspos = FALSE;
+                        
+                        static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
+                        if (!bone->getFastAttributeString(name_string, name))
+                        {
+                                llwarns << "No bone name specified for skeletal param." << llendl;
+                                continue;
+                        }
+
+                        static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
+                        if (!bone->getFastAttributeVector3(scale_string, scale))
+                        {
+                                llwarns << "No scale specified for bone " << name << "." << llendl;
+                                continue;
+                        }
+
+                        // optional offset deformation (translation)
+                        static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
+                        if (bone->getFastAttributeVector3(offset_string, pos))
+                        {
+                                haspos = TRUE;
+                        }
+                        mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
+                }
+                else
+                {
+                        llwarns << "Unrecognized element " << bone->getName() << " in skeletal distortion" << llendl;
+                        continue;
+                }
+        }
+        return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDistortion()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLAvatarAppearance *avatarp)
+{
+        mAvatar = avatarp;
+        mDefaultVec.splat(0.001f);
+}
+
+//-----------------------------------------------------------------------------
+// ~LLPolySkeletalDistortion()
+//-----------------------------------------------------------------------------
+LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
+{
+}
+
+BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
+{
+        llassert(mInfo == NULL);
+        if (info->mID < 0)
+                return FALSE;
+        mInfo = info;
+        mID = info->mID;
+        setWeight(getDefaultWeight(), FALSE );
+
+        LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
+        for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
+        {
+                LLPolySkeletalBoneInfo *bone_info = &(*iter);
+                LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName);
+                if (!joint)
+                {
+                        llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl;
+                        continue;
+                }
+
+                if (mJointScales.find(joint) != mJointScales.end())
+                {
+                        llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl;
+                }
+
+                // store it
+                mJointScales[joint] = bone_info->mScaleDeformation;
+
+                // apply to children that need to inherit it
+                for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
+                     iter != joint->mChildren.end(); ++iter)
+                {
+                        LLAvatarJoint* child_joint = (LLAvatarJoint*)(*iter);
+                        if (child_joint->inheritScale())
+                        {
+                                LLVector3 childDeformation = LLVector3(child_joint->getScale());
+                                childDeformation.scaleVec(bone_info->mScaleDeformation);
+                                mJointScales[child_joint] = childDeformation;
+                        }
+                }
+
+                if (bone_info->mHasPositionDeformation)
+                {
+                        if (mJointOffsets.find(joint) != mJointOffsets.end())
+                        {
+                                llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl;
+                        }
+                        mJointOffsets[joint] = bone_info->mPositionDeformation;
+                }
+        }
+        return TRUE;
+}
+
+/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
+{
+        LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar);
+        *new_param = *this;
+        return new_param;
+}
+
+//-----------------------------------------------------------------------------
+// apply()
+//-----------------------------------------------------------------------------
+static LLFastTimer::DeclareTimer FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
+
+void LLPolySkeletalDistortion::apply( ESex avatar_sex )
+{
+	LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY);
+
+        F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
+
+        LLJoint* joint;
+        joint_vec_map_t::iterator iter;
+
+        for (iter = mJointScales.begin();
+             iter != mJointScales.end();
+             iter++)
+        {
+                joint = iter->first;
+                LLVector3 newScale = joint->getScale();
+                LLVector3 scaleDelta = iter->second;
+                newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
+                joint->setScale(newScale);
+        }
+
+        for (iter = mJointOffsets.begin();
+             iter != mJointOffsets.end();
+             iter++)
+        {
+                joint = iter->first;
+                LLVector3 newPosition = joint->getPosition();
+                LLVector3 positionDelta = iter->second;
+                newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
+                joint->setPosition(newPosition);
+        }
+
+        if (mLastWeight != mCurWeight && !mIsAnimating)
+        {
+                mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
+        }
+        mLastWeight = mCurWeight;
+}
+
+
+LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
+					     const std::string &name)
+{
+        LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
+        cloned_morph_data->mName = name;
+        for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
+        {
+                cloned_morph_data->mCoords[v] = src_data->mCoords[v];
+                cloned_morph_data->mNormals[v] = src_data->mNormals[v];
+                cloned_morph_data->mBinormals[v] = src_data->mBinormals[v];
+        }
+        return cloned_morph_data;
+}
+
+LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
+					     const LLVector3 &direction,
+					     const std::string &name)
+{
+        LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
+        cloned_morph_data->mName = name;
+		LLVector4a dir;
+		dir.load3(direction.mV);
+
+        for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
+        {
+                cloned_morph_data->mCoords[v] = dir;
+                cloned_morph_data->mNormals[v].clear();
+                cloned_morph_data->mBinormals[v].clear();
+        }
+        return cloned_morph_data;
+}
+
+LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
+                                            F32 scale,
+                                            const std::string &name)
+{
+        LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
+        cloned_morph_data->mName = name;
+
+		LLVector4a sc;
+		sc.splat(scale);
+
+		LLVector4a nsc;
+		nsc.set(scale, -scale, scale, scale);
+
+        for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
+        {
+            if (cloned_morph_data->mCoords[v][1] < 0)
+            {
+                cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc);
+				cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc);
+				cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc);
+			}
+			else
+			{
+				cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc);
+				cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc);
+				cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc);
+			}
+        }
+        return cloned_morph_data;
+}
+
+// End
diff --git a/indra/llappearance/llpolyskeletaldistortion.h b/indra/llappearance/llpolyskeletaldistortion.h
new file mode 100644
index 0000000000..040cf841ea
--- /dev/null
+++ b/indra/llappearance/llpolyskeletaldistortion.h
@@ -0,0 +1,119 @@
+/** 
+ * @file llpolyskeletaldistortion.h
+ * @brief Implementation of LLPolyMesh class
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLPOLYSKELETALDISTORTION_H
+#define LL_LLPOLYSKELETALDISTORTION_H
+
+#include "llcommon.h"
+
+#include <string>
+#include <map>
+#include "llstl.h"
+
+#include "v3math.h"
+#include "v2math.h"
+#include "llquaternion.h"
+//#include "llpolymorph.h"
+#include "lljoint.h"
+#include "llviewervisualparam.h"
+//#include "lldarray.h"
+
+//class LLSkinJoint;
+class LLAvatarAppearance;
+
+//#define USE_STRIPS	// Use tri-strips for rendering.
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDeformationInfo
+// Shared information for LLPolySkeletalDeformations
+//-----------------------------------------------------------------------------
+struct LLPolySkeletalBoneInfo
+{
+	LLPolySkeletalBoneInfo(std::string &name, LLVector3 &scale, LLVector3 &pos, BOOL haspos)
+		: mBoneName(name),
+		  mScaleDeformation(scale),
+		  mPositionDeformation(pos),
+		  mHasPositionDeformation(haspos) {}
+	std::string mBoneName;
+	LLVector3 mScaleDeformation;
+	LLVector3 mPositionDeformation;
+	BOOL mHasPositionDeformation;
+};
+
+class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
+{
+	friend class LLPolySkeletalDistortion;
+public:
+	LLPolySkeletalDistortionInfo();
+	/*virtual*/ ~LLPolySkeletalDistortionInfo() {};
+	
+	/*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
+
+protected:
+	typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
+	bone_info_list_t mBoneInfoList;
+};
+
+//-----------------------------------------------------------------------------
+// LLPolySkeletalDeformation
+// A set of joint scale data for deforming the avatar mesh
+//-----------------------------------------------------------------------------
+class LLPolySkeletalDistortion : public LLViewerVisualParam
+{
+public:
+	LLPolySkeletalDistortion(LLAvatarAppearance *avatarp);
+	~LLPolySkeletalDistortion();
+
+	// Special: These functions are overridden by child classes
+	LLPolySkeletalDistortionInfo*	getInfo() const { return (LLPolySkeletalDistortionInfo*)mInfo; }
+	//   This sets mInfo and calls initialization functions
+	BOOL							setInfo(LLPolySkeletalDistortionInfo *info);
+
+	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
+
+	// LLVisualParam Virtual functions
+	///*virtual*/ BOOL				parseData(LLXmlTreeNode* node);
+	/*virtual*/ void				apply( ESex sex );
+	
+	// LLViewerVisualParam Virtual functions
+	/*virtual*/ F32					getTotalDistortion() { return 0.1f; }
+	/*virtual*/ const LLVector4a&	getAvgDistortion()	{ return mDefaultVec; }
+	/*virtual*/ F32					getMaxDistortion() { return 0.1f; }
+	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);}
+	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;};
+	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
+
+protected:
+	typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;
+	joint_vec_map_t mJointScales;
+	joint_vec_map_t mJointOffsets;
+	LLVector4a	mDefaultVec;
+	// Backlink only; don't make this an LLPointer.
+	LLAvatarAppearance *mAvatar;
+};
+
+#endif // LL_LLPOLYSKELETALDISTORTION_H
+
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 21b1512e58..7942e815ae 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -443,8 +443,6 @@ set(viewer_SOURCE_FILES
     llplacesinventorybridge.cpp
     llplacesinventorypanel.cpp
     llpopupview.cpp
-    llpolymesh.cpp
-    llpolymorph.cpp
     llpostcard.cpp
     llpreview.cpp
     llpreviewanim.cpp
@@ -1000,8 +998,6 @@ set(viewer_HEADER_FILES
     llpipelinelistener.h
     llplacesinventorybridge.h
     llplacesinventorypanel.h
-    llpolymesh.h
-    llpolymorph.h
     llpopupview.h
     llpostcard.h
     llpreview.h
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index e1ef0d5399..7f4d33753d 100644
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -1078,8 +1078,8 @@ void LLAgentCamera::updateLookAt(const S32 mouse_x, const S32 mouse_y)
 
 	if (!isAgentAvatarValid()) return;
 
-	LLQuaternion av_inv_rot = ~gAgentAvatarp->mRoot.getWorldRotation();
-	LLVector3 root_at = LLVector3::x_axis * gAgentAvatarp->mRoot.getWorldRotation();
+	LLQuaternion av_inv_rot = ~gAgentAvatarp->mRoot->getWorldRotation();
+	LLVector3 root_at = LLVector3::x_axis * gAgentAvatarp->mRoot->getWorldRotation();
 
 	if 	((gViewerWindow->getMouseVelocityStat()->getCurrent() < 0.01f) &&
 		 (root_at * last_at_axis > 0.95f))
@@ -1432,7 +1432,7 @@ void LLAgentCamera::updateCamera()
 			LLVector3(0.08f, 0.f, 0.05f) * gAgentAvatarp->mHeadp->getWorldRotation() + 
 			LLVector3(0.1f, 0.f, 0.f) * gAgentAvatarp->mPelvisp->getWorldRotation();
 		LLVector3 diff = mCameraPositionAgent - head_pos;
-		diff = diff * ~gAgentAvatarp->mRoot.getWorldRotation();
+		diff = diff * ~gAgentAvatarp->mRoot->getWorldRotation();
 
 		LLJoint* torso_joint = gAgentAvatarp->mTorsop;
 		LLJoint* chest_joint = gAgentAvatarp->mChestp;
@@ -1456,7 +1456,7 @@ void LLAgentCamera::updateCamera()
 
 		gAgentAvatarp->mPelvisp->setPosition(gAgentAvatarp->mPelvisp->getPosition() + diff);
 
-		gAgentAvatarp->mRoot.updateWorldMatrixChildren();
+		gAgentAvatarp->mRoot->updateWorldMatrixChildren();
 
 		for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin(); 
 			 iter != gAgentAvatarp->mAttachmentPoints.end(); )
@@ -1684,7 +1684,7 @@ LLVector3d LLAgentCamera::calcCameraPositionTargetGlobal(BOOL *hit_limit)
 	F32			camera_land_height;
 	LLVector3d	frame_center_global = !isAgentAvatarValid() ? 
 		gAgent.getPositionGlobal() :
-		gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot.getWorldPosition());
+		gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot->getWorldPosition());
 	
 	BOOL		isConstrained = FALSE;
 	LLVector3d	head_offset;
diff --git a/indra/newview/llfloaterbvhpreview.cpp b/indra/newview/llfloaterbvhpreview.cpp
index fa0ad20fdb..ce67c6c65d 100644
--- a/indra/newview/llfloaterbvhpreview.cpp
+++ b/indra/newview/llfloaterbvhpreview.cpp
@@ -1097,12 +1097,12 @@ BOOL	LLPreviewAnimation::render()
 
 	gGL.flush();
 
-	LLVector3 target_pos = avatarp->mRoot.getWorldPosition();
+	LLVector3 target_pos = avatarp->mRoot->getWorldPosition();
 
 	LLQuaternion camera_rot = LLQuaternion(mCameraPitch, LLVector3::y_axis) * 
 		LLQuaternion(mCameraYaw, LLVector3::z_axis);
 
-	LLQuaternion av_rot = avatarp->mRoot.getWorldRotation() * camera_rot;
+	LLQuaternion av_rot = avatarp->mRoot->getWorldRotation() * camera_rot;
 	LLViewerCamera::getInstance()->setOriginAndLookAt(
 		target_pos + ((LLVector3(mCameraDistance, 0.f, 0.f) + mCameraOffset) * av_rot),		// camera
 		LLVector3::z_axis,																	// up
diff --git a/indra/newview/llfloaterimagepreview.cpp b/indra/newview/llfloaterimagepreview.cpp
index 6b2492d927..887cd2f4b0 100644
--- a/indra/newview/llfloaterimagepreview.cpp
+++ b/indra/newview/llfloaterimagepreview.cpp
@@ -593,7 +593,7 @@ S8 LLImagePreviewAvatar::getType() const
 
 void LLImagePreviewAvatar::setPreviewTarget(const std::string& joint_name, const std::string& mesh_name, LLImageRaw* imagep, F32 distance, BOOL male) 
 { 
-	mTargetJoint = mDummyAvatar->mRoot.findJoint(joint_name);
+	mTargetJoint = mDummyAvatar->mRoot->findJoint(joint_name);
 	// clear out existing test mesh
 	if (mTargetMesh)
 	{
@@ -612,9 +612,9 @@ void LLImagePreviewAvatar::setPreviewTarget(const std::string& joint_name, const
 		mDummyAvatar->updateVisualParams();
 		mDummyAvatar->updateGeometry(mDummyAvatar->mDrawable);
 	}
-	mDummyAvatar->mRoot.setVisible(FALSE, TRUE);
+	mDummyAvatar->mRoot->setVisible(FALSE, TRUE);
 
-	mTargetMesh = (LLViewerJointMesh*)mDummyAvatar->mRoot.findJoint(mesh_name);
+	mTargetMesh = (LLViewerJointMesh*)mDummyAvatar->mRoot->findJoint(mesh_name);
 	mTargetMesh->setTestTexture(mTextureName);
 	mTargetMesh->setVisible(TRUE, FALSE);
 	mCameraDistance = distance;
@@ -631,7 +631,7 @@ void LLImagePreviewAvatar::clearPreviewTexture(const std::string& mesh_name)
 {
 	if (mDummyAvatar)
 	{
-		LLViewerJointMesh *mesh = (LLViewerJointMesh*)mDummyAvatar->mRoot.findJoint(mesh_name);
+		LLViewerJointMesh *mesh = (LLViewerJointMesh*)mDummyAvatar->mRoot->findJoint(mesh_name);
 		// clear out existing test mesh
 		if (mesh)
 		{
diff --git a/indra/newview/llhudeffectlookat.cpp b/indra/newview/llhudeffectlookat.cpp
index bc3b220dc0..9dde65ceb6 100644
--- a/indra/newview/llhudeffectlookat.cpp
+++ b/indra/newview/llhudeffectlookat.cpp
@@ -636,7 +636,7 @@ bool LLHUDEffectLookAt::calcTargetPosition()
 			}
 			else
 			{
-				target_rot = target_av->mRoot.getWorldRotation();
+				target_rot = target_av->mRoot->getWorldRotation();
 			}
 		}
 		else // target obj is not an avatar
diff --git a/indra/newview/llpolymesh.cpp b/indra/newview/llpolymesh.cpp
deleted file mode 100644
index 70f3b5335e..0000000000
--- a/indra/newview/llpolymesh.cpp
+++ /dev/null
@@ -1,1297 +0,0 @@
-/** 
- * @file llpolymesh.cpp
- * @brief Implementation of LLPolyMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-//-----------------------------------------------------------------------------
-// Header Files
-//-----------------------------------------------------------------------------
-#include "llviewerprecompiledheaders.h"
-
-#include "llfasttimer.h"
-#include "llmemory.h"
-
-#include "llviewercontrol.h"
-#include "llxmltree.h"
-#include "llvoavatar.h"
-#include "llwearable.h"
-#include "lldir.h"
-#include "llvolume.h"
-#include "llendianswizzle.h"
-
-#include "llpolymesh.h"
-
-#define HEADER_ASCII "Linden Mesh 1.0"
-#define HEADER_BINARY "Linden Binary Mesh 1.0"
-
-extern LLControlGroup gSavedSettings;                           // read only
-
-LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
-					     const std::string &name);
-LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
-					     const LLVector3 &direction,
-					     const std::string &name);
-LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
-                                            F32 scale,
-                                            const std::string &name);
-
-//-----------------------------------------------------------------------------
-// Global table of loaded LLPolyMeshes
-//-----------------------------------------------------------------------------
-LLPolyMesh::LLPolyMeshSharedDataTable LLPolyMesh::sGlobalSharedMeshList;
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData()
-//-----------------------------------------------------------------------------
-LLPolyMeshSharedData::LLPolyMeshSharedData()
-{
-        mNumVertices = 0;
-        mBaseCoords = NULL;
-        mBaseNormals = NULL;
-        mBaseBinormals = NULL;
-        mTexCoords = NULL;
-        mDetailTexCoords = NULL;
-        mWeights = NULL;
-        mHasWeights = FALSE;
-        mHasDetailTexCoords = FALSE;
-
-        mNumFaces = 0;
-        mFaces = NULL;
-
-        mNumJointNames = 0;
-        mJointNames = NULL;
-
-        mTriangleIndices = NULL;
-        mNumTriangleIndices = 0;
-
-        mReferenceData = NULL;
-
-        mLastIndexOffset = -1;
-}
-
-//-----------------------------------------------------------------------------
-// ~LLPolyMeshSharedData()
-//-----------------------------------------------------------------------------
-LLPolyMeshSharedData::~LLPolyMeshSharedData()
-{
-        freeMeshData();
-        for_each(mMorphData.begin(), mMorphData.end(), DeletePointer());
-        mMorphData.clear();
-}
-
-//-----------------------------------------------------------------------------
-// setupLOD()
-//-----------------------------------------------------------------------------
-void LLPolyMeshSharedData::setupLOD(LLPolyMeshSharedData* reference_data)
-{
-        mReferenceData = reference_data;
-
-        if (reference_data)
-        {
-                mBaseCoords = reference_data->mBaseCoords;
-                mBaseNormals = reference_data->mBaseNormals;
-                mBaseBinormals = reference_data->mBaseBinormals;
-                mTexCoords = reference_data->mTexCoords;
-                mDetailTexCoords = reference_data->mDetailTexCoords;
-                mWeights = reference_data->mWeights;
-                mHasWeights = reference_data->mHasWeights;
-                mHasDetailTexCoords = reference_data->mHasDetailTexCoords;
-        }
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData::freeMeshData()
-//-----------------------------------------------------------------------------
-void LLPolyMeshSharedData::freeMeshData()
-{
-        if (!mReferenceData)
-        {
-                mNumVertices = 0;
-
-                ll_aligned_free_16(mBaseCoords);
-                mBaseCoords = NULL;
-
-                ll_aligned_free_16(mBaseNormals);
-                mBaseNormals = NULL;
-
-                ll_aligned_free_16(mBaseBinormals);
-                mBaseBinormals = NULL;
-
-                ll_aligned_free_16(mTexCoords);
-                mTexCoords = NULL;
-
-                ll_aligned_free_16(mDetailTexCoords);
-                mDetailTexCoords = NULL;
-
-                ll_aligned_free_16(mWeights);
-                mWeights = NULL;
-        }
-
-        mNumFaces = 0;
-        delete [] mFaces;
-        mFaces = NULL;
-
-        mNumJointNames = 0;
-        delete [] mJointNames;
-        mJointNames = NULL;
-
-        delete [] mTriangleIndices;
-        mTriangleIndices = NULL;
-
-//      mVertFaceMap.deleteAllData();
-}
-
-// compate_int is used by the qsort function to sort the index array
-int compare_int(const void *a, const void *b);
-
-//-----------------------------------------------------------------------------
-// genIndices()
-//-----------------------------------------------------------------------------
-void LLPolyMeshSharedData::genIndices(S32 index_offset)
-{
-        if (index_offset == mLastIndexOffset)
-        {
-                return;
-        }
-
-        delete []mTriangleIndices;
-        mTriangleIndices = new U32[mNumTriangleIndices];
-
-        S32 cur_index = 0;
-        for (S32 i = 0; i < mNumFaces; i++)
-        {
-                mTriangleIndices[cur_index] = mFaces[i][0] + index_offset;
-                cur_index++;
-                mTriangleIndices[cur_index] = mFaces[i][1] + index_offset;
-                cur_index++;
-                mTriangleIndices[cur_index] = mFaces[i][2] + index_offset;
-                cur_index++;
-        }
-
-        mLastIndexOffset = index_offset;
-}
-
-//--------------------------------------------------------------------
-// LLPolyMeshSharedData::getNumKB()
-//--------------------------------------------------------------------
-U32 LLPolyMeshSharedData::getNumKB()
-{
-        U32 num_kb = sizeof(LLPolyMesh);
-
-        if (!isLOD())
-        {
-                num_kb += mNumVertices *
-                        ( sizeof(LLVector3) +   // coords
-                          sizeof(LLVector3) +             // normals
-                          sizeof(LLVector2) );    // texCoords
-        }
-
-        if (mHasDetailTexCoords && !isLOD())
-        {
-                num_kb += mNumVertices * sizeof(LLVector2);     // detailTexCoords
-        }
-
-        if (mHasWeights && !isLOD())
-        {
-                num_kb += mNumVertices * sizeof(float);         // weights
-        }
-
-        num_kb += mNumFaces * sizeof(LLPolyFace);       // faces
-
-        num_kb /= 1024;
-        return num_kb;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData::allocateVertexData()
-//-----------------------------------------------------------------------------
-BOOL LLPolyMeshSharedData::allocateVertexData( U32 numVertices )
-{
-        U32 i;
-        mBaseCoords = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
-        mBaseNormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
-        mBaseBinormals = (LLVector4a*) ll_aligned_malloc_16(numVertices*sizeof(LLVector4a));
-        mTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
-        mDetailTexCoords = (LLVector2*) ll_aligned_malloc_16(numVertices*sizeof(LLVector2));
-        mWeights = (F32*) ll_aligned_malloc_16(numVertices*sizeof(F32));
-        for (i = 0; i < numVertices; i++)
-        {
-			mBaseCoords[i].clear();
-			mBaseNormals[i].clear();
-			mBaseBinormals[i].clear();
-			mTexCoords[i].clear();
-            mWeights[i] = 0.f;
-        }
-        mNumVertices = numVertices;
-        return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData::allocateFaceData()
-//-----------------------------------------------------------------------------
-BOOL LLPolyMeshSharedData::allocateFaceData( U32 numFaces )
-{
-        mFaces = new LLPolyFace[ numFaces ];
-        mNumFaces = numFaces;
-        mNumTriangleIndices = mNumFaces * 3;
-        return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMeshSharedData::allocateJointNames()
-//-----------------------------------------------------------------------------
-BOOL LLPolyMeshSharedData::allocateJointNames( U32 numJointNames )
-{
-        mJointNames = new std::string[ numJointNames ];
-        mNumJointNames = numJointNames;
-        return TRUE;
-}
-
-//--------------------------------------------------------------------
-// LLPolyMeshSharedData::loadMesh()
-//--------------------------------------------------------------------
-BOOL LLPolyMeshSharedData::loadMesh( const std::string& fileName )
-{
-        //-------------------------------------------------------------------------
-        // Open the file
-        //-------------------------------------------------------------------------
-        if(fileName.empty())
-        {
-                llerrs << "Filename is Empty!" << llendl;
-                return FALSE;
-        }
-        LLFILE* fp = LLFile::fopen(fileName, "rb");                     /*Flawfinder: ignore*/
-        if (!fp)
-        {
-                llerrs << "can't open: " << fileName << llendl;
-                return FALSE;
-        }
-
-        //-------------------------------------------------------------------------
-        // Read a chunk
-        //-------------------------------------------------------------------------
-        char header[128];               /*Flawfinder: ignore*/
-        if (fread(header, sizeof(char), 128, fp) != 128)
-        {
-                llwarns << "Short read" << llendl;
-        }
-
-        //-------------------------------------------------------------------------
-        // Check for proper binary header
-        //-------------------------------------------------------------------------
-        BOOL status = FALSE;
-        if ( strncmp(header, HEADER_BINARY, strlen(HEADER_BINARY)) == 0 )       /*Flawfinder: ignore*/
-        {
-                lldebugs << "Loading " << fileName << llendl;
-
-                //----------------------------------------------------------------
-                // File Header (seek past it)
-                //----------------------------------------------------------------
-                fseek(fp, 24, SEEK_SET);
-
-                //----------------------------------------------------------------
-                // HasWeights
-                //----------------------------------------------------------------
-                U8 hasWeights;
-                size_t numRead = fread(&hasWeights, sizeof(U8), 1, fp);
-                if (numRead != 1)
-                {
-                        llerrs << "can't read HasWeights flag from " << fileName << llendl;
-                        return FALSE;
-                }
-                if (!isLOD())
-                {
-                        mHasWeights = (hasWeights==0) ? FALSE : TRUE;
-                }
-
-                //----------------------------------------------------------------
-                // HasDetailTexCoords
-                //----------------------------------------------------------------
-                U8 hasDetailTexCoords;
-                numRead = fread(&hasDetailTexCoords, sizeof(U8), 1, fp);
-                if (numRead != 1)
-                {
-                        llerrs << "can't read HasDetailTexCoords flag from " << fileName << llendl;
-                        return FALSE;
-                }
-
-                //----------------------------------------------------------------
-                // Position
-                //----------------------------------------------------------------
-                LLVector3 position;
-                numRead = fread(position.mV, sizeof(float), 3, fp);
-                llendianswizzle(position.mV, sizeof(float), 3);
-                if (numRead != 3)
-                {
-                        llerrs << "can't read Position from " << fileName << llendl;
-                        return FALSE;
-                }
-                setPosition( position );
-
-                //----------------------------------------------------------------
-                // Rotation
-                //----------------------------------------------------------------
-                LLVector3 rotationAngles;
-                numRead = fread(rotationAngles.mV, sizeof(float), 3, fp);
-                llendianswizzle(rotationAngles.mV, sizeof(float), 3);
-                if (numRead != 3)
-                {
-                        llerrs << "can't read RotationAngles from " << fileName << llendl;
-                        return FALSE;
-                }
-
-                U8 rotationOrder;
-                numRead = fread(&rotationOrder, sizeof(U8), 1, fp);
-
-                if (numRead != 1)
-                {
-                        llerrs << "can't read RotationOrder from " << fileName << llendl;
-                        return FALSE;
-                }
-
-                rotationOrder = 0;
-
-                setRotation( mayaQ(     rotationAngles.mV[0],
-                                        rotationAngles.mV[1],
-                                        rotationAngles.mV[2],
-                                        (LLQuaternion::Order)rotationOrder ) );
-
-                //----------------------------------------------------------------
-                // Scale
-                //----------------------------------------------------------------
-                LLVector3 scale;
-                numRead = fread(scale.mV, sizeof(float), 3, fp);
-                llendianswizzle(scale.mV, sizeof(float), 3);
-                if (numRead != 3)
-                {
-                        llerrs << "can't read Scale from " << fileName << llendl;
-                        return FALSE;
-                }
-                setScale( scale );
-
-                //-------------------------------------------------------------------------
-                // Release any existing mesh geometry
-                //-------------------------------------------------------------------------
-                freeMeshData();
-
-                U16 numVertices = 0;
-
-                //----------------------------------------------------------------
-                // NumVertices
-                //----------------------------------------------------------------
-                if (!isLOD())
-                {
-                        numRead = fread(&numVertices, sizeof(U16), 1, fp);
-                        llendianswizzle(&numVertices, sizeof(U16), 1);
-                        if (numRead != 1)
-                        {
-                                llerrs << "can't read NumVertices from " << fileName << llendl;
-                                return FALSE;
-                        }
-
-                        allocateVertexData( numVertices );      
-
-						for (U16 i = 0; i < numVertices; ++i)
-						{
-							//----------------------------------------------------------------
-							// Coords
-							//----------------------------------------------------------------
-							numRead = fread(&mBaseCoords[i], sizeof(float), 3, fp);
-							llendianswizzle(&mBaseCoords[i], sizeof(float), 3);
-							if (numRead != 3)
-							{
-									llerrs << "can't read Coordinates from " << fileName << llendl;
-									return FALSE;
-							}
-						}
-
-						for (U16 i = 0; i < numVertices; ++i)
-						{
-							//----------------------------------------------------------------
-							// Normals
-							//----------------------------------------------------------------
-							numRead = fread(&mBaseNormals[i], sizeof(float), 3, fp);
-							llendianswizzle(&mBaseNormals[i], sizeof(float), 3);
-							if (numRead != 3)
-							{
-									llerrs << " can't read Normals from " << fileName << llendl;
-									return FALSE;
-							}
-						}
-
-						for (U16 i = 0; i < numVertices; ++i)
-						{
-							//----------------------------------------------------------------
-							// Binormals
-							//----------------------------------------------------------------
-							numRead = fread(&mBaseBinormals[i], sizeof(float), 3, fp);
-							llendianswizzle(&mBaseBinormals[i], sizeof(float), 3);
-							if (numRead != 3)
-							{
-									llerrs << " can't read Binormals from " << fileName << llendl;
-									return FALSE;
-							}
-						}
-
-                        //----------------------------------------------------------------
-                        // TexCoords
-                        //----------------------------------------------------------------
-                        numRead = fread(mTexCoords, 2*sizeof(float), numVertices, fp);
-                        llendianswizzle(mTexCoords, sizeof(float), 2*numVertices);
-                        if (numRead != numVertices)
-                        {
-                                llerrs << "can't read TexCoords from " << fileName << llendl;
-                                return FALSE;
-                        }
-
-                        //----------------------------------------------------------------
-                        // DetailTexCoords
-                        //----------------------------------------------------------------
-                        if (mHasDetailTexCoords)
-                        {
-                                numRead = fread(mDetailTexCoords, 2*sizeof(float), numVertices, fp);
-                                llendianswizzle(mDetailTexCoords, sizeof(float), 2*numVertices);
-                                if (numRead != numVertices)
-                                {
-                                        llerrs << "can't read DetailTexCoords from " << fileName << llendl;
-                                        return FALSE;
-                                }
-                        }
-
-                        //----------------------------------------------------------------
-                        // Weights
-                        //----------------------------------------------------------------
-                        if (mHasWeights)
-                        {
-                                numRead = fread(mWeights, sizeof(float), numVertices, fp);
-                                llendianswizzle(mWeights, sizeof(float), numVertices);
-                                if (numRead != numVertices)
-                                {
-                                        llerrs << "can't read Weights from " << fileName << llendl;
-                                        return FALSE;
-                                }
-                        }
-                }
-
-                //----------------------------------------------------------------
-                // NumFaces
-                //----------------------------------------------------------------
-                U16 numFaces;
-                numRead = fread(&numFaces, sizeof(U16), 1, fp);
-                llendianswizzle(&numFaces, sizeof(U16), 1);
-                if (numRead != 1)
-                {
-                        llerrs << "can't read NumFaces from " << fileName << llendl;
-                        return FALSE;
-                }
-                allocateFaceData( numFaces );
-
-
-                //----------------------------------------------------------------
-                // Faces
-                //----------------------------------------------------------------
-                U32 i;
-                U32 numTris = 0;
-                for (i = 0; i < numFaces; i++)
-                {
-                        S16 face[3];
-                        numRead = fread(face, sizeof(U16), 3, fp);
-                        llendianswizzle(face, sizeof(U16), 3);
-                        if (numRead != 3)
-                        {
-                                llerrs << "can't read Face[" << i << "] from " << fileName << llendl;
-                                return FALSE;
-                        }
-                        if (mReferenceData)
-                        {
-                                llassert(face[0] < mReferenceData->mNumVertices);
-                                llassert(face[1] < mReferenceData->mNumVertices);
-                                llassert(face[2] < mReferenceData->mNumVertices);
-                        }
-                        
-                        if (isLOD())
-                        {
-                                // store largest index in case of LODs
-                                for (S32 j = 0; j < 3; j++)
-                                {
-                                        if (face[j] > mNumVertices - 1)
-                                        {
-                                                mNumVertices = face[j] + 1;
-                                        }
-                                }
-                        }
-                        mFaces[i][0] = face[0];
-                        mFaces[i][1] = face[1];
-                        mFaces[i][2] = face[2];
-
-//                      S32 j;
-//                      for(j = 0; j < 3; j++)
-//                      {
-//                              LLDynamicArray<S32> *face_list = mVertFaceMap.getIfThere(face[j]);
-//                              if (!face_list)
-//                              {
-//                                      face_list = new LLDynamicArray<S32>;
-//                                      mVertFaceMap.addData(face[j], face_list);
-//                              }
-//                              face_list->put(i);
-//                      }
-
-                        numTris++;
-                }
-
-                lldebugs << "verts: " << numVertices 
-                         << ", faces: "   << numFaces
-                         << ", tris: "    << numTris
-                         << llendl;
-
-                //----------------------------------------------------------------
-                // NumSkinJoints
-                //----------------------------------------------------------------
-                if (!isLOD())
-                {
-                        U16 numSkinJoints = 0;
-                        if ( mHasWeights )
-                        {
-                                numRead = fread(&numSkinJoints, sizeof(U16), 1, fp);
-                                llendianswizzle(&numSkinJoints, sizeof(U16), 1);
-                                if (numRead != 1)
-                                {
-                                        llerrs << "can't read NumSkinJoints from " << fileName << llendl;
-                                        return FALSE;
-                                }
-                                allocateJointNames( numSkinJoints );
-                        }
-
-                        //----------------------------------------------------------------
-                        // SkinJoints
-                        //----------------------------------------------------------------
-                        for (i=0; i < numSkinJoints; i++)
-                        {
-                                char jointName[64+1];
-                                numRead = fread(jointName, sizeof(jointName)-1, 1, fp);
-                                jointName[sizeof(jointName)-1] = '\0'; // ensure nul-termination
-                                if (numRead != 1)
-                                {
-                                        llerrs << "can't read Skin[" << i << "].Name from " << fileName << llendl;
-                                        return FALSE;
-                                }
-
-                                std::string *jn = &mJointNames[i];
-                                *jn = jointName;
-                        }
-
-                        //-------------------------------------------------------------------------
-                        // look for morph section
-                        //-------------------------------------------------------------------------
-                        char morphName[64+1];
-                        morphName[sizeof(morphName)-1] = '\0'; // ensure nul-termination
-                        while(fread(&morphName, sizeof(char), 64, fp) == 64)
-                        {
-                                if (!strcmp(morphName, "End Morphs"))
-                                {
-                                        // we reached the end of the morphs
-                                        break;
-                                }
-                                LLPolyMorphData* morph_data = new LLPolyMorphData(std::string(morphName));
-
-                                BOOL result = morph_data->loadBinary(fp, this);
-
-                                if (!result)
-                                {
-                                        delete morph_data;
-                                        continue;
-                                }
-
-                                mMorphData.insert(morph_data);
-
-                                if (!strcmp(morphName, "Breast_Female_Cleavage"))
-                                {
-                                        mMorphData.insert(clone_morph_param_cleavage(morph_data,
-                                                                                     .75f,
-                                                                                     "Breast_Physics_LeftRight_Driven"));
-                                }
-
-                                if (!strcmp(morphName, "Breast_Female_Cleavage"))
-                                {
-                                        mMorphData.insert(clone_morph_param_duplicate(morph_data,
-										      "Breast_Physics_InOut_Driven"));
-                                }
-                                if (!strcmp(morphName, "Breast_Gravity"))
-                                {
-                                        mMorphData.insert(clone_morph_param_duplicate(morph_data,
-										      "Breast_Physics_UpDown_Driven"));
-                                }
-
-                                if (!strcmp(morphName, "Big_Belly_Torso"))
-                                {
-                                        mMorphData.insert(clone_morph_param_direction(morph_data,
-										      LLVector3(0,0,0.05f),
-										      "Belly_Physics_Torso_UpDown_Driven"));
-                                }
-
-                                if (!strcmp(morphName, "Big_Belly_Legs"))
-                                {
-                                        mMorphData.insert(clone_morph_param_direction(morph_data,
-										      LLVector3(0,0,0.05f),
-										      "Belly_Physics_Legs_UpDown_Driven"));
-                                }
-
-                                if (!strcmp(morphName, "skirt_belly"))
-                                {
-                                        mMorphData.insert(clone_morph_param_direction(morph_data,
-										      LLVector3(0,0,0.05f),
-										      "Belly_Physics_Skirt_UpDown_Driven"));
-                                }
-
-                                if (!strcmp(morphName, "Small_Butt"))
-                                {
-                                        mMorphData.insert(clone_morph_param_direction(morph_data,
-										      LLVector3(0,0,0.05f),
-										      "Butt_Physics_UpDown_Driven"));
-                                }
-                                if (!strcmp(morphName, "Small_Butt"))
-                                {
-                                        mMorphData.insert(clone_morph_param_direction(morph_data,
-										      LLVector3(0,0.03f,0),
-										      "Butt_Physics_LeftRight_Driven"));
-                                }
-                        }
-
-                        S32 numRemaps;
-                        if (fread(&numRemaps, sizeof(S32), 1, fp) == 1)
-                        {
-                                llendianswizzle(&numRemaps, sizeof(S32), 1);
-                                for (S32 i = 0; i < numRemaps; i++)
-                                {
-                                        S32 remapSrc;
-                                        S32 remapDst;
-                                        if (fread(&remapSrc, sizeof(S32), 1, fp) != 1)
-                                        {
-                                                llerrs << "can't read source vertex in vertex remap data" << llendl;
-                                                break;
-                                        }
-                                        if (fread(&remapDst, sizeof(S32), 1, fp) != 1)
-                                        {
-                                                llerrs << "can't read destination vertex in vertex remap data" << llendl;
-                                                break;
-                                        }
-                                        llendianswizzle(&remapSrc, sizeof(S32), 1);
-                                        llendianswizzle(&remapDst, sizeof(S32), 1);
-
-                                        mSharedVerts[remapSrc] = remapDst;
-                                }
-                        }
-                }
-
-                status = TRUE;
-        }
-        else
-        {
-                llerrs << "invalid mesh file header: " << fileName << llendl;
-                status = FALSE;
-        }
-
-        if (0 == mNumJointNames)
-        {
-                allocateJointNames(1);
-        }
-
-        fclose( fp );
-
-        return status;
-}
-
-//-----------------------------------------------------------------------------
-// getSharedVert()
-//-----------------------------------------------------------------------------
-const S32 *LLPolyMeshSharedData::getSharedVert(S32 vert)
-{
-        if (mSharedVerts.count(vert) > 0)
-        {
-                return &mSharedVerts[vert];
-        }
-        return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// getUV()
-//-----------------------------------------------------------------------------
-const LLVector2 &LLPolyMeshSharedData::getUVs(U32 index)
-{
-        // TODO: convert all index variables to S32
-        llassert((S32)index < mNumVertices);
-
-        return mTexCoords[index];
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh::LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh)
-{       
-	LLMemType mt(LLMemType::MTYPE_AVATAR_MESH);
-
-	llassert(shared_data);
-
-	mSharedData = shared_data;
-	mReferenceMesh = reference_mesh;
-	mAvatarp = NULL;
-	mVertexData = NULL;
-
-	mCurVertexCount = 0;
-	mFaceIndexCount = 0;
-	mFaceIndexOffset = 0;
-	mFaceVertexCount = 0;
-	mFaceVertexOffset = 0;
-
-	if (shared_data->isLOD() && reference_mesh)
-	{
-		mCoords = reference_mesh->mCoords;
-		mNormals = reference_mesh->mNormals;
-		mScaledNormals = reference_mesh->mScaledNormals;
-		mBinormals = reference_mesh->mBinormals;
-		mScaledBinormals = reference_mesh->mScaledBinormals;
-		mTexCoords = reference_mesh->mTexCoords;
-		mClothingWeights = reference_mesh->mClothingWeights;
-	}
-	else
-	{
-		// Allocate memory without initializing every vector
-		// NOTE: This makes asusmptions about the size of LLVector[234]
-		S32 nverts = mSharedData->mNumVertices;
-		//make sure it's an even number of verts for alignment
-		nverts += nverts%2;
-		S32 nfloats = nverts * (
-					4 + //coords
-					4 + //normals
-					4 + //weights
-					2 + //coords
-					4 + //scaled normals
-					4 + //binormals
-					4); //scaled binormals
-
-		//use 16 byte aligned vertex data to make LLPolyMesh SSE friendly
-		mVertexData = (F32*) ll_aligned_malloc_16(nfloats*4);
-		S32 offset = 0;
-		mCoords				= 	(LLVector4a*)(mVertexData + offset); offset += 4*nverts;
-		mNormals			=	(LLVector4a*)(mVertexData + offset); offset += 4*nverts;
-		mClothingWeights	= 	(LLVector4a*)(mVertexData + offset); offset += 4*nverts;
-		mTexCoords			= 	(LLVector2*)(mVertexData + offset);  offset += 2*nverts;
-		mScaledNormals		=   (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
-		mBinormals			=   (LLVector4a*)(mVertexData + offset); offset += 4*nverts;
-		mScaledBinormals	=   (LLVector4a*)(mVertexData + offset); offset += 4*nverts; 
-		initializeForMorph();
-	}
-}
-
-
-//-----------------------------------------------------------------------------
-// ~LLPolyMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh::~LLPolyMesh()
-{
-        S32 i;
-        for (i = 0; i < mJointRenderData.count(); i++)
-        {
-                delete mJointRenderData[i];
-                mJointRenderData[i] = NULL;
-        }
-
-		ll_aligned_free_16(mVertexData);
-
-}
-
-
-//-----------------------------------------------------------------------------
-// LLPolyMesh::getMesh()
-//-----------------------------------------------------------------------------
-LLPolyMesh *LLPolyMesh::getMesh(const std::string &name, LLPolyMesh* reference_mesh)
-{
-        //-------------------------------------------------------------------------
-        // search for an existing mesh by this name
-        //-------------------------------------------------------------------------
-        LLPolyMeshSharedData* meshSharedData = get_if_there(sGlobalSharedMeshList, name, (LLPolyMeshSharedData*)NULL);
-        if (meshSharedData)
-        {
-//              llinfos << "Polymesh " << name << " found in global mesh table." << llendl;
-                LLPolyMesh *poly_mesh = new LLPolyMesh(meshSharedData, reference_mesh);
-                return poly_mesh;
-        }
-
-        //-------------------------------------------------------------------------
-        // if not found, create a new one, add it to the list
-        //-------------------------------------------------------------------------
-        std::string full_path;
-        full_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,name);
-
-        LLPolyMeshSharedData *mesh_data = new LLPolyMeshSharedData();
-        if (reference_mesh)
-        {
-                mesh_data->setupLOD(reference_mesh->getSharedData());
-        }
-        if ( ! mesh_data->loadMesh( full_path ) )
-        {
-                delete mesh_data;
-                return NULL;
-        }
-
-        LLPolyMesh *poly_mesh = new LLPolyMesh(mesh_data, reference_mesh);
-
-//      llinfos << "Polymesh " << name << " added to global mesh table." << llendl;
-        sGlobalSharedMeshList[name] = poly_mesh->mSharedData;
-
-        return poly_mesh;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolyMesh::freeAllMeshes()
-//-----------------------------------------------------------------------------
-void LLPolyMesh::freeAllMeshes()
-{
-        // delete each item in the global lists
-        for_each(sGlobalSharedMeshList.begin(), sGlobalSharedMeshList.end(), DeletePairedPointer());
-        sGlobalSharedMeshList.clear();
-}
-
-LLPolyMeshSharedData *LLPolyMesh::getSharedData() const
-{
-        return mSharedData;
-}
-
-
-//--------------------------------------------------------------------
-// LLPolyMesh::dumpDiagInfo()
-//--------------------------------------------------------------------
-void LLPolyMesh::dumpDiagInfo()
-{
-        // keep track of totals
-        U32 total_verts = 0;
-        U32 total_faces = 0;
-        U32 total_kb = 0;
-
-        std::string buf;
-
-        llinfos << "-----------------------------------------------------" << llendl;
-        llinfos << "       Global PolyMesh Table (DEBUG only)" << llendl;
-        llinfos << "   Verts    Faces  Mem(KB) Name" << llendl;
-        llinfos << "-----------------------------------------------------" << llendl;
-
-        // print each loaded mesh, and it's memory usage
-        for(LLPolyMeshSharedDataTable::iterator iter = sGlobalSharedMeshList.begin();
-            iter != sGlobalSharedMeshList.end(); ++iter)
-        {
-                const std::string& mesh_name = iter->first;
-                LLPolyMeshSharedData* mesh = iter->second;
-
-                S32 num_verts = mesh->mNumVertices;
-                S32 num_faces = mesh->mNumFaces;
-                U32 num_kb = mesh->getNumKB();
-
-                buf = llformat("%8d %8d %8d %s", num_verts, num_faces, num_kb, mesh_name.c_str());
-                llinfos << buf << llendl;
-
-                total_verts += num_verts;
-                total_faces += num_faces;
-                total_kb += num_kb;
-        }
-
-        llinfos << "-----------------------------------------------------" << llendl;
-        buf = llformat("%8d %8d %8d TOTAL", total_verts, total_faces, total_kb );
-        llinfos << buf << llendl;
-        llinfos << "-----------------------------------------------------" << llendl;
-}
-
-//-----------------------------------------------------------------------------
-// getWritableCoords()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getWritableCoords()
-{
-        return mCoords;
-}
-
-//-----------------------------------------------------------------------------
-// getWritableNormals()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getWritableNormals()
-{
-        return mNormals;
-}
-
-//-----------------------------------------------------------------------------
-// getWritableBinormals()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getWritableBinormals()
-{
-        return mBinormals;
-}
-
-
-//-----------------------------------------------------------------------------
-// getWritableClothingWeights()
-//-----------------------------------------------------------------------------
-LLVector4a       *LLPolyMesh::getWritableClothingWeights()
-{
-        return mClothingWeights;
-}
-
-//-----------------------------------------------------------------------------
-// getWritableTexCoords()
-//-----------------------------------------------------------------------------
-LLVector2       *LLPolyMesh::getWritableTexCoords()
-{
-        return mTexCoords;
-}
-
-//-----------------------------------------------------------------------------
-// getScaledNormals()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getScaledNormals()
-{
-        return mScaledNormals;
-}
-
-//-----------------------------------------------------------------------------
-// getScaledBinormals()
-//-----------------------------------------------------------------------------
-LLVector4a *LLPolyMesh::getScaledBinormals()
-{
-        return mScaledBinormals;
-}
-
-
-//-----------------------------------------------------------------------------
-// initializeForMorph()
-//-----------------------------------------------------------------------------
-void LLPolyMesh::initializeForMorph()
-{
-    LLVector4a::memcpyNonAliased16((F32*) mCoords, (F32*) mSharedData->mBaseCoords, sizeof(LLVector4a) * mSharedData->mNumVertices);
-	LLVector4a::memcpyNonAliased16((F32*) mNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
-	LLVector4a::memcpyNonAliased16((F32*) mScaledNormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
-	LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
-	LLVector4a::memcpyNonAliased16((F32*) mScaledBinormals, (F32*) mSharedData->mBaseNormals, sizeof(LLVector4a) * mSharedData->mNumVertices);
-	LLVector4a::memcpyNonAliased16((F32*) mTexCoords, (F32*) mSharedData->mTexCoords, sizeof(LLVector2) * (mSharedData->mNumVertices + mSharedData->mNumVertices%2));
-
-	for (U32 i = 0; i < mSharedData->mNumVertices; ++i)
-	{
-		mClothingWeights[i].clear();
-	}
-}
-
-//-----------------------------------------------------------------------------
-// getMorphData()
-//-----------------------------------------------------------------------------
-LLPolyMorphData*        LLPolyMesh::getMorphData(const std::string& morph_name)
-{
-        if (!mSharedData)
-                return NULL;
-        for (LLPolyMeshSharedData::morphdata_list_t::iterator iter = mSharedData->mMorphData.begin();
-             iter != mSharedData->mMorphData.end(); ++iter)
-        {
-                LLPolyMorphData *morph_data = *iter;
-                if (morph_data->getName() == morph_name)
-                {
-                        return morph_data;
-                }
-        }
-        return NULL;
-}
-
-//-----------------------------------------------------------------------------
-// removeMorphData()
-//-----------------------------------------------------------------------------
-// // erasing but not deleting seems bad, but fortunately we don't actually use this...
-// void LLPolyMesh::removeMorphData(LLPolyMorphData *morph_target)
-// {
-//      if (!mSharedData)
-//              return;
-//      mSharedData->mMorphData.erase(morph_target);
-// }
-
-//-----------------------------------------------------------------------------
-// deleteAllMorphData()
-//-----------------------------------------------------------------------------
-// void LLPolyMesh::deleteAllMorphData()
-// {
-//      if (!mSharedData)
-//              return;
-
-//      for_each(mSharedData->mMorphData.begin(), mSharedData->mMorphData.end(), DeletePointer());
-//      mSharedData->mMorphData.clear();
-// }
-
-//-----------------------------------------------------------------------------
-// getWritableWeights()
-//-----------------------------------------------------------------------------
-F32*    LLPolyMesh::getWritableWeights() const
-{
-        return mSharedData->mWeights;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolySkeletalDistortionInfo()
-//-----------------------------------------------------------------------------
-LLPolySkeletalDistortionInfo::LLPolySkeletalDistortionInfo()
-{
-}
-
-BOOL LLPolySkeletalDistortionInfo::parseXml(LLXmlTreeNode* node)
-{
-        llassert( node->hasName( "param" ) && node->getChildByName( "param_skeleton" ) );
-        
-        if (!LLViewerVisualParamInfo::parseXml(node))
-                return FALSE;
-
-        LLXmlTreeNode* skeletalParam = node->getChildByName("param_skeleton");
-
-        if (NULL == skeletalParam)
-        {
-                llwarns << "Failed to getChildByName(\"param_skeleton\")"
-                        << llendl;
-                return FALSE;
-        }
-
-        for( LLXmlTreeNode* bone = skeletalParam->getFirstChild(); bone; bone = skeletalParam->getNextChild() )
-        {
-                if (bone->hasName("bone"))
-                {
-                        std::string name;
-                        LLVector3 scale;
-                        LLVector3 pos;
-                        BOOL haspos = FALSE;
-                        
-                        static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
-                        if (!bone->getFastAttributeString(name_string, name))
-                        {
-                                llwarns << "No bone name specified for skeletal param." << llendl;
-                                continue;
-                        }
-
-                        static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
-                        if (!bone->getFastAttributeVector3(scale_string, scale))
-                        {
-                                llwarns << "No scale specified for bone " << name << "." << llendl;
-                                continue;
-                        }
-
-                        // optional offset deformation (translation)
-                        static LLStdStringHandle offset_string = LLXmlTree::addAttributeString("offset");
-                        if (bone->getFastAttributeVector3(offset_string, pos))
-                        {
-                                haspos = TRUE;
-                        }
-                        mBoneInfoList.push_back(LLPolySkeletalBoneInfo(name, scale, pos, haspos));
-                }
-                else
-                {
-                        llwarns << "Unrecognized element " << bone->getName() << " in skeletal distortion" << llendl;
-                        continue;
-                }
-        }
-        return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// LLPolySkeletalDistortion()
-//-----------------------------------------------------------------------------
-LLPolySkeletalDistortion::LLPolySkeletalDistortion(LLVOAvatar *avatarp)
-{
-        mAvatar = avatarp;
-        mDefaultVec.splat(0.001f);
-}
-
-//-----------------------------------------------------------------------------
-// ~LLPolySkeletalDistortion()
-//-----------------------------------------------------------------------------
-LLPolySkeletalDistortion::~LLPolySkeletalDistortion()
-{
-}
-
-BOOL LLPolySkeletalDistortion::setInfo(LLPolySkeletalDistortionInfo *info)
-{
-        llassert(mInfo == NULL);
-        if (info->mID < 0)
-                return FALSE;
-        mInfo = info;
-        mID = info->mID;
-        setWeight(getDefaultWeight(), FALSE );
-
-        LLPolySkeletalDistortionInfo::bone_info_list_t::iterator iter;
-        for (iter = getInfo()->mBoneInfoList.begin(); iter != getInfo()->mBoneInfoList.end(); iter++)
-        {
-                LLPolySkeletalBoneInfo *bone_info = &(*iter);
-                LLJoint* joint = mAvatar->getJoint(bone_info->mBoneName);
-                if (!joint)
-                {
-                        llwarns << "Joint " << bone_info->mBoneName << " not found." << llendl;
-                        continue;
-                }
-
-                if (mJointScales.find(joint) != mJointScales.end())
-                {
-                        llwarns << "Scale deformation already supplied for joint " << joint->getName() << "." << llendl;
-                }
-
-                // store it
-                mJointScales[joint] = bone_info->mScaleDeformation;
-
-                // apply to children that need to inherit it
-                for (LLJoint::child_list_t::iterator iter = joint->mChildren.begin();
-                     iter != joint->mChildren.end(); ++iter)
-                {
-                        LLViewerJoint* child_joint = (LLViewerJoint*)(*iter);
-                        if (child_joint->inheritScale())
-                        {
-                                LLVector3 childDeformation = LLVector3(child_joint->getScale());
-                                childDeformation.scaleVec(bone_info->mScaleDeformation);
-                                mJointScales[child_joint] = childDeformation;
-                        }
-                }
-
-                if (bone_info->mHasPositionDeformation)
-                {
-                        if (mJointOffsets.find(joint) != mJointOffsets.end())
-                        {
-                                llwarns << "Offset deformation already supplied for joint " << joint->getName() << "." << llendl;
-                        }
-                        mJointOffsets[joint] = bone_info->mPositionDeformation;
-                }
-        }
-        return TRUE;
-}
-
-/*virtual*/ LLViewerVisualParam* LLPolySkeletalDistortion::cloneParam(LLWearable* wearable) const
-{
-        LLPolySkeletalDistortion *new_param = new LLPolySkeletalDistortion(mAvatar);
-        *new_param = *this;
-        return new_param;
-}
-
-//-----------------------------------------------------------------------------
-// apply()
-//-----------------------------------------------------------------------------
-static LLFastTimer::DeclareTimer FTM_POLYSKELETAL_DISTORTION_APPLY("Skeletal Distortion");
-
-void LLPolySkeletalDistortion::apply( ESex avatar_sex )
-{
-	LLFastTimer t(FTM_POLYSKELETAL_DISTORTION_APPLY);
-
-        F32 effective_weight = ( getSex() & avatar_sex ) ? mCurWeight : getDefaultWeight();
-
-        LLJoint* joint;
-        joint_vec_map_t::iterator iter;
-
-        for (iter = mJointScales.begin();
-             iter != mJointScales.end();
-             iter++)
-        {
-                joint = iter->first;
-                LLVector3 newScale = joint->getScale();
-                LLVector3 scaleDelta = iter->second;
-                newScale = newScale + (effective_weight * scaleDelta) - (mLastWeight * scaleDelta);
-                joint->setScale(newScale);
-        }
-
-        for (iter = mJointOffsets.begin();
-             iter != mJointOffsets.end();
-             iter++)
-        {
-                joint = iter->first;
-                LLVector3 newPosition = joint->getPosition();
-                LLVector3 positionDelta = iter->second;
-                newPosition = newPosition + (effective_weight * positionDelta) - (mLastWeight * positionDelta);
-                joint->setPosition(newPosition);
-        }
-
-        if (mLastWeight != mCurWeight && !mIsAnimating)
-        {
-                mAvatar->setSkeletonSerialNum(mAvatar->getSkeletonSerialNum() + 1);
-        }
-        mLastWeight = mCurWeight;
-}
-
-
-LLPolyMorphData *clone_morph_param_duplicate(const LLPolyMorphData *src_data,
-					     const std::string &name)
-{
-        LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
-        cloned_morph_data->mName = name;
-        for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
-        {
-                cloned_morph_data->mCoords[v] = src_data->mCoords[v];
-                cloned_morph_data->mNormals[v] = src_data->mNormals[v];
-                cloned_morph_data->mBinormals[v] = src_data->mBinormals[v];
-        }
-        return cloned_morph_data;
-}
-
-LLPolyMorphData *clone_morph_param_direction(const LLPolyMorphData *src_data,
-					     const LLVector3 &direction,
-					     const std::string &name)
-{
-        LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
-        cloned_morph_data->mName = name;
-		LLVector4a dir;
-		dir.load3(direction.mV);
-
-        for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
-        {
-                cloned_morph_data->mCoords[v] = dir;
-                cloned_morph_data->mNormals[v].clear();
-                cloned_morph_data->mBinormals[v].clear();
-        }
-        return cloned_morph_data;
-}
-
-LLPolyMorphData *clone_morph_param_cleavage(const LLPolyMorphData *src_data,
-                                            F32 scale,
-                                            const std::string &name)
-{
-        LLPolyMorphData* cloned_morph_data = new LLPolyMorphData(*src_data);
-        cloned_morph_data->mName = name;
-
-		LLVector4a sc;
-		sc.splat(scale);
-
-		LLVector4a nsc;
-		nsc.set(scale, -scale, scale, scale);
-
-        for (U32 v=0; v < cloned_morph_data->mNumIndices; v++)
-        {
-            if (cloned_morph_data->mCoords[v][1] < 0)
-            {
-                cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],nsc);
-				cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v],nsc);
-				cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],nsc);
-			}
-			else
-			{
-				cloned_morph_data->mCoords[v].setMul(src_data->mCoords[v],sc);
-				cloned_morph_data->mNormals[v].setMul(src_data->mNormals[v], sc);
-				cloned_morph_data->mBinormals[v].setMul(src_data->mBinormals[v],sc);
-			}
-        }
-        return cloned_morph_data;
-}
-
-// End
diff --git a/indra/newview/llpolymesh.h b/indra/newview/llpolymesh.h
deleted file mode 100644
index ffb11a3f7e..0000000000
--- a/indra/newview/llpolymesh.h
+++ /dev/null
@@ -1,438 +0,0 @@
-/** 
- * @file llpolymesh.h
- * @brief Implementation of LLPolyMesh class
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-#ifndef LL_LLPOLYMESH_H
-#define LL_LLPOLYMESH_H
-
-#include <string>
-#include <map>
-#include "llstl.h"
-
-#include "v3math.h"
-#include "v2math.h"
-#include "llquaternion.h"
-#include "llpolymorph.h"
-#include "lljoint.h"
-//#include "lldarray.h"
-
-class LLSkinJoint;
-class LLVOAvatar;
-class LLWearable;
-
-//#define USE_STRIPS	// Use tri-strips for rendering.
-
-//-----------------------------------------------------------------------------
-// LLPolyFace
-// A set of 4 vertex indices.
-// An LLPolyFace can represent either a triangle or quad.
-// If the last index is -1, it's a triangle.
-//-----------------------------------------------------------------------------
-typedef S32 LLPolyFace[3];
-
-//struct PrimitiveGroup;
-
-//-----------------------------------------------------------------------------
-// LLPolyMesh
-// A polyhedra consisting of any number of triangles and quads.
-// All instances contain a set of faces, and optionally may include
-// faces grouped into named face sets.
-//-----------------------------------------------------------------------------
-class LLPolyMorphTarget;
-
-class LLPolyMeshSharedData
-{
-	friend class LLPolyMesh;
-private:
-	// transform data
-	LLVector3				mPosition;
-	LLQuaternion			mRotation;
-	LLVector3				mScale;
-							
-	// vertex data			
-	S32						mNumVertices;
-	LLVector4a				*mBaseCoords;
-	LLVector4a				*mBaseNormals;
-	LLVector4a				*mBaseBinormals;
-	LLVector2				*mTexCoords;
-	LLVector2				*mDetailTexCoords;
-	F32						*mWeights;
-	
-	BOOL					mHasWeights;
-	BOOL					mHasDetailTexCoords;
-
-	// face data			
-	S32						mNumFaces;
-	LLPolyFace				*mFaces;
-							
-	// face set data		
-	U32						mNumJointNames;
-	std::string*			mJointNames;
-
-	// morph targets
-	typedef std::set<LLPolyMorphData*> morphdata_list_t;
-	morphdata_list_t			mMorphData;
-
-	std::map<S32, S32> 			mSharedVerts;
-	
-	LLPolyMeshSharedData*		mReferenceData;
-	S32							mLastIndexOffset;
-
-public:
-	// Temporarily...
-	// Triangle indices
-	U32				mNumTriangleIndices;
-	U32				*mTriangleIndices;
-
-public:
-	LLPolyMeshSharedData();
-	~LLPolyMeshSharedData();
-
-private:
-	void setupLOD(LLPolyMeshSharedData* reference_data);
-
-	// Frees all mesh memory resources 
-	void freeMeshData();
-
-	void setPosition( const LLVector3 &pos ) { 	mPosition = pos; }
-	void setRotation( const LLQuaternion &rot ) { mRotation = rot; }
-	void setScale( const LLVector3 &scale ) { mScale = scale; }
-
-	BOOL allocateVertexData( U32 numVertices );
-
-	BOOL allocateFaceData( U32 numFaces );
-
-	BOOL allocateJointNames( U32 numJointNames );
-
-	// Retrieve the number of KB of memory used by this instance
-	U32 getNumKB();
-
-	// Load mesh data from file
-	BOOL loadMesh( const std::string& fileName );
-
-public:
-	void genIndices(S32 offset);
-
-	const LLVector2 &getUVs(U32 index);
-
-	const S32	*getSharedVert(S32 vert);
-
-	BOOL isLOD() { return (mReferenceData != NULL); }
-};
-
-
-class LLJointRenderData
-{
-public:
-	LLJointRenderData(const LLMatrix4* world_matrix, LLSkinJoint* skin_joint) : mWorldMatrix(world_matrix), mSkinJoint(skin_joint) {}
-	~LLJointRenderData(){}
-
-	const LLMatrix4*		mWorldMatrix;
-	LLSkinJoint*			mSkinJoint;
-};
-
-
-class LLPolyMesh
-{
-public:
-	
-	// Constructor
-	LLPolyMesh(LLPolyMeshSharedData *shared_data, LLPolyMesh *reference_mesh);
-
-	// Destructor 
-	~LLPolyMesh();
-
-	// Requests a mesh by name.
-	// If the mesh already exists in the global mesh table, it is returned,
-	// otherwise it is loaded from file, added to the table, and returned.
-	static LLPolyMesh *getMesh( const std::string &name, LLPolyMesh* reference_mesh = NULL);
-
-	// Frees all loaded meshes.
-	// This should only be called once you know there are no outstanding
-	// references to these objects.  Generally, upon exit of the application.
-	static void freeAllMeshes();
-
-	//--------------------------------------------------------------------
-	// Transform Data Access
-	//--------------------------------------------------------------------
-	// Get position
-	const LLVector3 &getPosition() { 
-		llassert (mSharedData);
-		return mSharedData->mPosition; 
-	}
-
-	// Get rotation
-	const LLQuaternion &getRotation() { 
-		llassert (mSharedData);
-		return mSharedData->mRotation; 
-	}
-
-	// Get scale
-	const LLVector3 &getScale() { 
-		llassert (mSharedData);
-		return mSharedData->mScale; 
-	}
-
-	//--------------------------------------------------------------------
-	// Vertex Data Access
-	//--------------------------------------------------------------------
-	// Get number of vertices
-	U32 getNumVertices() { 
-		llassert (mSharedData);
-		return mSharedData->mNumVertices; 
-	}
-
-	// Returns whether or not the mesh has detail texture coords
-	BOOL hasDetailTexCoords() { 
-		llassert (mSharedData);
-		return mSharedData->mHasDetailTexCoords; 
-	}
-
-	// Returns whether or not the mesh has vertex weights
-	BOOL hasWeights() const{ 
-		llassert (mSharedData);
-		return mSharedData->mHasWeights; 
-	}
-
-	// Get coords
-	const LLVector4a	*getCoords() const{
-		return mCoords;
-	}
-
-	// non const version
-	LLVector4a *getWritableCoords();
-
-	// Get normals
-	const LLVector4a	*getNormals() const{ 
-		return mNormals; 
-	}
-
-	// Get normals
-	const LLVector4a	*getBinormals() const{ 
-		return mBinormals; 
-	}
-
-	// Get base mesh normals
-	const LLVector4a *getBaseNormals() const{
-		llassert(mSharedData);
-		return mSharedData->mBaseNormals;
-	}
-
-	// Get base mesh normals
-	const LLVector4a *getBaseBinormals() const{
-		llassert(mSharedData);
-		return mSharedData->mBaseBinormals;
-	}
-
-	// intermediate morphed normals and output normals
-	LLVector4a *getWritableNormals();
-	LLVector4a *getScaledNormals();
-
-	LLVector4a *getWritableBinormals();
-	LLVector4a *getScaledBinormals();
-
-	// Get texCoords
-	const LLVector2	*getTexCoords() const { 
-		return mTexCoords; 
-	}
-
-	// non const version
-	LLVector2 *getWritableTexCoords();
-
-	// Get detailTexCoords
-	const LLVector2	*getDetailTexCoords() const { 
-		llassert (mSharedData);
-		return mSharedData->mDetailTexCoords; 
-	}
-
-	// Get weights
-	const F32 *getWeights() const {
-		llassert (mSharedData);
-		return mSharedData->mWeights;
-	}
-
-	F32			*getWritableWeights() const;
-
-	LLVector4a	*getWritableClothingWeights();
-
-	const LLVector4a		*getClothingWeights()
-	{
-		return mClothingWeights;	
-	}
-
-	//--------------------------------------------------------------------
-	// Face Data Access
-	//--------------------------------------------------------------------
-	// Get number of faces
-	S32 getNumFaces() { 
-		llassert (mSharedData);
-		return mSharedData->mNumFaces; 
-	}
-
-	// Get faces
-	LLPolyFace *getFaces() { 
-		llassert (mSharedData);
-		return mSharedData->mFaces;
-	}
-
-	U32 getNumJointNames() { 
-		llassert (mSharedData);
-		return mSharedData->mNumJointNames; 
-	}
-
-	std::string *getJointNames() { 
-		llassert (mSharedData);
-		return mSharedData->mJointNames;
-	}
-
-	LLPolyMorphData*	getMorphData(const std::string& morph_name);
-// 	void	removeMorphData(LLPolyMorphData *morph_target);
-// 	void	deleteAllMorphData();
-
-	LLPolyMeshSharedData *getSharedData() const;
-	LLPolyMesh *getReferenceMesh() { return mReferenceMesh ? mReferenceMesh : this; }
-
-	// Get indices
-	U32*	getIndices() { return mSharedData ? mSharedData->mTriangleIndices : NULL; }
-
-	BOOL	isLOD() { return mSharedData && mSharedData->isLOD(); }
-
-	void setAvatar(LLVOAvatar* avatarp) { mAvatarp = avatarp; }
-	LLVOAvatar* getAvatar() { return mAvatarp; }
-
-	LLDynamicArray<LLJointRenderData*>	mJointRenderData;
-
-	U32				mFaceVertexOffset;
-	U32				mFaceVertexCount;
-	U32				mFaceIndexOffset;
-	U32				mFaceIndexCount;
-	U32				mCurVertexCount;
-private:
-	void initializeForMorph();
-
-	// Dumps diagnostic information about the global mesh table
-	static void dumpDiagInfo();
-
-protected:
-	// mesh data shared across all instances of a given mesh
-	LLPolyMeshSharedData	*mSharedData;
-	// Single array of floats for allocation / deletion
-	F32						*mVertexData;
-	// deformed vertices (resulting from application of morph targets)
-	LLVector4a				*mCoords;
-	// deformed normals (resulting from application of morph targets)
-	LLVector4a				*mScaledNormals;
-	// output normals (after normalization)
-	LLVector4a				*mNormals;
-	// deformed binormals (resulting from application of morph targets)
-	LLVector4a				*mScaledBinormals;
-	// output binormals (after normalization)
-	LLVector4a				*mBinormals;
-	// weight values that mark verts as clothing/skin
-	LLVector4a				*mClothingWeights;
-	// output texture coordinates
-	LLVector2				*mTexCoords;
-	
-	LLPolyMesh				*mReferenceMesh;
-
-	// global mesh list
-	typedef std::map<std::string, LLPolyMeshSharedData*> LLPolyMeshSharedDataTable; 
-	static LLPolyMeshSharedDataTable sGlobalSharedMeshList;
-
-	// Backlink only; don't make this an LLPointer.
-	LLVOAvatar* mAvatarp;
-};
-
-//-----------------------------------------------------------------------------
-// LLPolySkeletalDeformationInfo
-// Shared information for LLPolySkeletalDeformations
-//-----------------------------------------------------------------------------
-struct LLPolySkeletalBoneInfo
-{
-	LLPolySkeletalBoneInfo(std::string &name, LLVector3 &scale, LLVector3 &pos, BOOL haspos)
-		: mBoneName(name),
-		  mScaleDeformation(scale),
-		  mPositionDeformation(pos),
-		  mHasPositionDeformation(haspos) {}
-	std::string mBoneName;
-	LLVector3 mScaleDeformation;
-	LLVector3 mPositionDeformation;
-	BOOL mHasPositionDeformation;
-};
-
-class LLPolySkeletalDistortionInfo : public LLViewerVisualParamInfo
-{
-	friend class LLPolySkeletalDistortion;
-public:
-	LLPolySkeletalDistortionInfo();
-	/*virtual*/ ~LLPolySkeletalDistortionInfo() {};
-	
-	/*virtual*/ BOOL parseXml(LLXmlTreeNode* node);
-
-protected:
-	typedef std::vector<LLPolySkeletalBoneInfo> bone_info_list_t;
-	bone_info_list_t mBoneInfoList;
-};
-
-//-----------------------------------------------------------------------------
-// LLPolySkeletalDeformation
-// A set of joint scale data for deforming the avatar mesh
-//-----------------------------------------------------------------------------
-class LLPolySkeletalDistortion : public LLViewerVisualParam
-{
-public:
-	LLPolySkeletalDistortion(LLVOAvatar *avatarp);
-	~LLPolySkeletalDistortion();
-
-	// Special: These functions are overridden by child classes
-	LLPolySkeletalDistortionInfo*	getInfo() const { return (LLPolySkeletalDistortionInfo*)mInfo; }
-	//   This sets mInfo and calls initialization functions
-	BOOL							setInfo(LLPolySkeletalDistortionInfo *info);
-
-	/*virtual*/ LLViewerVisualParam* cloneParam(LLWearable* wearable) const;
-
-	// LLVisualParam Virtual functions
-	///*virtual*/ BOOL				parseData(LLXmlTreeNode* node);
-	/*virtual*/ void				apply( ESex sex );
-	
-	// LLViewerVisualParam Virtual functions
-	/*virtual*/ F32					getTotalDistortion() { return 0.1f; }
-	/*virtual*/ const LLVector4a&	getAvgDistortion()	{ return mDefaultVec; }
-	/*virtual*/ F32					getMaxDistortion() { return 0.1f; }
-	/*virtual*/ LLVector4a			getVertexDistortion(S32 index, LLPolyMesh *poly_mesh){return LLVector4a(0.001f, 0.001f, 0.001f);}
-	/*virtual*/ const LLVector4a*	getFirstDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return &mDefaultVec;};
-	/*virtual*/ const LLVector4a*	getNextDistortion(U32 *index, LLPolyMesh **poly_mesh){index = 0; poly_mesh = NULL; return NULL;};
-
-protected:
-	typedef std::map<LLJoint*, LLVector3> joint_vec_map_t;
-	joint_vec_map_t mJointScales;
-	joint_vec_map_t mJointOffsets;
-	LLVector4a	mDefaultVec;
-	// Backlink only; don't make this an LLPointer.
-	LLVOAvatar *mAvatar;
-};
-
-#endif // LL_LLPOLYMESH_H
-
diff --git a/indra/newview/llpolymorph.h b/indra/newview/llpolymorph.h
index 46e23b7792..28d7755d4d 100644
--- a/indra/newview/llpolymorph.h
+++ b/indra/newview/llpolymorph.h
@@ -35,7 +35,7 @@
 class LLPolyMeshSharedData;
 class LLVOAvatar;
 class LLVector2;
-class LLViewerJointCollisionVolume;
+class LLAvatarJointCollisionVolume;
 class LLWearable;
 
 //-----------------------------------------------------------------------------
@@ -104,10 +104,10 @@ struct LLPolyVolumeMorphInfo
 
 struct LLPolyVolumeMorph
 {
-	LLPolyVolumeMorph(LLViewerJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos)
+	LLPolyVolumeMorph(LLAvatarJointCollisionVolume* volume, LLVector3 scale, LLVector3 pos)
 		: mVolume(volume), mScale(scale), mPos(pos) {};
 
-	LLViewerJointCollisionVolume*	mVolume;
+	LLAvatarJointCollisionVolume*	mVolume;
 	LLVector3						mScale;
 	LLVector3						mPos;
 };
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index c804898cc3..fadaaf4541 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -4028,7 +4028,7 @@ void renderAgentTarget(LLVOAvatar* avatar)
 	{
 		renderCrossHairs(avatar->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
 		renderCrossHairs(avatar->mDrawable->getPositionAgent(), 0.2f, LLColor4(1, 0, 0, 0.8f));
-		renderCrossHairs(avatar->mRoot.getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f));
+		renderCrossHairs(avatar->mRoot->getWorldPosition(), 0.2f, LLColor4(1, 1, 1, 0.8f));
 		renderCrossHairs(avatar->mPelvisp->getWorldPosition(), 0.2f, LLColor4(0, 0, 1, 0.8f));
 	}
 }
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 6782e3ef8a..ab06b1f5aa 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1247,6 +1247,9 @@ bool idle_startup()
 		LLPostProcess::initClass();
 		display_startup();
 
+		LLAvatarAppearance::initClass();
+		display_startup();
+
 		LLViewerObject::initVOClasses();
 		display_startup();
 
diff --git a/indra/newview/llviewerjoint.cpp b/indra/newview/llviewerjoint.cpp
index a907f102f8..bb45cf89fc 100644
--- a/indra/newview/llviewerjoint.cpp
+++ b/indra/newview/llviewerjoint.cpp
@@ -53,7 +53,7 @@ BOOL					LLViewerJoint::sDisableLOD = FALSE;
 // Class Constructor
 //-----------------------------------------------------------------------------
 LLViewerJoint::LLViewerJoint()
-	:       LLJoint()
+	:       LLAvatarJoint()
 {
 	init();
 }
@@ -64,7 +64,7 @@ LLViewerJoint::LLViewerJoint()
 // Class Constructor
 //-----------------------------------------------------------------------------
 LLViewerJoint::LLViewerJoint(const std::string &name, LLJoint *parent)
-	:	LLJoint(name, parent)
+	:	LLAvatarJoint(name, parent)
 {
 	init();
 }
@@ -90,31 +90,6 @@ LLViewerJoint::~LLViewerJoint()
 }
 
 
-//--------------------------------------------------------------------
-// setValid()
-//--------------------------------------------------------------------
-void LLViewerJoint::setValid( BOOL valid, BOOL recursive )
-{
-	//----------------------------------------------------------------
-	// set visibility for this joint
-	//----------------------------------------------------------------
-	mValid = valid;
-	
-	//----------------------------------------------------------------
-	// set visibility for children
-	//----------------------------------------------------------------
-	if (recursive)
-	{
-		for (child_list_t::iterator iter = mChildren.begin();
-			 iter != mChildren.end(); ++iter)
-		{
-			LLViewerJoint* joint = (LLViewerJoint*)(*iter);
-			joint->setValid(valid, TRUE);
-		}
-	}
-
-}
-
 //--------------------------------------------------------------------
 // renderSkeleton()
 // DEBUG (UNUSED)
@@ -522,98 +497,6 @@ void LLViewerJoint::setMeshesToChildren()
 		addChild((LLViewerJointMesh *) *iter);
 	}
 }
-//-----------------------------------------------------------------------------
-// LLViewerJointCollisionVolume()
-//-----------------------------------------------------------------------------
-
-LLViewerJointCollisionVolume::LLViewerJointCollisionVolume()
-{
-	mUpdateXform = FALSE;
-}
 
-LLViewerJointCollisionVolume::LLViewerJointCollisionVolume(const std::string &name, LLJoint *parent) : LLViewerJoint(name, parent)
-{
-	
-}
-
-void LLViewerJointCollisionVolume::renderCollision()
-{
-	updateWorldMatrix();
-	
-	gGL.pushMatrix();
-	gGL.multMatrix( &mXform.getWorldMatrix().mMatrix[0][0] );
-
-	gGL.diffuseColor3f( 0.f, 0.f, 1.f );
-	
-	gGL.begin(LLRender::LINES);
-	
-	LLVector3 v[] = 
-	{
-		LLVector3(1,0,0),
-		LLVector3(-1,0,0),
-		LLVector3(0,1,0),
-		LLVector3(0,-1,0),
-
-		LLVector3(0,0,-1),
-		LLVector3(0,0,1),
-	};
-
-	//sides
-	gGL.vertex3fv(v[0].mV); 
-	gGL.vertex3fv(v[2].mV);
-
-	gGL.vertex3fv(v[0].mV); 
-	gGL.vertex3fv(v[3].mV);
-
-	gGL.vertex3fv(v[1].mV); 
-	gGL.vertex3fv(v[2].mV);
-
-	gGL.vertex3fv(v[1].mV); 
-	gGL.vertex3fv(v[3].mV);
-
-
-	//top
-	gGL.vertex3fv(v[0].mV); 
-	gGL.vertex3fv(v[4].mV);
-
-	gGL.vertex3fv(v[1].mV); 
-	gGL.vertex3fv(v[4].mV);
-
-	gGL.vertex3fv(v[2].mV); 
-	gGL.vertex3fv(v[4].mV);
-
-	gGL.vertex3fv(v[3].mV); 
-	gGL.vertex3fv(v[4].mV);
-
-
-	//bottom
-	gGL.vertex3fv(v[0].mV); 
-	gGL.vertex3fv(v[5].mV);
-
-	gGL.vertex3fv(v[1].mV); 
-	gGL.vertex3fv(v[5].mV);
-
-	gGL.vertex3fv(v[2].mV); 
-	gGL.vertex3fv(v[5].mV);
-
-	gGL.vertex3fv(v[3].mV); 
-	gGL.vertex3fv(v[5].mV);
-
-	gGL.end();
-
-	gGL.popMatrix();
-}
-
-LLVector3 LLViewerJointCollisionVolume::getVolumePos(LLVector3 &offset)
-{
-	mUpdateXform = TRUE;
-	
-	LLVector3 result = offset;
-	result.scaleVec(getScale());
-	result.rotVec(getWorldRotation());
-	result += getWorldPosition();
-
-	return result;
-}
 
 // End
diff --git a/indra/newview/llviewerjoint.h b/indra/newview/llviewerjoint.h
index 531c0f765c..37c80dafeb 100644
--- a/indra/newview/llviewerjoint.h
+++ b/indra/newview/llviewerjoint.h
@@ -30,7 +30,7 @@
 //-----------------------------------------------------------------------------
 // Header Files
 //-----------------------------------------------------------------------------
-#include "lljoint.h"
+#include "llavatarjoint.h"
 #include "lljointpickname.h"
 
 class LLFace;
@@ -40,7 +40,7 @@ class LLViewerJointMesh;
 // class LLViewerJoint
 //-----------------------------------------------------------------------------
 class LLViewerJoint :
-	public LLJoint
+	public LLAvatarJoint
 {
 public:
 	LLViewerJoint();
@@ -50,9 +50,6 @@ public:
 	// Gets the validity of this joint
 	BOOL getValid() { return mValid; }
 
-	// Sets the validity of this joint
-	virtual void setValid( BOOL valid, BOOL recursive=FALSE );
-
 	// Primarily for debugging and character setup
 	// Derived classes may add text/graphic output.
 	// Draw skeleton graphic for debugging and character setup
@@ -134,19 +131,6 @@ protected:
 	S32			mMeshID;
 };
 
-class LLViewerJointCollisionVolume : public LLViewerJoint
-{
-public:
-	LLViewerJointCollisionVolume();
-	LLViewerJointCollisionVolume(const std::string &name, LLJoint *parent = NULL);
-	virtual ~LLViewerJointCollisionVolume() {};
-
-	virtual BOOL inheritScale() { return TRUE; }
-
-	void renderCollision();
-	LLVector3 getVolumePos(LLVector3 &offset);
-};
-
 #endif // LL_LLVIEWERJOINT_H
 
 
diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp
index 3532fac1bc..8d479ab0bf 100755
--- a/indra/newview/llviewerjointmesh.cpp
+++ b/indra/newview/llviewerjointmesh.cpp
@@ -67,101 +67,20 @@ static const U32 sRenderMask = LLVertexBuffer::MAP_VERTEX |
 							   LLVertexBuffer::MAP_NORMAL |
 							   LLVertexBuffer::MAP_TEXCOORD0;
 
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-// LLViewerJointMesh::LLSkinJoint
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// LLSkinJoint
-//-----------------------------------------------------------------------------
-LLSkinJoint::LLSkinJoint()
-{
-	mJoint       = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// ~LLSkinJoint
-//-----------------------------------------------------------------------------
-LLSkinJoint::~LLSkinJoint()
-{
-	mJoint = NULL;
-}
-
-
-//-----------------------------------------------------------------------------
-// LLSkinJoint::setupSkinJoint()
-//-----------------------------------------------------------------------------
-BOOL LLSkinJoint::setupSkinJoint( LLViewerJoint *joint)
-{
-	// find the named joint
-	mJoint = joint;
-	if ( !mJoint )
-	{
-		llinfos << "Can't find joint" << llendl;
-	}
-
-	// compute the inverse root skin matrix
-	mRootToJointSkinOffset.clearVec();
-
-	LLVector3 rootSkinOffset;
-	while (joint)
-	{
-		rootSkinOffset += joint->getSkinOffset();
-		joint = (LLViewerJoint*)joint->getParent();
-	}
-
-	mRootToJointSkinOffset = -rootSkinOffset;
-	mRootToParentJointSkinOffset = mRootToJointSkinOffset;
-	mRootToParentJointSkinOffset += mJoint->getSkinOffset();
-
-	return TRUE;
-}
-
-
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 // LLViewerJointMesh
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 
-BOOL LLViewerJointMesh::sPipelineRender = FALSE;
-EAvatarRenderPass LLViewerJointMesh::sRenderPass = AVATAR_RENDER_PASS_SINGLE;
-U32 LLViewerJointMesh::sClothingMaskImageName = 0;
-LLColor4 LLViewerJointMesh::sClothingInnerColor;
 
 //-----------------------------------------------------------------------------
 // LLViewerJointMesh()
 //-----------------------------------------------------------------------------
 LLViewerJointMesh::LLViewerJointMesh()
 	:
-	mTexture( NULL ),
-	mLayerSet( NULL ),
-	mTestImageName( 0 ),
-	mFaceIndexCount(0),
-	mIsTransparent(FALSE)
+	LLAvatarJointMesh()
 {
-
-	mColor[0] = 1.0f;
-	mColor[1] = 1.0f;
-	mColor[2] = 1.0f;
-	mColor[3] = 1.0f;
-	mShiny = 0.0f;
-	mCullBackFaces = TRUE;
-
-	mMesh = NULL;
-
-	mNumSkinJoints = 0;
-	mSkinJoints = NULL;
-
-	mFace = NULL;
-
-	mMeshID = 0;
-	mUpdateXform = FALSE;
-
-	mValid = FALSE;
 }
 
 
@@ -171,199 +90,6 @@ LLViewerJointMesh::LLViewerJointMesh()
 //-----------------------------------------------------------------------------
 LLViewerJointMesh::~LLViewerJointMesh()
 {
-	mMesh = NULL;
-	mTexture = NULL;
-	freeSkinData();
-}
-
-
-//-----------------------------------------------------------------------------
-// LLViewerJointMesh::allocateSkinData()
-//-----------------------------------------------------------------------------
-BOOL LLViewerJointMesh::allocateSkinData( U32 numSkinJoints )
-{
-	mSkinJoints = new LLSkinJoint[ numSkinJoints ];
-	mNumSkinJoints = numSkinJoints;
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// LLViewerJointMesh::freeSkinData()
-//-----------------------------------------------------------------------------
-void LLViewerJointMesh::freeSkinData()
-{
-	mNumSkinJoints = 0;
-	delete [] mSkinJoints;
-	mSkinJoints = NULL;
-}
-
-//--------------------------------------------------------------------
-// LLViewerJointMesh::getColor()
-//--------------------------------------------------------------------
-void LLViewerJointMesh::getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha )
-{
-	*red   = mColor[0];
-	*green = mColor[1];
-	*blue  = mColor[2];
-	*alpha = mColor[3];
-}
-
-//--------------------------------------------------------------------
-// LLViewerJointMesh::setColor()
-//--------------------------------------------------------------------
-void LLViewerJointMesh::setColor( F32 red, F32 green, F32 blue, F32 alpha )
-{
-	mColor[0] = red;
-	mColor[1] = green;
-	mColor[2] = blue;
-	mColor[3] = alpha;
-}
-
-
-//--------------------------------------------------------------------
-// LLViewerJointMesh::getTexture()
-//--------------------------------------------------------------------
-//LLViewerTexture *LLViewerJointMesh::getTexture()
-//{
-//	return mTexture;
-//}
-
-//--------------------------------------------------------------------
-// LLViewerJointMesh::setTexture()
-//--------------------------------------------------------------------
-void LLViewerJointMesh::setTexture( LLViewerTexture *texture )
-{
-	mTexture = texture;
-
-	// texture and dynamic_texture are mutually exclusive
-	if( texture )
-	{
-		mLayerSet = NULL;
-		//texture->bindTexture(0);
-		//texture->setClamp(TRUE, TRUE);
-	}
-}
-
-//--------------------------------------------------------------------
-// LLViewerJointMesh::setLayerSet()
-// Sets the shape texture (takes precedence over normal texture)
-//--------------------------------------------------------------------
-void LLViewerJointMesh::setLayerSet( LLViewerTexLayerSet* layer_set )
-{
-	mLayerSet = layer_set;
-	
-	// texture and dynamic_texture are mutually exclusive
-	if( layer_set )
-	{
-		mTexture = NULL;
-	}
-}
-
-
-
-//--------------------------------------------------------------------
-// LLViewerJointMesh::getMesh()
-//--------------------------------------------------------------------
-LLPolyMesh *LLViewerJointMesh::getMesh()
-{
-	return mMesh;
-}
-
-//-----------------------------------------------------------------------------
-// LLViewerJointMesh::setMesh()
-//-----------------------------------------------------------------------------
-void LLViewerJointMesh::setMesh( LLPolyMesh *mesh )
-{
-	// set the mesh pointer
-	mMesh = mesh;
-
-	// release any existing skin joints
-	freeSkinData();
-
-	if ( mMesh == NULL )
-	{
-		return;
-	}
-
-	// acquire the transform from the mesh object
-	setPosition( mMesh->getPosition() );
-	setRotation( mMesh->getRotation() );
-	setScale( mMesh->getScale() );
-
-	// create skin joints if necessary
-	if ( mMesh->hasWeights() && !mMesh->isLOD())
-	{
-		U32 numJointNames = mMesh->getNumJointNames();
-		
-		allocateSkinData( numJointNames );
-		std::string *jointNames = mMesh->getJointNames();
-
-		U32 jn;
-		for (jn = 0; jn < numJointNames; jn++)
-		{
-			//llinfos << "Setting up joint " << jointNames[jn] << llendl;
-			LLViewerJoint* joint = (LLViewerJoint*)(getRoot()->findJoint(jointNames[jn]) );
-			mSkinJoints[jn].setupSkinJoint( joint );
-		}
-	}
-
-	// setup joint array
-	if (!mMesh->isLOD())
-	{
-		setupJoint((LLViewerJoint*)getRoot());
-	}
-
-//	llinfos << "joint render entries: " << mMesh->mJointRenderData.count() << llendl;
-}
-
-//-----------------------------------------------------------------------------
-// setupJoint()
-//-----------------------------------------------------------------------------
-void LLViewerJointMesh::setupJoint(LLViewerJoint* current_joint)
-{
-//	llinfos << "Mesh: " << getName() << llendl;
-
-//	S32 joint_count = 0;
-	U32 sj;
-	for (sj=0; sj<mNumSkinJoints; sj++)
-	{
-		LLSkinJoint &js = mSkinJoints[sj];
-
-		if (js.mJoint != current_joint)
-		{
-			continue;
-		}
-
-		// we've found a skinjoint for this joint..
-
-		// is the last joint in the array our parent?
-		if(mMesh->mJointRenderData.count() && mMesh->mJointRenderData[mMesh->mJointRenderData.count() - 1]->mWorldMatrix == &current_joint->getParent()->getWorldMatrix())
-		{
-			// ...then just add ourselves
-			LLViewerJoint* jointp = js.mJoint;
-			mMesh->mJointRenderData.put(new LLJointRenderData(&jointp->getWorldMatrix(), &js));
-//			llinfos << "joint " << joint_count << js.mJoint->getName() << llendl;
-//			joint_count++;
-		}
-		// otherwise add our parent and ourselves
-		else
-		{
-			mMesh->mJointRenderData.put(new LLJointRenderData(&current_joint->getParent()->getWorldMatrix(), NULL));
-//			llinfos << "joint " << joint_count << current_joint->getParent()->getName() << llendl;
-//			joint_count++;
-			mMesh->mJointRenderData.put(new LLJointRenderData(&current_joint->getWorldMatrix(), &js));
-//			llinfos << "joint " << joint_count << current_joint->getName() << llendl;
-//			joint_count++;
-		}
-	}
-
-	// depth-first traversal
-	for (LLJoint::child_list_t::iterator iter = current_joint->mChildren.begin();
-		 iter != current_joint->mChildren.end(); ++iter)
-	{
-		LLViewerJoint* child_joint = (LLViewerJoint*)(*iter);
-		setupJoint(child_joint);
-	}
 }
 
 const S32 NUM_AXES = 3;
@@ -544,6 +270,7 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 	llassert( !(mTexture.notNull() && mLayerSet) );  // mutually exclusive
 
 	LLTexUnit::eTextureAddressMode old_mode = LLTexUnit::TAM_WRAP;
+	LLViewerTexLayerSet *layerset = dynamic_cast<LLViewerTexLayerSet*>(mLayerSet);
 	if (mTestImageName)
 	{
 		gGL.getTexUnit(diffuse_channel)->bindManual(LLTexUnit::TT_TEXTURE, mTestImageName);
@@ -558,11 +285,11 @@ U32 LLViewerJointMesh::drawShape( F32 pixelArea, BOOL first_pass, BOOL is_dummy)
 			gGL.getTexUnit(diffuse_channel)->setTextureColorBlend(LLTexUnit::TBO_LERP_TEX_ALPHA, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
 		}
 	}
-	else if( !is_dummy && mLayerSet )
+	else if( !is_dummy && layerset )
 	{
-		if(	mLayerSet->hasComposite() )
+		if(	layerset->hasComposite() )
 		{
-			gGL.getTexUnit(diffuse_channel)->bind(mLayerSet->getViewerComposite());
+			gGL.getTexUnit(diffuse_channel)->bind(layerset->getViewerComposite());
 		}
 		else
 		{
diff --git a/indra/newview/llviewerjointmesh.h b/indra/newview/llviewerjointmesh.h
index ff6bed4f0f..039175830f 100755
--- a/indra/newview/llviewerjointmesh.h
+++ b/indra/newview/llviewerjointmesh.h
@@ -29,6 +29,7 @@
 
 #include "llviewerjoint.h"
 #include "llviewertexture.h"
+#include "llavatarjointmesh.h"
 #include "llpolymesh.h"
 #include "v4color.h"
 
@@ -37,56 +38,12 @@ class LLFace;
 class LLCharacter;
 class LLViewerTexLayerSet;
 
-typedef enum e_avatar_render_pass
-{
-	AVATAR_RENDER_PASS_SINGLE,
-	AVATAR_RENDER_PASS_CLOTHING_INNER,
-	AVATAR_RENDER_PASS_CLOTHING_OUTER
-} EAvatarRenderPass;
-
-class LLSkinJoint
-{
-public:
-	LLSkinJoint();
-	~LLSkinJoint();
-	BOOL setupSkinJoint( LLViewerJoint *joint);
-
-	LLViewerJoint	*mJoint;
-	LLVector3		mRootToJointSkinOffset;
-	LLVector3		mRootToParentJointSkinOffset;
-};
-
 //-----------------------------------------------------------------------------
 // class LLViewerJointMesh
 //-----------------------------------------------------------------------------
-class LLViewerJointMesh : public LLViewerJoint
+class LLViewerJointMesh : public LLAvatarJointMesh
 {
 	friend class LLVOAvatar;
-protected:
-	LLColor4					mColor;			// color value
-// 	LLColor4					mSpecular;		// specular color (always white for now)
-	F32							mShiny;			// shiny value
-	LLPointer<LLViewerTexture>	mTexture;		// ptr to a global texture
-	LLViewerTexLayerSet*		mLayerSet;		// ptr to a layer set owned by the avatar
-	U32 						mTestImageName;		// handle to a temporary texture for previewing uploads
-	LLPolyMesh*					mMesh;			// ptr to a global polymesh
-	BOOL						mCullBackFaces;	// true by default
-	LLFace*						mFace;			// ptr to a face w/ AGP copy of mesh
-
-	U32							mFaceIndexCount;
-	BOOL						mIsTransparent;
-
-	U32							mNumSkinJoints;
-	LLSkinJoint*				mSkinJoints;
-	S32							mMeshID;
-
-public:
-	static BOOL					sPipelineRender;
-	//RN: this is here for testing purposes
-	static U32					sClothingMaskImageName;
-	static EAvatarRenderPass	sRenderPass;
-	static LLColor4				sClothingInnerColor;
-
 public:
 	// Constructor
 	LLViewerJointMesh();
@@ -94,41 +51,9 @@ public:
 	// Destructor
 	virtual ~LLViewerJointMesh();
 
-	// Gets the shape color
-	void getColor( F32 *red, F32 *green, F32 *blue, F32 *alpha );
-
-	// Sets the shape color
-	void setColor( F32 red, F32 green, F32 blue, F32 alpha );
-
-	// Sets the shininess
-	void setSpecular( const LLColor4& color, F32 shiny ) { /*mSpecular = color;*/ mShiny = shiny; };
-
-	// Sets the shape texture
-	void setTexture( LLViewerTexture *texture );
-
-	void setTestTexture( U32 name ) { mTestImageName = name; }
-
-	// Sets layer set responsible for a dynamic shape texture (takes precedence over normal texture)
-	void setLayerSet( LLViewerTexLayerSet* layer_set );
-
-	// Gets the poly mesh
-	LLPolyMesh *getMesh();
-
-	// Sets the poly mesh
-	void setMesh( LLPolyMesh *mesh );
-
-	// Sets up joint matrix data for rendering
-	void setupJoint(LLViewerJoint* current_joint);
-
 	// Render time method to upload batches of joint matrices
 	void uploadJointMatrices();
 
-	// Sets ID for picking
-	void setMeshID( S32 id ) {mMeshID = id;}
-
-	// Gets ID for picking
-	S32 getMeshID() { return mMeshID; }	
-
 	// overloaded from base class
 	/*virtual*/ void drawBone();
 	/*virtual*/ BOOL isTransparent();
@@ -148,13 +73,6 @@ private:
 
 	//copy mesh into given face's vertex buffer, applying current animation pose
 	static void updateGeometry(LLFace* face, LLPolyMesh* mesh);
-
-private:
-	// Allocate skin data
-	BOOL allocateSkinData( U32 numSkinJoints );
-
-	// Free skin data
-	void freeSkinData();
 };
 
 #endif // LL_LLVIEWERJOINTMESH_H
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index d5ca01931f..8fc5a3f277 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -382,7 +382,7 @@ public:
 
 			if (isAgentAvatarValid())
 			{
-				tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot.getWorldPosition());
+				tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot->getWorldPosition());
 				agent_root_center_text = llformat("AgentRootCenter %f %f %f",
 												  (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
 			}
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index f6cac6d2d6..f0f469e959 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -139,7 +139,6 @@ const LLUUID ANIM_AGENT_PHYSICS_MOTION = LLUUID("7360e029-3cb8-ebc4-863e-212df44
 //-----------------------------------------------------------------------------
 // Constants
 //-----------------------------------------------------------------------------
-const std::string AVATAR_DEFAULT_CHAR = "avatar";
 
 const S32 MIN_PIXEL_AREA_FOR_COMPOSITE = 1024;
 const F32 SHADOW_OFFSET_AMT = 0.03f;
@@ -220,58 +219,6 @@ struct LLTextureMaskData
  **
  **/
 
-//------------------------------------------------------------------------
-// LLVOBoneInfo
-// Trans/Scale/Rot etc. info about each avatar bone.  Used by LLVOAvatarSkeleton.
-//------------------------------------------------------------------------
-class LLVOAvatarBoneInfo
-{
-	friend class LLVOAvatar;
-	friend class LLVOAvatarSkeletonInfo;
-public:
-	LLVOAvatarBoneInfo() : mIsJoint(FALSE) {}
-	~LLVOAvatarBoneInfo()
-	{
-		std::for_each(mChildList.begin(), mChildList.end(), DeletePointer());
-	}
-	BOOL parseXml(LLXmlTreeNode* node);
-	
-private:
-	std::string mName;
-	BOOL mIsJoint;
-	LLVector3 mPos;
-	LLVector3 mRot;
-	LLVector3 mScale;
-	LLVector3 mPivot;
-	typedef std::vector<LLVOAvatarBoneInfo*> child_list_t;
-	child_list_t mChildList;
-};
-
-//------------------------------------------------------------------------
-// LLVOAvatarSkeletonInfo
-// Overall avatar skeleton
-//------------------------------------------------------------------------
-class LLVOAvatarSkeletonInfo
-{
-	friend class LLVOAvatar;
-public:
-	LLVOAvatarSkeletonInfo() :
-		mNumBones(0), mNumCollisionVolumes(0) {}
-	~LLVOAvatarSkeletonInfo()
-	{
-		std::for_each(mBoneInfoList.begin(), mBoneInfoList.end(), DeletePointer());
-	}
-	BOOL parseXml(LLXmlTreeNode* node);
-	S32 getNumBones() const { return mNumBones; }
-	S32 getNumCollisionVolumes() const { return mNumCollisionVolumes; }
-	
-private:
-	S32 mNumBones;
-	S32 mNumCollisionVolumes;
-	typedef std::vector<LLVOAvatarBoneInfo*> bone_info_list_t;
-	bone_info_list_t mBoneInfoList;
-};
-
 //-----------------------------------------------------------------------------
 // class LLBodyNoiseMotion
 //-----------------------------------------------------------------------------
@@ -593,10 +540,6 @@ private:
 //-----------------------------------------------------------------------------
 // Static Data
 //-----------------------------------------------------------------------------
-LLXmlTree LLVOAvatar::sXMLTree;
-LLXmlTree LLVOAvatar::sSkeletonXMLTree;
-LLVOAvatarSkeletonInfo* LLVOAvatar::sAvatarSkeletonInfo = NULL;
-LLVOAvatar::LLVOAvatarXmlInfo* LLVOAvatar::sAvatarXmlInfo = NULL;
 LLAvatarAppearanceDictionary *LLVOAvatar::sAvatarDictionary = NULL;
 S32 LLVOAvatar::sFreezeCounter = 0;
 U32 LLVOAvatar::sMaxVisible = 12;
@@ -650,9 +593,7 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mAttachmentGeometryBytes(0),
 	mAttachmentSurfaceArea(0.f),
 	mTurning(FALSE),
-	mPelvisToFoot(0.f),
 	mLastSkeletonSerialNum( 0 ),
-	mHeadOffset(),
 	mIsSitting(FALSE),
 	mTimeVisible(),
 	mTyping(FALSE),
@@ -707,13 +648,6 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 	mMeshTexturesDirty = FALSE;
 	mHeadp = NULL;
 
-	mIsBuilt = FALSE;
-
-	mNumJoints = 0;
-	mSkeleton = NULL;
-
-	mNumCollisionVolumes = 0;
-	mCollisionVolumes = NULL;
 
 	// set up animation variables
 	mSpeed = 0.f;
@@ -802,35 +736,9 @@ LLVOAvatar::~LLVOAvatar()
 
 	lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl;
 
-	mRoot.removeAllChildren();
-	mJointMap.clear();
-
-	deleteAndClearArray(mSkeleton);
-	deleteAndClearArray(mCollisionVolumes);
-
-	mNumJoints = 0;
-
 	std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer());
 	mAttachmentPoints.clear();
 
-	deleteAndClear(mTexSkinColor);
-	deleteAndClear(mTexHairColor);
-	deleteAndClear(mTexEyeColor);
-
-	std::for_each(mMeshes.begin(), mMeshes.end(), DeletePairedPointer());
-	mMeshes.clear();
-
-	for (std::vector<LLViewerJoint*>::iterator jointIter = mMeshLOD.begin();
-		 jointIter != mMeshLOD.end(); 
-		 ++jointIter)
-	{
-		LLViewerJoint* joint = (LLViewerJoint *) *jointIter;
-		std::for_each(joint->mMeshParts.begin(), joint->mMeshParts.end(), DeletePointer());
-		joint->mMeshParts.clear();
-	}
-	std::for_each(mMeshLOD.begin(), mMeshLOD.end(), DeletePointer());
-	mMeshLOD.clear();
-	
 	mDead = TRUE;
 	
 	mAnimationSources.clear();
@@ -1127,109 +1035,6 @@ void LLVOAvatar::deleteCachedImages(bool clearAll)
 //------------------------------------------------------------------------
 void LLVOAvatar::initClass()
 { 
-	std::string xmlFile;
-
-	xmlFile = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,AVATAR_DEFAULT_CHAR) + "_lad.xml";
-	BOOL success = sXMLTree.parseFile( xmlFile, FALSE );
-	if (!success)
-	{
-		llerrs << "Problem reading avatar configuration file:" << xmlFile << llendl;
-	}
-
-	// now sanity check xml file
-	LLXmlTreeNode* root = sXMLTree.getRoot();
-	if (!root) 
-	{
-		llerrs << "No root node found in avatar configuration file: " << xmlFile << llendl;
-		return;
-	}
-
-	//-------------------------------------------------------------------------
-	// <linden_avatar version="1.0"> (root)
-	//-------------------------------------------------------------------------
-	if( !root->hasName( "linden_avatar" ) )
-	{
-		llerrs << "Invalid avatar file header: " << xmlFile << llendl;
-	}
-	
-	std::string version;
-	static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
-	if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
-	{
-		llerrs << "Invalid avatar file version: " << version << " in file: " << xmlFile << llendl;
-	}
-
-	S32 wearable_def_version = 1;
-	static LLStdStringHandle wearable_definition_version_string = LLXmlTree::addAttributeString("wearable_definition_version");
-	root->getFastAttributeS32( wearable_definition_version_string, wearable_def_version );
-	LLWearable::setCurrentDefinitionVersion( wearable_def_version );
-
-	std::string mesh_file_name;
-
-	LLXmlTreeNode* skeleton_node = root->getChildByName( "skeleton" );
-	if (!skeleton_node)
-	{
-		llerrs << "No skeleton in avatar configuration file: " << xmlFile << llendl;
-		return;
-	}
-	
-	std::string skeleton_file_name;
-	static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
-	if (!skeleton_node->getFastAttributeString(file_name_string, skeleton_file_name))
-	{
-		llerrs << "No file name in skeleton node in avatar config file: " << xmlFile << llendl;
-	}
-	
-	std::string skeleton_path;
-	skeleton_path = gDirUtilp->getExpandedFilename(LL_PATH_CHARACTER,skeleton_file_name);
-	if (!parseSkeletonFile(skeleton_path))
-	{
-		llerrs << "Error parsing skeleton file: " << skeleton_path << llendl;
-	}
-
-	// Process XML data
-
-	// avatar_skeleton.xml
-	if (sAvatarSkeletonInfo)
-	{ //this can happen if a login attempt failed
-		delete sAvatarSkeletonInfo;
-	}
-	sAvatarSkeletonInfo = new LLVOAvatarSkeletonInfo;
-	if (!sAvatarSkeletonInfo->parseXml(sSkeletonXMLTree.getRoot()))
-	{
-		llerrs << "Error parsing skeleton XML file: " << skeleton_path << llendl;
-	}
-	// parse avatar_lad.xml
-	if (sAvatarXmlInfo)
-	{ //this can happen if a login attempt failed
-		deleteAndClear(sAvatarXmlInfo);
-	}
-	sAvatarXmlInfo = new LLVOAvatarXmlInfo;
-	if (!sAvatarXmlInfo->parseXmlSkeletonNode(root))
-	{
-		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
-	}
-	if (!sAvatarXmlInfo->parseXmlMeshNodes(root))
-	{
-		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
-	}
-	if (!sAvatarXmlInfo->parseXmlColorNodes(root))
-	{
-		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
-	}
-	if (!sAvatarXmlInfo->parseXmlLayerNodes(root))
-	{
-		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
-	}
-	if (!sAvatarXmlInfo->parseXmlDriverNodes(root))
-	{
-		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
-	}
-	if (!sAvatarXmlInfo->parseXmlMorphNodes(root))
-	{
-		llerrs << "Error parsing skeleton node in avatar XML file: " << skeleton_path << llendl;
-	}
-
 	gAnimLibrary.animStateSetString(ANIM_AGENT_BODY_NOISE,"body_noise");
 	gAnimLibrary.animStateSetString(ANIM_AGENT_BREATHE_ROT,"breathe_rot");
 	gAnimLibrary.animStateSetString(ANIM_AGENT_PHYSICS_MOTION,"physics_motion");
@@ -1256,7 +1061,12 @@ void LLVOAvatar::initInstance(void)
 	//-------------------------------------------------------------------------
 	// initialize joint, mesh and shape members
 	//-------------------------------------------------------------------------
-	mRoot.setName( "mRoot" );
+	if (mRoot)
+	{
+		delete mRoot;
+	}
+	mRoot = new LLViewerJoint();
+	mRoot->setName( "mRoot" );
 	
 	for (LLAvatarAppearanceDictionary::Meshes::const_iterator iter = LLAvatarAppearanceDictionary::getInstance()->getMeshes().begin();
 		 iter != LLAvatarAppearanceDictionary::getInstance()->getMeshes().end();
@@ -1314,7 +1124,7 @@ void LLVOAvatar::initInstance(void)
 		// Skip it if there's no associated baked texture.
 		if (baked_texture_index == BAKED_NUM_INDICES) continue;
 		
-		for (std::vector<LLViewerJointMesh* >::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin();
+		for (std::vector<LLAvatarJointMesh* >::iterator iter = mMeshLOD[mesh_index]->mMeshParts.begin();
 			 iter != mMeshLOD[mesh_index]->mMeshParts.end(); 
 			 ++iter)
 		{
@@ -1707,160 +1517,6 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector
 	return hit;
 }
 
-//-----------------------------------------------------------------------------
-// parseSkeletonFile()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::parseSkeletonFile(const std::string& filename)
-{
-	LLMemType mt(LLMemType::MTYPE_AVATAR);
-	
-	//-------------------------------------------------------------------------
-	// parse the file
-	//-------------------------------------------------------------------------
-	BOOL parsesuccess = sSkeletonXMLTree.parseFile( filename, FALSE );
-
-	if (!parsesuccess)
-	{
-		llerrs << "Can't parse skeleton file: " << filename << llendl;
-		return FALSE;
-	}
-
-	// now sanity check xml file
-	LLXmlTreeNode* root = sSkeletonXMLTree.getRoot();
-	if (!root) 
-	{
-		llerrs << "No root node found in avatar skeleton file: " << filename << llendl;
-		return FALSE;
-	}
-
-	if( !root->hasName( "linden_skeleton" ) )
-	{
-		llerrs << "Invalid avatar skeleton file header: " << filename << llendl;
-		return FALSE;
-	}
-
-	std::string version;
-	static LLStdStringHandle version_string = LLXmlTree::addAttributeString("version");
-	if( !root->getFastAttributeString( version_string, version ) || (version != "1.0") )
-	{
-		llerrs << "Invalid avatar skeleton file version: " << version << " in file: " << filename << llendl;
-		return FALSE;
-	}
-
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// setupBone()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 &volume_num, S32 &joint_num)
-{
-	LLMemType mt(LLMemType::MTYPE_AVATAR);
-	
-	LLViewerJoint* joint = NULL;
-
-	if (info->mIsJoint)
-	{
-		joint = (LLViewerJoint*)getCharacterJoint(joint_num);
-		if (!joint)
-		{
-			llwarns << "Too many bones" << llendl;
-			return FALSE;
-		}
-		joint->setName( info->mName );
-	}
-	else // collision volume
-	{
-		if (volume_num >= (S32)mNumCollisionVolumes)
-		{
-			llwarns << "Too many bones" << llendl;
-			return FALSE;
-		}
-		joint = (LLViewerJoint*)(&mCollisionVolumes[volume_num]);
-		joint->setName( info->mName );
-	}
-
-	// add to parent
-	if (parent)
-	{
-		parent->addChild( joint );
-	}
-
-	joint->setPosition(info->mPos);
-	joint->setRotation(mayaQ(info->mRot.mV[VX], info->mRot.mV[VY],
-							 info->mRot.mV[VZ], LLQuaternion::XYZ));
-	joint->setScale(info->mScale);
-
-	joint->setDefaultFromCurrentXform();
-	
-	if (info->mIsJoint)
-	{
-		joint->setSkinOffset( info->mPivot );
-		joint_num++;
-	}
-	else // collision volume
-	{
-		volume_num++;
-	}
-
-	// setup children
-	LLVOAvatarBoneInfo::child_list_t::const_iterator iter;
-	for (iter = info->mChildList.begin(); iter != info->mChildList.end(); ++iter)
-	{
-		LLVOAvatarBoneInfo *child_info = *iter;
-		if (!setupBone(child_info, joint, volume_num, joint_num))
-		{
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// buildSkeleton()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::buildSkeleton(const LLVOAvatarSkeletonInfo *info)
-{
-	LLMemType mt(LLMemType::MTYPE_AVATAR);
-	
-	//-------------------------------------------------------------------------
-	// allocate joints
-	//-------------------------------------------------------------------------
-	if (!allocateCharacterJoints(info->mNumBones))
-	{
-		llerrs << "Can't allocate " << info->mNumBones << " joints" << llendl;
-		return FALSE;
-	}
-	
-	//-------------------------------------------------------------------------
-	// allocate volumes
-	//-------------------------------------------------------------------------
-	if (info->mNumCollisionVolumes)
-	{
-		if (!allocateCollisionVolumes(info->mNumCollisionVolumes))
-		{
-			llerrs << "Can't allocate " << info->mNumCollisionVolumes << " collision volumes" << llendl;
-			return FALSE;
-		}
-	}
-
-	S32 current_joint_num = 0;
-	S32 current_volume_num = 0;
-	LLVOAvatarSkeletonInfo::bone_info_list_t::const_iterator iter;
-	for (iter = info->mBoneInfoList.begin(); iter != info->mBoneInfoList.end(); ++iter)
-	{
-		LLVOAvatarBoneInfo *info = *iter;
-		if (!setupBone(info, NULL, current_volume_num, current_joint_num))
-		{
-			llerrs << "Error parsing bone in skeleton file" << llendl;
-			return FALSE;
-		}
-	}
-
-	return TRUE;
-}
-
 LLVOAvatar* LLVOAvatar::asAvatar()
 {
 	return this;
@@ -1892,27 +1548,13 @@ void LLVOAvatar::startDefaultMotions()
 // LLVOAvatar::buildCharacter()
 // Deferred initialization and rebuild of the avatar.
 //-----------------------------------------------------------------------------
+// virtual
 void LLVOAvatar::buildCharacter()
 {
-	LLMemType mt(LLMemType::MTYPE_AVATAR);
-	
-	//-------------------------------------------------------------------------
-	// remove all references to our existing skeleton
-	// so we can rebuild it
-	//-------------------------------------------------------------------------
-	flushAllMotions();
-
-	//-------------------------------------------------------------------------
-	// remove all of mRoot's children
-	//-------------------------------------------------------------------------
-	mRoot.removeAllChildren();
-	mJointMap.clear();
-	mIsBuilt = FALSE;
-
 	//-------------------------------------------------------------------------
 	// clear mesh data
 	//-------------------------------------------------------------------------
-	for (std::vector<LLViewerJoint*>::iterator jointIter = mMeshLOD.begin();
+	for (std::vector<LLAvatarJoint*>::iterator jointIter = mMeshLOD.begin();
 		 jointIter != mMeshLOD.end(); ++jointIter)
 	{
 		LLViewerJoint* joint = (LLViewerJoint*) *jointIter;
@@ -1924,83 +1566,8 @@ void LLVOAvatar::buildCharacter()
 		}
 	}
 
-	//-------------------------------------------------------------------------
-	// (re)load our skeleton and meshes
-	//-------------------------------------------------------------------------
-	LLTimer timer;
-
-	BOOL status = loadAvatar();
-	stop_glerror();
-
-// 	gPrintMessagesThisFrame = TRUE;
-	lldebugs << "Avatar load took " << timer.getElapsedTimeF32() << " seconds." << llendl;
-
-	if (!status)
-	{
-		if (isSelf())
-		{
-			llerrs << "Unable to load user's avatar" << llendl;
-		}
-		else
-		{
-			llwarns << "Unable to load other's avatar" << llendl;
-		}
-		return;
-	}
-
-	//-------------------------------------------------------------------------
-	// initialize "well known" joint pointers
-	//-------------------------------------------------------------------------
-	mPelvisp		= (LLViewerJoint*)mRoot.findJoint("mPelvis");
-	mTorsop			= (LLViewerJoint*)mRoot.findJoint("mTorso");
-	mChestp			= (LLViewerJoint*)mRoot.findJoint("mChest");
-	mNeckp			= (LLViewerJoint*)mRoot.findJoint("mNeck");
-	mHeadp			= (LLViewerJoint*)mRoot.findJoint("mHead");
-	mSkullp			= (LLViewerJoint*)mRoot.findJoint("mSkull");
-	mHipLeftp		= (LLViewerJoint*)mRoot.findJoint("mHipLeft");
-	mHipRightp		= (LLViewerJoint*)mRoot.findJoint("mHipRight");
-	mKneeLeftp		= (LLViewerJoint*)mRoot.findJoint("mKneeLeft");
-	mKneeRightp		= (LLViewerJoint*)mRoot.findJoint("mKneeRight");
-	mAnkleLeftp		= (LLViewerJoint*)mRoot.findJoint("mAnkleLeft");
-	mAnkleRightp	= (LLViewerJoint*)mRoot.findJoint("mAnkleRight");
-	mFootLeftp		= (LLViewerJoint*)mRoot.findJoint("mFootLeft");
-	mFootRightp		= (LLViewerJoint*)mRoot.findJoint("mFootRight");
-	mWristLeftp		= (LLViewerJoint*)mRoot.findJoint("mWristLeft");
-	mWristRightp	= (LLViewerJoint*)mRoot.findJoint("mWristRight");
-	mEyeLeftp		= (LLViewerJoint*)mRoot.findJoint("mEyeLeft");
-	mEyeRightp		= (LLViewerJoint*)mRoot.findJoint("mEyeRight");
-
-	//-------------------------------------------------------------------------
-	// Make sure "well known" pointers exist
-	//-------------------------------------------------------------------------
-	if (!(mPelvisp && 
-		  mTorsop &&
-		  mChestp &&
-		  mNeckp &&
-		  mHeadp &&
-		  mSkullp &&
-		  mHipLeftp &&
-		  mHipRightp &&
-		  mKneeLeftp &&
-		  mKneeRightp &&
-		  mAnkleLeftp &&
-		  mAnkleRightp &&
-		  mFootLeftp &&
-		  mFootRightp &&
-		  mWristLeftp &&
-		  mWristRightp &&
-		  mEyeLeftp &&
-		  mEyeRightp))
-	{
-		llerrs << "Failed to create avatar." << llendl;
-		return;
-	}
+	LLAvatarAppearance::buildCharacter();
 
-	//-------------------------------------------------------------------------
-	// initialize the pelvis
-	//-------------------------------------------------------------------------
-	mPelvisp->setPosition( LLVector3(0.0f, 0.0f, 0.0f) );
-	
 	//-------------------------------------------------------------------------
 	// set head offset from pelvis
 	//-------------------------------------------------------------------------
@@ -2033,9 +1600,6 @@ void LLVOAvatar::buildCharacter()
 	//-------------------------------------------------------------------------
 	processAnimationStateChanges();
 
-	mIsBuilt = TRUE;
-	stop_glerror();
-
 	mMeshValid = TRUE;
 }
 
@@ -2055,7 +1619,7 @@ void LLVOAvatar::releaseMeshData()
 	//llinfos << "Releasing" << llendl;
 
 	// cleanup mesh data
-	for (std::vector<LLViewerJoint*>::iterator iter = mMeshLOD.begin();
+	for (std::vector<LLAvatarJoint*>::iterator iter = mMeshLOD.begin();
 		 iter != mMeshLOD.end(); 
 		 ++iter)
 	{
@@ -2149,7 +1713,11 @@ void LLVOAvatar::updateMeshData()
 				last_v_num = num_vertices ;
 				last_i_num = num_indices ;
 
-				mMeshLOD[part_index++]->updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea);
+				LLViewerJoint* part_mesh = getViewerJoint(part_index++);
+				if (part_mesh)
+				{
+					part_mesh->updateFaceSizes(num_vertices, num_indices, mAdjustedPixelArea);
+				}
 			}
 			if(num_vertices < 1)//skip empty meshes
 			{
@@ -2223,7 +1791,11 @@ void LLVOAvatar::updateMeshData()
 					rigid = true;
 				}
 				
-				mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR, terse_update && !rigid);
+				LLViewerJoint* mesh = getViewerJoint(k);
+				if (mesh)
+				{
+					mesh->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR, terse_update && !rigid);
+				}
 			}
 
 			stop_glerror();
@@ -2243,72 +1815,6 @@ void LLVOAvatar::updateMeshData()
 
 //------------------------------------------------------------------------
 
-//------------------------------------------------------------------------
-// The viewer can only suggest a good size for the agent,
-// the simulator will keep it inside a reasonable range.
-void LLVOAvatar::computeBodySize() 
-{
-	LLVector3 pelvis_scale = mPelvisp->getScale();
-
-	// some of the joints have not been cached
-	LLVector3 skull = mSkullp->getPosition();
-	LLVector3 skull_scale = mSkullp->getScale();
-
-	LLVector3 neck = mNeckp->getPosition();
-	LLVector3 neck_scale = mNeckp->getScale();
-
-	LLVector3 chest = mChestp->getPosition();
-	LLVector3 chest_scale = mChestp->getScale();
-
-	// the rest of the joints have been cached
-	LLVector3 head = mHeadp->getPosition();
-	LLVector3 head_scale = mHeadp->getScale();
-
-	LLVector3 torso = mTorsop->getPosition();
-	LLVector3 torso_scale = mTorsop->getScale();
-
-	LLVector3 hip = mHipLeftp->getPosition();
-	LLVector3 hip_scale = mHipLeftp->getScale();
-
-	LLVector3 knee = mKneeLeftp->getPosition();
-	LLVector3 knee_scale = mKneeLeftp->getScale();
-
-	LLVector3 ankle = mAnkleLeftp->getPosition();
-	LLVector3 ankle_scale = mAnkleLeftp->getScale();
-
-	LLVector3 foot  = mFootLeftp->getPosition();
-
-	mPelvisToFoot = hip.mV[VZ] * pelvis_scale.mV[VZ] -
-				 	knee.mV[VZ] * hip_scale.mV[VZ] -
-				 	ankle.mV[VZ] * knee_scale.mV[VZ] -
-				 	foot.mV[VZ] * ankle_scale.mV[VZ];
-
-	LLVector3 new_body_size;
-	new_body_size.mV[VZ] = mPelvisToFoot +
-					   // the sqrt(2) correction below is an approximate
-					   // correction to get to the top of the head
-					   F_SQRT2 * (skull.mV[VZ] * head_scale.mV[VZ]) + 
-					   head.mV[VZ] * neck_scale.mV[VZ] + 
-					   neck.mV[VZ] * chest_scale.mV[VZ] + 
-					   chest.mV[VZ] * torso_scale.mV[VZ] + 
-					   torso.mV[VZ] * pelvis_scale.mV[VZ]; 
-
-	// TODO -- measure the real depth and width
-	new_body_size.mV[VX] = DEFAULT_AGENT_DEPTH;
-	new_body_size.mV[VY] = DEFAULT_AGENT_WIDTH;
-
-	if (new_body_size != mBodySize)
-	{
-		mBodySize = new_body_size;
-
-		if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF())
-		{	// notify simulator of change in size
-			// but not if we are in the middle of updating appearance
-			gAgent.sendAgentSetAppearance();
-		}
-	}
-}
-
 //------------------------------------------------------------------------
 // LLVOAvatar::processUpdateMessage()
 //------------------------------------------------------------------------
@@ -2478,7 +1984,7 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time)
 	
 	// animate the character
 	// store off last frame's root position to be consistent with camera position
-	LLVector3 root_pos_last = mRoot.getWorldPosition();
+	LLVector3 root_pos_last = mRoot->getWorldPosition();
 	BOOL detailed_update = updateCharacter(agent);
 
 	static LLUICachedControl<bool> visualizers_in_calls("ShowVoiceVisualizersInCalls", false);
@@ -2597,11 +2103,11 @@ void LLVOAvatar::idleUpdateVoiceVisualizer(bool voice_enabled)
 		if ( mIsSitting )
 		{
 			LLVector3 headOffset = LLVector3( 0.0f, 0.0f, mHeadOffset.mV[2] );
-			mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot.getWorldPosition() + headOffset );
+			mVoiceVisualizer->setVoiceSourceWorldPosition( mRoot->getWorldPosition() + headOffset );
 		}
 		else 
 		{
-			LLVector3 tagPos = mRoot.getWorldPosition();
+			LLVector3 tagPos = mRoot->getWorldPosition();
 			tagPos[VZ] -= mPelvisToFoot;
 			tagPos[VZ] += ( mBodySize[VZ] + 0.125f );
 			mVoiceVisualizer->setVoiceSourceWorldPosition( tagPos );
@@ -3338,7 +2844,7 @@ void LLVOAvatar::invalidateNameTags()
 // Compute name tag position during idle update
 LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)
 {
-	LLQuaternion root_rot = mRoot.getWorldRotation();
+	LLQuaternion root_rot = mRoot->getWorldRotation();
 	LLVector3 pixel_right_vec;
 	LLVector3 pixel_up_vec;
 	LLViewerCamera::getInstance()->getPixelVectors(root_pos_last, pixel_up_vec, pixel_right_vec);
@@ -3352,7 +2858,7 @@ LLVector3 LLVOAvatar::idleUpdateNameTagPosition(const LLVector3& root_pos_last)
 	local_camera_up.scaleVec(mBodySize * 0.5f);
 	local_camera_at.scaleVec(mBodySize * 0.5f);
 
-	LLVector3 name_position = mRoot.getWorldPosition();
+	LLVector3 name_position = mRoot->getWorldPosition();
 	name_position[VZ] -= mPelvisToFoot;
 	name_position[VZ] += (mBodySize[VZ]* 0.55f);
 	name_position += (local_camera_up * root_rot) - (projected_vec(local_camera_at * root_rot, camera_to_av));	
@@ -3417,13 +2923,13 @@ void LLVOAvatar::idleUpdateBelowWater()
 void LLVOAvatar::slamPosition()
 {
 	gAgent.setPositionAgent(getPositionAgent());
-	mRoot.setWorldPosition(getPositionAgent()); // teleport
+	mRoot->setWorldPosition(getPositionAgent()); // teleport
 	setChanged(TRANSLATED);
 	if (mDrawable.notNull())
 	{
 		gPipeline.updateMoveNormalAsync(mDrawable);
 	}
-	mRoot.updateWorldMatrixChildren();
+	mRoot->updateWorldMatrixChildren();
 }
 
 bool LLVOAvatar::isVisuallyMuted() const
@@ -3600,8 +3106,8 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 			throttle = FALSE;
 
 			// put the pelvis at slaved position/mRotation
-			mRoot.setWorldPosition( getPositionAgent() ); // first frame
-			mRoot.setWorldRotation( getRotation() );
+			mRoot->setWorldPosition( getPositionAgent() ); // first frame
+			mRoot->setWorldRotation( getRotation() );
 		}
 	
 		//--------------------------------------------------------------------
@@ -3644,10 +3150,10 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 		
 		LLVector3 newPosition = gAgent.getPosAgentFromGlobal(root_pos);
 
-		if (newPosition != mRoot.getXform()->getWorldPosition())
+		if (newPosition != mRoot->getXform()->getWorldPosition())
 		{		
-			mRoot.touch();
-			mRoot.setWorldPosition( newPosition ); // regular update				
+			mRoot->touch();
+			mRoot->setWorldPosition( newPosition ); // regular update				
 		}
 
 
@@ -3708,7 +3214,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 				
 			}
 
-			LLQuaternion root_rotation = mRoot.getWorldMatrix().quaternion();
+			LLQuaternion root_rotation = mRoot->getWorldMatrix().quaternion();
 			F32 root_roll, root_pitch, root_yaw;
 			root_rotation.getEulerAngles(&root_roll, &root_pitch, &root_yaw);
 
@@ -3717,7 +3223,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 			// and head turn.  Once in motion, it must conform however.
 			BOOL self_in_mouselook = isSelf() && gAgentCamera.cameraMouselook();
 
-			LLVector3 pelvisDir( mRoot.getWorldMatrix().getFwdRow4().mV );
+			LLVector3 pelvisDir( mRoot->getWorldMatrix().getFwdRow4().mV );
 
 			static LLCachedControl<F32> s_pelvis_rot_threshold_slow(gSavedSettings, "AvatarRotateThresholdSlow");
 			static LLCachedControl<F32> s_pelvis_rot_threshold_fast(gSavedSettings, "AvatarRotateThresholdFast");
@@ -3803,14 +3309,14 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 
 			F32 u = llclamp((deltaTime / pelvis_lag_time), 0.0f, 1.0f);	
 
-			mRoot.setWorldRotation( slerp(u, mRoot.getWorldRotation(), wQv) );
+			mRoot->setWorldRotation( slerp(u, mRoot->getWorldRotation(), wQv) );
 			
 		}
 	}
 	else if (mDrawable.notNull())
 	{
-		mRoot.setPosition(mDrawable->getPosition());
-		mRoot.setRotation(mDrawable->getRotation());
+		mRoot->setPosition(mDrawable->getPosition());
+		mRoot->setRotation(mDrawable->getRotation());
 	}
 	
 	//-------------------------------------------------------------------------
@@ -3910,7 +3416,7 @@ BOOL LLVOAvatar::updateCharacter(LLAgent &agent)
 		}
 	}
 
-	mRoot.updateWorldMatrixChildren();
+	mRoot->updateWorldMatrixChildren();
 
 	if (!mDebugText.size() && mText.notNull())
 	{
@@ -3934,7 +3440,7 @@ void LLVOAvatar::updateHeadOffset()
 {
 	// since we only care about Z, just grab one of the eyes
 	LLVector3 midEyePt = mEyeLeftp->getWorldPosition();
-	midEyePt -= mDrawable.notNull() ? mDrawable->getWorldPosition() : mRoot.getWorldPosition();
+	midEyePt -= mDrawable.notNull() ? mDrawable->getWorldPosition() : mRoot->getWorldPosition();
 	midEyePt.mV[VZ] = llmax(-mPelvisToFoot + LLViewerCamera::getInstance()->getNear(), midEyePt.mV[VZ]);
 
 	if (mDrawable.notNull())
@@ -3972,8 +3478,8 @@ void LLVOAvatar::setPelvisOffset( bool hasOffset, const LLVector3& offsetAmount,
 void LLVOAvatar::postPelvisSetRecalc( void )
 {	
 	computeBodySize(); 
-	mRoot.touch();
-	mRoot.updateWorldMatrixChildren();	
+	mRoot->touch();
+	mRoot->updateWorldMatrixChildren();	
 	dirtyMesh();
 	updateHeadOffset();
 }
@@ -4207,19 +3713,44 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 		if (mNeedsSkin)
 		{
 			//generate animated mesh
-			mMeshLOD[MESH_ID_LOWER_BODY]->updateJointGeometry();
-			mMeshLOD[MESH_ID_UPPER_BODY]->updateJointGeometry();
+			LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY);
+			LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY);
+			LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT);
+			LLViewerJoint* eyelash_mesh = getViewerJoint(MESH_ID_EYELASH);
+			LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD);
+			LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
+
+			if(upper_mesh)
+			{
+				upper_mesh->updateJointGeometry();
+			}
+			if (lower_mesh)
+			{
+				lower_mesh->updateJointGeometry();
+			}
 
 			if( isWearingWearableType( LLWearableType::WT_SKIRT ) )
 			{
-				mMeshLOD[MESH_ID_SKIRT]->updateJointGeometry();
+				if(skirt_mesh)
+				{
+					skirt_mesh->updateJointGeometry();
+				}
 			}
 
 			if (!isSelf() || gAgent.needsRenderHead() || LLPipeline::sShadowRender)
 			{
-				mMeshLOD[MESH_ID_EYELASH]->updateJointGeometry();
-				mMeshLOD[MESH_ID_HEAD]->updateJointGeometry();
-				mMeshLOD[MESH_ID_HAIR]->updateJointGeometry();
+				if(eyelash_mesh)
+				{
+					eyelash_mesh->updateJointGeometry();
+				}
+				if(head_mesh)
+				{
+					head_mesh->updateJointGeometry();
+				}
+				if(hair_mesh)
+				{
+					hair_mesh->updateJointGeometry();
+				}
 			}
 			mNeedsSkin = FALSE;
 			mLastSkinTime = gFrameTimeSeconds;
@@ -4336,19 +3867,31 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 			{
 				if (isTextureVisible(TEX_HEAD_BAKED) || mIsDummy)
 				{
-					num_indices += mMeshLOD[MESH_ID_HEAD]->render(mAdjustedPixelArea, TRUE, mIsDummy);
+					LLViewerJoint* head_mesh = getViewerJoint(MESH_ID_HEAD);
+					if (head_mesh)
+					{
+						num_indices += head_mesh->render(mAdjustedPixelArea, TRUE, mIsDummy);
+					}
 					first_pass = FALSE;
 				}
 			}
 			if (isTextureVisible(TEX_UPPER_BAKED) || mIsDummy)
 			{
-				num_indices += mMeshLOD[MESH_ID_UPPER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
+				LLViewerJoint* upper_mesh = getViewerJoint(MESH_ID_UPPER_BODY);
+				if (upper_mesh)
+				{
+					num_indices += upper_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
+				}
 				first_pass = FALSE;
 			}
 			
 			if (isTextureVisible(TEX_LOWER_BAKED) || mIsDummy)
 			{
-				num_indices += mMeshLOD[MESH_ID_LOWER_BODY]->render(mAdjustedPixelArea, first_pass, mIsDummy);
+				LLViewerJoint* lower_mesh = getViewerJoint(MESH_ID_LOWER_BODY);
+				if (lower_mesh)
+				{
+					num_indices += lower_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
+				}
 				first_pass = FALSE;
 			}
 		}
@@ -4381,7 +3924,11 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 	if( isWearingWearableType( LLWearableType::WT_SKIRT ) && (mIsDummy || isTextureVisible(TEX_SKIRT_BAKED)) )
 	{
 		gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.25f);
-		num_indices += mMeshLOD[MESH_ID_SKIRT]->render(mAdjustedPixelArea, FALSE);
+		LLViewerJoint* skirt_mesh = getViewerJoint(MESH_ID_SKIRT);
+		if (skirt_mesh)
+		{
+			num_indices += skirt_mesh->render(mAdjustedPixelArea, FALSE);
+		}
 		first_pass = FALSE;
 		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 	}
@@ -4395,14 +3942,22 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 		
 		if (isTextureVisible(TEX_HEAD_BAKED))
 		{
-			num_indices += mMeshLOD[MESH_ID_EYELASH]->render(mAdjustedPixelArea, first_pass, mIsDummy);
+			LLViewerJoint* eyelash_mesh = getViewerJoint(MESH_ID_EYELASH);
+			if (eyelash_mesh)
+			{
+				num_indices += eyelash_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
+			}
 			first_pass = FALSE;
 		}
 		// Can't test for baked hair being defined, since that won't always be the case (not all viewers send baked hair)
 		// TODO: 1.25 will be able to switch this logic back to calling isTextureVisible();
 		if (getImage(TEX_HAIR_BAKED, 0)->getID() != IMG_INVISIBLE || LLDrawPoolAlpha::sShowDebugAlpha)
 		{
-			num_indices += mMeshLOD[MESH_ID_HAIR]->render(mAdjustedPixelArea, first_pass, mIsDummy);
+			LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
+			if (hair_mesh)
+			{
+				num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
+			}
 			first_pass = FALSE;
 		}
 		if (LLPipeline::sImpostorRender)
@@ -4446,8 +4001,16 @@ U32 LLVOAvatar::renderRigid()
 
 	if (isTextureVisible(TEX_EYES_BAKED)  || mIsDummy)
 	{
-		num_indices += mMeshLOD[MESH_ID_EYEBALL_LEFT]->render(mAdjustedPixelArea, TRUE, mIsDummy);
-		num_indices += mMeshLOD[MESH_ID_EYEBALL_RIGHT]->render(mAdjustedPixelArea, TRUE, mIsDummy);
+		LLViewerJoint* eyeball_left = getViewerJoint(MESH_ID_EYEBALL_LEFT);
+		LLViewerJoint* eyeball_right = getViewerJoint(MESH_ID_EYEBALL_RIGHT);
+		if (eyeball_left)
+		{
+			num_indices += eyeball_left->render(mAdjustedPixelArea, TRUE, mIsDummy);
+		}
+		if(eyeball_right)
+		{
+			num_indices += eyeball_right->render(mAdjustedPixelArea, TRUE, mIsDummy);
+		}
 	}
 
 	if (should_alpha_mask && !LLGLSLShader::sNoFixedFunction)
@@ -5139,7 +4702,7 @@ LLJoint *LLVOAvatar::getJoint( const std::string &name )
 
 	if (iter == mJointMap.end() || iter->second == NULL)
 	{ //search for joint and cache found joint in lookup table
-		jointp = mRoot.findJoint(name);
+		jointp = mRoot->findJoint(name);
 		mJointMap[name] = jointp;
 	}
 	else
@@ -5168,7 +4731,7 @@ void LLVOAvatar::resetJointPositions( void )
 //-----------------------------------------------------------------------------
 void LLVOAvatar::resetSpecificJointPosition( const std::string& name )
 {
-	LLJoint* pJoint = mRoot.findJoint( name );
+	LLJoint* pJoint = mRoot->findJoint( name );
 	
 	if ( pJoint  && pJoint->doesJointNeedToBeReset() )
 	{
@@ -5356,23 +4919,6 @@ BOOL LLVOAvatar::allocateCharacterJoints( U32 num )
 	return TRUE;
 }
 
-//-----------------------------------------------------------------------------
-// allocateCollisionVolumes()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::allocateCollisionVolumes( U32 num )
-{
-	deleteAndClearArray(mCollisionVolumes);
-	mNumCollisionVolumes = 0;
-
-	mCollisionVolumes = new LLViewerJointCollisionVolume[num];
-	if (!mCollisionVolumes)
-	{
-		return FALSE;
-	}
-
-	mNumCollisionVolumes = num;
-	return TRUE;
-}
 
 
 //-----------------------------------------------------------------------------
@@ -5397,154 +4943,14 @@ void LLVOAvatar::requestStopMotion( LLMotion* motion )
 	// Only agent avatars should handle the stop motion notifications.
 }
 
-//-----------------------------------------------------------------------------
-// loadAvatar()
-//-----------------------------------------------------------------------------
-static LLFastTimer::DeclareTimer FTM_LOAD_AVATAR("Load Avatar");
-
-BOOL LLVOAvatar::loadAvatar()
-{
-// 	LLFastTimer t(FTM_LOAD_AVATAR);
-	
-	// avatar_skeleton.xml
-	if( !buildSkeleton(sAvatarSkeletonInfo) )
-	{
-		llwarns << "avatar file: buildSkeleton() failed" << llendl;
-		return FALSE;
-	}
-
-	// avatar_lad.xml : <skeleton>
-	if( !loadSkeletonNode() )
-	{
-		llwarns << "avatar file: loadNodeSkeleton() failed" << llendl;
-		return FALSE;
-	}
-	
-	// avatar_lad.xml : <mesh>
-	if( !loadMeshNodes() )
-	{
-		llwarns << "avatar file: loadNodeMesh() failed" << llendl;
-		return FALSE;
-	}
-	
-	// avatar_lad.xml : <global_color>
-	if( sAvatarXmlInfo->mTexSkinColorInfo )
-	{
-		mTexSkinColor = new LLTexGlobalColor( this );
-		if( !mTexSkinColor->setInfo( sAvatarXmlInfo->mTexSkinColorInfo ) )
-		{
-			llwarns << "avatar file: mTexSkinColor->setInfo() failed" << llendl;
-			return FALSE;
-		}
-	}
-	else
-	{
-		llwarns << "<global_color> name=\"skin_color\" not found" << llendl;
-		return FALSE;
-	}
-	if( sAvatarXmlInfo->mTexHairColorInfo )
-	{
-		mTexHairColor = new LLTexGlobalColor( this );
-		if( !mTexHairColor->setInfo( sAvatarXmlInfo->mTexHairColorInfo ) )
-		{
-			llwarns << "avatar file: mTexHairColor->setInfo() failed" << llendl;
-			return FALSE;
-		}
-	}
-	else
-	{
-		llwarns << "<global_color> name=\"hair_color\" not found" << llendl;
-		return FALSE;
-	}
-	if( sAvatarXmlInfo->mTexEyeColorInfo )
-	{
-		mTexEyeColor = new LLTexGlobalColor( this );
-		if( !mTexEyeColor->setInfo( sAvatarXmlInfo->mTexEyeColorInfo ) )
-		{
-			llwarns << "avatar file: mTexEyeColor->setInfo() failed" << llendl;
-			return FALSE;
-		}
-	}
-	else
-	{
-		llwarns << "<global_color> name=\"eye_color\" not found" << llendl;
-		return FALSE;
-	}
-	
-	// avatar_lad.xml : <layer_set>
-	if (sAvatarXmlInfo->mLayerInfoList.empty())
-	{
-		llwarns << "avatar file: missing <layer_set> node" << llendl;
-		return FALSE;
-	}
-
-	if (sAvatarXmlInfo->mMorphMaskInfoList.empty())
-	{
-		llwarns << "avatar file: missing <morph_masks> node" << llendl;
-		return FALSE;
-	}
-
-	// avatar_lad.xml : <morph_masks>
-	for (LLVOAvatarXmlInfo::morph_info_list_t::iterator iter = sAvatarXmlInfo->mMorphMaskInfoList.begin();
-		 iter != sAvatarXmlInfo->mMorphMaskInfoList.end();
-		 ++iter)
-	{
-		LLVOAvatarXmlInfo::LLVOAvatarMorphInfo *info = *iter;
-
-		EBakedTextureIndex baked = LLAvatarAppearanceDictionary::findBakedByRegionName(info->mRegion); 
-		if (baked != BAKED_NUM_INDICES)
-		{
-			LLVisualParam* morph_param;
-			const std::string *name = &info->mName;
-			morph_param = getVisualParam(name->c_str());
-			if (morph_param)
-			{
-				BOOL invert = info->mInvert;
-				addMaskedMorph(baked, morph_param, invert, info->mLayer);
-			}
-		}
-
-	}
-
-	loadLayersets();	
-	
-	// avatar_lad.xml : <driver_parameters>
-	for (LLVOAvatarXmlInfo::driver_info_list_t::iterator iter = sAvatarXmlInfo->mDriverInfoList.begin();
-		 iter != sAvatarXmlInfo->mDriverInfoList.end(); 
-		 ++iter)
-	{
-		LLDriverParamInfo *info = *iter;
-		LLDriverParam* driver_param = new LLDriverParam( this );
-		if (driver_param->setInfo(info))
-		{
-			addVisualParam( driver_param );
-			LLVisualParam*(LLVOAvatar::*avatar_function)(S32)const = &LLVOAvatar::getVisualParam; 
-			if( !driver_param->linkDrivenParams(boost::bind(avatar_function,(LLVOAvatar*)this,_1 ), false))
-			{
-				llwarns << "could not link driven params for avatar " << this->getFullname() << " id: " << driver_param->getID() << llendl;
-				continue;
-			}
-		}
-		else
-		{
-			delete driver_param;
-			llwarns << "avatar file: driver_param->parseData() failed" << llendl;
-			return FALSE;
-		}
-	}
-
-	
-	return TRUE;
-}
-
 //-----------------------------------------------------------------------------
 // loadSkeletonNode(): loads <skeleton> node from XML tree
 //-----------------------------------------------------------------------------
+//virtual
 BOOL LLVOAvatar::loadSkeletonNode ()
 {
-	mRoot.addChild( &mSkeleton[0] );
-
-	for (std::vector<LLViewerJoint *>::iterator iter = mMeshLOD.begin();
+	// make meshes children before calling parent version of the function
+	for (std::vector<LLAvatarJoint *>::iterator iter = mMeshLOD.begin();
 		 iter != mMeshLOD.end(); 
 		 ++iter)
 	{
@@ -5553,60 +4959,19 @@ BOOL LLVOAvatar::loadSkeletonNode ()
 		joint->setMeshesToChildren();
 	}
 
-	mRoot.addChild(mMeshLOD[MESH_ID_HEAD]);
-	mRoot.addChild(mMeshLOD[MESH_ID_EYELASH]);
-	mRoot.addChild(mMeshLOD[MESH_ID_UPPER_BODY]);
-	mRoot.addChild(mMeshLOD[MESH_ID_LOWER_BODY]);
-	mRoot.addChild(mMeshLOD[MESH_ID_SKIRT]);
-	mRoot.addChild(mMeshLOD[MESH_ID_HEAD]);
-
-	LLViewerJoint *skull = (LLViewerJoint*)mRoot.findJoint("mSkull");
-	if (skull)
-	{
-		skull->addChild(mMeshLOD[MESH_ID_HAIR] );
-	}
-
-	LLViewerJoint *eyeL = (LLViewerJoint*)mRoot.findJoint("mEyeLeft");
-	if (eyeL)
+	if (!LLAvatarAppearance::loadSkeletonNode())
 	{
-		eyeL->addChild( mMeshLOD[MESH_ID_EYEBALL_LEFT] );
-	}
-
-	LLViewerJoint *eyeR = (LLViewerJoint*)mRoot.findJoint("mEyeRight");
-	if (eyeR)
-	{
-		eyeR->addChild( mMeshLOD[MESH_ID_EYEBALL_RIGHT] );
+		return FALSE;
 	}
 
-	// SKELETAL DISTORTIONS
-	{
-		LLVOAvatarXmlInfo::skeletal_distortion_info_list_t::iterator iter;
-		for (iter = sAvatarXmlInfo->mSkeletalDistortionInfoList.begin();
-			 iter != sAvatarXmlInfo->mSkeletalDistortionInfoList.end(); 
-			 ++iter)
-		{
-			LLPolySkeletalDistortionInfo *info = *iter;
-			LLPolySkeletalDistortion *param = new LLPolySkeletalDistortion(this);
-			if (!param->setInfo(info))
-			{
-				delete param;
-				return FALSE;
-			}
-			else
-			{
-				addVisualParam(param);
-			}				
-		}
-	}
-	
 	// ATTACHMENTS
 	{
-		LLVOAvatarXmlInfo::attachment_info_list_t::iterator iter;
+		LLAvatarXmlInfo::attachment_info_list_t::iterator iter;
 		for (iter = sAvatarXmlInfo->mAttachmentInfoList.begin();
 			 iter != sAvatarXmlInfo->mAttachmentInfoList.end(); 
 			 ++iter)
 		{
-			LLVOAvatarXmlInfo::LLVOAvatarAttachmentInfo *info = *iter;
+			LLAvatarXmlInfo::LLAvatarAttachmentInfo *info = *iter;
 			if (!isSelf() && info->mJointName == "mScreen")
 			{ //don't process screen joint for other avatars
 				continue;
@@ -5678,144 +5043,6 @@ BOOL LLVOAvatar::loadSkeletonNode ()
 	return TRUE;
 }
 
-//-----------------------------------------------------------------------------
-// loadMeshNodes(): loads <mesh> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::loadMeshNodes()
-{
-	for (LLVOAvatarXmlInfo::mesh_info_list_t::const_iterator meshinfo_iter = sAvatarXmlInfo->mMeshInfoList.begin();
-		 meshinfo_iter != sAvatarXmlInfo->mMeshInfoList.end(); 
-		 ++meshinfo_iter)
-	{
-		const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo *info = *meshinfo_iter;
-		const std::string &type = info->mType;
-		S32 lod = info->mLOD;
-
-		LLViewerJointMesh* mesh = NULL;
-		U8 mesh_id = 0;
-		BOOL found_mesh_id = FALSE;
-
-		/* if (type == "hairMesh")
-			switch(lod)
-			  case 0:
-				mesh = &mHairMesh0; */
-		for (LLAvatarAppearanceDictionary::Meshes::const_iterator mesh_iter = LLAvatarAppearanceDictionary::getInstance()->getMeshes().begin();
-			 mesh_iter != LLAvatarAppearanceDictionary::getInstance()->getMeshes().end();
-			 ++mesh_iter)
-		{
-			const EMeshIndex mesh_index = mesh_iter->first;
-			const LLAvatarAppearanceDictionary::MeshEntry *mesh_dict = mesh_iter->second;
-			if (type.compare(mesh_dict->mName) == 0)
-			{
-				mesh_id = mesh_index;
-				found_mesh_id = TRUE;
-				break;
-			}
-		}
-
-		if (found_mesh_id)
-		{
-			if (lod < (S32)mMeshLOD[mesh_id]->mMeshParts.size())
-			{
-				mesh = mMeshLOD[mesh_id]->mMeshParts[lod];
-			}
-			else
-			{
-				llwarns << "Avatar file: <mesh> has invalid lod setting " << lod << llendl;
-				return FALSE;
-			}
-		}
-		else 
-		{
-			llwarns << "Ignoring unrecognized mesh type: " << type << llendl;
-			return FALSE;
-		}
-
-		//	llinfos << "Parsing mesh data for " << type << "..." << llendl;
-
-		// If this isn't set to white (1.0), avatars will *ALWAYS* be darker than their surroundings.
-		// Do not touch!!!
-		mesh->setColor( 1.0f, 1.0f, 1.0f, 1.0f );
-
-		LLPolyMesh *poly_mesh = NULL;
-
-		if (!info->mReferenceMeshName.empty())
-		{
-			polymesh_map_t::const_iterator polymesh_iter = mMeshes.find(info->mReferenceMeshName);
-			if (polymesh_iter != mMeshes.end())
-			{
-				poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName, polymesh_iter->second);
-				poly_mesh->setAvatar(this);
-			}
-			else
-			{
-				// This should never happen
-				LL_WARNS("Avatar") << "Could not find avatar mesh: " << info->mReferenceMeshName << LL_ENDL;
-			}
-		}
-		else
-		{
-			poly_mesh = LLPolyMesh::getMesh(info->mMeshFileName);
-			poly_mesh->setAvatar(this);
-		}
-
-		if( !poly_mesh )
-		{
-			llwarns << "Failed to load mesh of type " << type << llendl;
-			return FALSE;
-		}
-
-		// Multimap insert
-		mMeshes.insert(std::make_pair(info->mMeshFileName, poly_mesh));
-	
-		mesh->setMesh( poly_mesh );
-		mesh->setLOD( info->mMinPixelArea );
-
-		for (LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_list_t::const_iterator xmlinfo_iter = info->mPolyMorphTargetInfoList.begin();
-			 xmlinfo_iter != info->mPolyMorphTargetInfoList.end(); 
-			 ++xmlinfo_iter)
-		{
-			const LLVOAvatarXmlInfo::LLVOAvatarMeshInfo::morph_info_pair_t *info_pair = &(*xmlinfo_iter);
-			LLPolyMorphTarget *param = new LLPolyMorphTarget(mesh->getMesh());
-			if (!param->setInfo(info_pair->first))
-			{
-				delete param;
-				return FALSE;
-			}
-			else
-			{
-				if (info_pair->second)
-				{
-					addSharedVisualParam(param);
-				}
-				else
-				{
-					addVisualParam(param);
-				}
-			}				
-		}
-	}
-
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// loadLayerSets()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::loadLayersets()
-{
-	BOOL success = TRUE;
-	for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator layerset_iter = sAvatarXmlInfo->mLayerInfoList.begin();
-		 layerset_iter != sAvatarXmlInfo->mLayerInfoList.end(); 
-		 ++layerset_iter)
-	{
-		// Construct a layerset for each one specified in avatar_lad.xml and initialize it as such.
-		LLTexLayerSetInfo *layerset_info = *layerset_iter;
-		layerset_info->createVisualParams(this);
-	}
-	return success;
-}
-
 //-----------------------------------------------------------------------------
 // updateVisualParams()
 //-----------------------------------------------------------------------------
@@ -5829,7 +5056,7 @@ void LLVOAvatar::updateVisualParams()
 	{
 		computeBodySize();
 		mLastSkeletonSerialNum = mSkeletonSerialNum;
-		mRoot.updateWorldMatrixChildren();
+		mRoot->updateWorldMatrixChildren();
 	}
 
 	dirtyMesh();
@@ -5919,7 +5146,12 @@ BOOL LLVOAvatar::updateJointLODs()
 		}
 
 		// now select meshes to render based on adjusted pixel area
-		BOOL res = mRoot.updateLOD(mAdjustedPixelArea, TRUE);
+		LLViewerJoint* root = dynamic_cast<LLViewerJoint*>(mRoot);
+		BOOL res = FALSE;
+		if (root)
+		{
+			res = root->updateLOD(mAdjustedPixelArea, TRUE);
+		}
  		if (res)
 		{
 			sNumLODChangesThisFrame++;
@@ -6009,6 +5241,15 @@ void LLVOAvatar::dirtyMesh(S32 priority)
 {
 	mDirtyMesh = llmax(mDirtyMesh, priority);
 }
+
+//-----------------------------------------------------------------------------
+// getViewerJoint()
+//-----------------------------------------------------------------------------
+LLViewerJoint*	LLVOAvatar::getViewerJoint(S32 idx)
+{
+	return dynamic_cast<LLViewerJoint*>(mMeshLOD[idx]);
+}
+
 //-----------------------------------------------------------------------------
 // hideSkirt()
 //-----------------------------------------------------------------------------
@@ -6322,9 +5563,9 @@ void LLVOAvatar::sitOnObject(LLViewerObject *sit_object)
 	// Notice that removing sitDown() from here causes avatars sitting on
 	// objects to be not rendered for new arrivals. See EXT-6835 and EXT-1655.
 	sitDown(TRUE);
-	mRoot.getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject
-	mRoot.setPosition(getPosition());
-	mRoot.updateWorldMatrixChildren();
+	mRoot->getXform()->setParent(&sit_object->mDrawable->mXform); // LLVOAvatar::sitOnObject
+	mRoot->setPosition(getPosition());
+	mRoot->updateWorldMatrixChildren();
 
 	stopMotion(ANIM_AGENT_BODY_NOISE);
 
@@ -6370,10 +5611,10 @@ void LLVOAvatar::getOffObject()
 
 	sitDown(FALSE);
 
-	mRoot.getXform()->setParent(NULL); // LLVOAvatar::getOffObject
-	mRoot.setPosition(cur_position_world);
-	mRoot.setRotation(cur_rotation_world);
-	mRoot.getXform()->update();
+	mRoot->getXform()->setParent(NULL); // LLVOAvatar::getOffObject
+	mRoot->setPosition(cur_position_world);
+	mRoot->setRotation(cur_rotation_world);
+	mRoot->getXform()->update();
 
 	startMotion(ANIM_AGENT_BODY_NOISE);
 
@@ -7752,501 +6993,20 @@ void LLVOAvatar::startAppearanceAnimation()
 	}
 }
 
-// virtual
-void LLVOAvatar::removeMissingBakedTextures()
-{	
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatarXmlInfo
-//-----------------------------------------------------------------------------
-
-LLVOAvatar::LLVOAvatarXmlInfo::LLVOAvatarXmlInfo()
-	: mTexSkinColorInfo(0), mTexHairColorInfo(0), mTexEyeColorInfo(0)
-{
-}
-
-LLVOAvatar::LLVOAvatarXmlInfo::~LLVOAvatarXmlInfo()
-{
-	std::for_each(mMeshInfoList.begin(), mMeshInfoList.end(), DeletePointer());
-	std::for_each(mSkeletalDistortionInfoList.begin(), mSkeletalDistortionInfoList.end(), DeletePointer());		
-	std::for_each(mAttachmentInfoList.begin(), mAttachmentInfoList.end(), DeletePointer());
-	deleteAndClear(mTexSkinColorInfo);
-	deleteAndClear(mTexHairColorInfo);
-	deleteAndClear(mTexEyeColorInfo);
-	std::for_each(mLayerInfoList.begin(), mLayerInfoList.end(), DeletePointer());		
-	std::for_each(mDriverInfoList.begin(), mDriverInfoList.end(), DeletePointer());
-	std::for_each(mMorphMaskInfoList.begin(), mMorphMaskInfoList.end(), DeletePointer());
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatarBoneInfo::parseXml()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatarBoneInfo::parseXml(LLXmlTreeNode* node)
-{
-	if (node->hasName("bone"))
-	{
-		mIsJoint = TRUE;
-		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
-		if (!node->getFastAttributeString(name_string, mName))
-		{
-			llwarns << "Bone without name" << llendl;
-			return FALSE;
-		}
-	}
-	else if (node->hasName("collision_volume"))
-	{
-		mIsJoint = FALSE;
-		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
-		if (!node->getFastAttributeString(name_string, mName))
-		{
-			mName = "Collision Volume";
-		}
-	}
-	else
-	{
-		llwarns << "Invalid node " << node->getName() << llendl;
-		return FALSE;
-	}
-
-	static LLStdStringHandle pos_string = LLXmlTree::addAttributeString("pos");
-	if (!node->getFastAttributeVector3(pos_string, mPos))
-	{
-		llwarns << "Bone without position" << llendl;
-		return FALSE;
-	}
-
-	static LLStdStringHandle rot_string = LLXmlTree::addAttributeString("rot");
-	if (!node->getFastAttributeVector3(rot_string, mRot))
-	{
-		llwarns << "Bone without rotation" << llendl;
-		return FALSE;
-	}
-	
-	static LLStdStringHandle scale_string = LLXmlTree::addAttributeString("scale");
-	if (!node->getFastAttributeVector3(scale_string, mScale))
-	{
-		llwarns << "Bone without scale" << llendl;
-		return FALSE;
-	}
-
-	if (mIsJoint)
-	{
-		static LLStdStringHandle pivot_string = LLXmlTree::addAttributeString("pivot");
-		if (!node->getFastAttributeVector3(pivot_string, mPivot))
-		{
-			llwarns << "Bone without pivot" << llendl;
-			return FALSE;
-		}
-	}
-
-	// parse children
-	LLXmlTreeNode* child;
-	for( child = node->getFirstChild(); child; child = node->getNextChild() )
-	{
-		LLVOAvatarBoneInfo *child_info = new LLVOAvatarBoneInfo;
-		if (!child_info->parseXml(child))
-		{
-			delete child_info;
-			return FALSE;
-		}
-		mChildList.push_back(child_info);
-	}
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// LLVOAvatarSkeletonInfo::parseXml()
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatarSkeletonInfo::parseXml(LLXmlTreeNode* node)
-{
-	static LLStdStringHandle num_bones_string = LLXmlTree::addAttributeString("num_bones");
-	if (!node->getFastAttributeS32(num_bones_string, mNumBones))
-	{
-		llwarns << "Couldn't find number of bones." << llendl;
-		return FALSE;
-	}
-
-	static LLStdStringHandle num_collision_volumes_string = LLXmlTree::addAttributeString("num_collision_volumes");
-	node->getFastAttributeS32(num_collision_volumes_string, mNumCollisionVolumes);
-
-	LLXmlTreeNode* child;
-	for( child = node->getFirstChild(); child; child = node->getNextChild() )
-	{
-		LLVOAvatarBoneInfo *info = new LLVOAvatarBoneInfo;
-		if (!info->parseXml(child))
-		{
-			delete info;
-			llwarns << "Error parsing bone in skeleton file" << llendl;
-			return FALSE;
-		}
-		mBoneInfoList.push_back(info);
-	}
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlSkeletonNode(): parses <skeleton> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlSkeletonNode(LLXmlTreeNode* root)
-{
-	LLXmlTreeNode* node = root->getChildByName( "skeleton" );
-	if( !node )
-	{
-		llwarns << "avatar file: missing <skeleton>" << llendl;
-		return FALSE;
-	}
-
-	LLXmlTreeNode* child;
-
-	// SKELETON DISTORTIONS
-	for (child = node->getChildByName( "param" );
-		 child;
-		 child = node->getNextNamedChild())
-	{
-		if (!child->getChildByName("param_skeleton"))
-		{
-			if (child->getChildByName("param_morph"))
-			{
-				llwarns << "Can't specify morph param in skeleton definition." << llendl;
-			}
-			else
-			{
-				llwarns << "Unknown param type." << llendl;
-			}
-			continue;
-		}
-		
-		LLPolySkeletalDistortionInfo *info = new LLPolySkeletalDistortionInfo;
-		if (!info->parseXml(child))
-		{
-			delete info;
-			return FALSE;
-		}
-
-		mSkeletalDistortionInfoList.push_back(info);
-	}
-
-	// ATTACHMENT POINTS
-	for (child = node->getChildByName( "attachment_point" );
-		 child;
-		 child = node->getNextNamedChild())
-	{
-		LLVOAvatarAttachmentInfo* info = new LLVOAvatarAttachmentInfo();
-
-		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
-		if (!child->getFastAttributeString(name_string, info->mName))
-		{
-			llwarns << "No name supplied for attachment point." << llendl;
-			delete info;
-			continue;
-		}
-
-		static LLStdStringHandle joint_string = LLXmlTree::addAttributeString("joint");
-		if (!child->getFastAttributeString(joint_string, info->mJointName))
-		{
-			llwarns << "No bone declared in attachment point " << info->mName << llendl;
-			delete info;
-			continue;
-		}
-
-		static LLStdStringHandle position_string = LLXmlTree::addAttributeString("position");
-		if (child->getFastAttributeVector3(position_string, info->mPosition))
-		{
-			info->mHasPosition = TRUE;
-		}
-
-		static LLStdStringHandle rotation_string = LLXmlTree::addAttributeString("rotation");
-		if (child->getFastAttributeVector3(rotation_string, info->mRotationEuler))
-		{
-			info->mHasRotation = TRUE;
-		}
-		 static LLStdStringHandle group_string = LLXmlTree::addAttributeString("group");
-		if (child->getFastAttributeS32(group_string, info->mGroup))
-		{
-			if (info->mGroup == -1)
-				info->mGroup = -1111; // -1 = none parsed, < -1 = bad value
-		}
-
-		static LLStdStringHandle id_string = LLXmlTree::addAttributeString("id");
-		if (!child->getFastAttributeS32(id_string, info->mAttachmentID))
-		{
-			llwarns << "No id supplied for attachment point " << info->mName << llendl;
-			delete info;
-			continue;
-		}
-
-		static LLStdStringHandle slot_string = LLXmlTree::addAttributeString("pie_slice");
-		child->getFastAttributeS32(slot_string, info->mPieMenuSlice);
-			
-		static LLStdStringHandle visible_in_first_person_string = LLXmlTree::addAttributeString("visible_in_first_person");
-		child->getFastAttributeBOOL(visible_in_first_person_string, info->mVisibleFirstPerson);
-
-		static LLStdStringHandle hud_attachment_string = LLXmlTree::addAttributeString("hud");
-		child->getFastAttributeBOOL(hud_attachment_string, info->mIsHUDAttachment);
-
-		mAttachmentInfoList.push_back(info);
-	}
-
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlMeshNodes(): parses <mesh> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMeshNodes(LLXmlTreeNode* root)
-{
-	for (LLXmlTreeNode* node = root->getChildByName( "mesh" );
-		 node;
-		 node = root->getNextNamedChild())
-	{
-		LLVOAvatarMeshInfo *info = new LLVOAvatarMeshInfo;
-
-		// attribute: type
-		static LLStdStringHandle type_string = LLXmlTree::addAttributeString("type");
-		if( !node->getFastAttributeString( type_string, info->mType ) )
-		{
-			llwarns << "Avatar file: <mesh> is missing type attribute.  Ignoring element. " << llendl;
-			delete info;
-			return FALSE;  // Ignore this element
-		}
-		
-		static LLStdStringHandle lod_string = LLXmlTree::addAttributeString("lod");
-		if (!node->getFastAttributeS32( lod_string, info->mLOD ))
-		{
-			llwarns << "Avatar file: <mesh> is missing lod attribute.  Ignoring element. " << llendl;
-			delete info;
-			return FALSE;  // Ignore this element
-		}
-
-		static LLStdStringHandle file_name_string = LLXmlTree::addAttributeString("file_name");
-		if( !node->getFastAttributeString( file_name_string, info->mMeshFileName ) )
-		{
-			llwarns << "Avatar file: <mesh> is missing file_name attribute.  Ignoring: " << info->mType << llendl;
-			delete info;
-			return FALSE;  // Ignore this element
-		}
-
-		static LLStdStringHandle reference_string = LLXmlTree::addAttributeString("reference");
-		node->getFastAttributeString( reference_string, info->mReferenceMeshName );
-		
-		// attribute: min_pixel_area
-		static LLStdStringHandle min_pixel_area_string = LLXmlTree::addAttributeString("min_pixel_area");
-		static LLStdStringHandle min_pixel_width_string = LLXmlTree::addAttributeString("min_pixel_width");
-		if (!node->getFastAttributeF32( min_pixel_area_string, info->mMinPixelArea ))
-		{
-			F32 min_pixel_area = 0.1f;
-			if (node->getFastAttributeF32( min_pixel_width_string, min_pixel_area ))
-			{
-				// this is square root of pixel area (sensible to use linear space in defining lods)
-				min_pixel_area = min_pixel_area * min_pixel_area;
-			}
-			info->mMinPixelArea = min_pixel_area;
-		}
-		
-		// Parse visual params for this node only if we haven't already
-		for (LLXmlTreeNode* child = node->getChildByName( "param" );
-			 child;
-			 child = node->getNextNamedChild())
-		{
-			if (!child->getChildByName("param_morph"))
-			{
-				if (child->getChildByName("param_skeleton"))
-				{
-					llwarns << "Can't specify skeleton param in a mesh definition." << llendl;
-				}
-				else
-				{
-					llwarns << "Unknown param type." << llendl;
-				}
-				continue;
-			}
-
-			LLPolyMorphTargetInfo *morphinfo = new LLPolyMorphTargetInfo();
-			if (!morphinfo->parseXml(child))
-			{
-				delete morphinfo;
-				delete info;
-				return -1;
-			}
-			BOOL shared = FALSE;
-			static LLStdStringHandle shared_string = LLXmlTree::addAttributeString("shared");
-			child->getFastAttributeBOOL(shared_string, shared);
-
-			info->mPolyMorphTargetInfoList.push_back(LLVOAvatarMeshInfo::morph_info_pair_t(morphinfo, shared));
-		}
-
-		mMeshInfoList.push_back(info);
-	}
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlColorNodes(): parses <global_color> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlColorNodes(LLXmlTreeNode* root)
-{
-	for (LLXmlTreeNode* color_node = root->getChildByName( "global_color" );
-		 color_node;
-		 color_node = root->getNextNamedChild())
-	{
-		std::string global_color_name;
-		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("name");
-		if (color_node->getFastAttributeString( name_string, global_color_name ) )
-		{
-			if( global_color_name == "skin_color" )
-			{
-				if (mTexSkinColorInfo)
-				{
-					llwarns << "avatar file: multiple instances of skin_color" << llendl;
-					return FALSE;
-				}
-				mTexSkinColorInfo = new LLTexGlobalColorInfo;
-				if( !mTexSkinColorInfo->parseXml( color_node ) )
-				{
-					deleteAndClear(mTexSkinColorInfo);
-					llwarns << "avatar file: mTexSkinColor->parseXml() failed" << llendl;
-					return FALSE;
-				}
-			}
-			else if( global_color_name == "hair_color" )
-			{
-				if (mTexHairColorInfo)
-				{
-					llwarns << "avatar file: multiple instances of hair_color" << llendl;
-					return FALSE;
-				}
-				mTexHairColorInfo = new LLTexGlobalColorInfo;
-				if( !mTexHairColorInfo->parseXml( color_node ) )
-				{
-					deleteAndClear(mTexHairColorInfo);
-					llwarns << "avatar file: mTexHairColor->parseXml() failed" << llendl;
-					return FALSE;
-				}
-			}
-			else if( global_color_name == "eye_color" )
-			{
-				if (mTexEyeColorInfo)
-				{
-					llwarns << "avatar file: multiple instances of eye_color" << llendl;
-					return FALSE;
-				}
-				mTexEyeColorInfo = new LLTexGlobalColorInfo;
-				if( !mTexEyeColorInfo->parseXml( color_node ) )
-				{
-					llwarns << "avatar file: mTexEyeColor->parseXml() failed" << llendl;
-					return FALSE;
-				}
-			}
-		}
-	}
-	return TRUE;
-}
-
-//-----------------------------------------------------------------------------
-// parseXmlLayerNodes(): parses <layer_set> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlLayerNodes(LLXmlTreeNode* root)
+//virtual
+void LLVOAvatar::bodySizeChanged()
 {
-	for (LLXmlTreeNode* layer_node = root->getChildByName( "layer_set" );
-		 layer_node;
-		 layer_node = root->getNextNamedChild())
-	{
-		LLTexLayerSetInfo* layer_info = new LLTexLayerSetInfo();
-		if( layer_info->parseXml( layer_node ) )
-		{
-			mLayerInfoList.push_back(layer_info);
-		}
-		else
-		{
-			delete layer_info;
-			llwarns << "avatar file: layer_set->parseXml() failed" << llendl;
-			return FALSE;
-		}
+	if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF())
+	{	// notify simulator of change in size
+		// but not if we are in the middle of updating appearance
+		gAgent.sendAgentSetAppearance();
 	}
-	return TRUE;
 }
 
-//-----------------------------------------------------------------------------
-// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlDriverNodes(LLXmlTreeNode* root)
-{
-	LLXmlTreeNode* driver = root->getChildByName( "driver_parameters" );
-	if( driver )
-	{
-		for (LLXmlTreeNode* grand_child = driver->getChildByName( "param" );
-			 grand_child;
-			 grand_child = driver->getNextNamedChild())
-		{
-			if( grand_child->getChildByName( "param_driver" ) )
-			{
-				LLDriverParamInfo* driver_info = new LLDriverParamInfo();
-				if( driver_info->parseXml( grand_child ) )
-				{
-					mDriverInfoList.push_back(driver_info);
-				}
-				else
-				{
-					delete driver_info;
-					llwarns << "avatar file: driver_param->parseXml() failed" << llendl;
-					return FALSE;
-				}
-			}
-		}
-	}
-	return TRUE;
-}
 
-//-----------------------------------------------------------------------------
-// parseXmlDriverNodes(): parses <driver_parameters> nodes from XML tree
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::LLVOAvatarXmlInfo::parseXmlMorphNodes(LLXmlTreeNode* root)
-{
-	LLXmlTreeNode* masks = root->getChildByName( "morph_masks" );
-	if( !masks )
-	{
-		return FALSE;
-	}
-
-	for (LLXmlTreeNode* grand_child = masks->getChildByName( "mask" );
-		 grand_child;
-		 grand_child = masks->getNextNamedChild())
-	{
-		LLVOAvatarMorphInfo* info = new LLVOAvatarMorphInfo();
-
-		static LLStdStringHandle name_string = LLXmlTree::addAttributeString("morph_name");
-		if (!grand_child->getFastAttributeString(name_string, info->mName))
-		{
-			llwarns << "No name supplied for morph mask." << llendl;
-			delete info;
-			continue;
-		}
-
-		static LLStdStringHandle region_string = LLXmlTree::addAttributeString("body_region");
-		if (!grand_child->getFastAttributeString(region_string, info->mRegion))
-		{
-			llwarns << "No region supplied for morph mask." << llendl;
-			delete info;
-			continue;
-		}
-
-		static LLStdStringHandle layer_string = LLXmlTree::addAttributeString("layer");
-		if (!grand_child->getFastAttributeString(layer_string, info->mLayer))
-		{
-			llwarns << "No layer supplied for morph mask." << llendl;
-			delete info;
-			continue;
-		}
-
-		// optional parameter. don't throw a warning if not present.
-		static LLStdStringHandle invert_string = LLXmlTree::addAttributeString("invert");
-		grand_child->getFastAttributeBOOL(invert_string, info->mInvert);
-
-		mMorphMaskInfoList.push_back(info);
-	}
-
-	return TRUE;
+// virtual
+void LLVOAvatar::removeMissingBakedTextures()
+{	
 }
 
 //virtual
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index dd8663f4dc..bda09b044d 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -69,8 +69,7 @@ class LLVoiceVisualizer;
 class LLHUDNameTag;
 class LLHUDEffectSpiral;
 class LLTexGlobalColor;
-class LLVOAvatarBoneInfo;
-class LLVOAvatarSkeletonInfo;
+class LLViewerJoint;
 
 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 // LLVOAvatar
@@ -85,8 +84,6 @@ class LLVOAvatar :
 
 public:
 	friend class LLVOAvatarSelf;
-protected:
-	struct LLVOAvatarXmlInfo;
 
 /********************************************************************************
  **                                                                            **
@@ -111,9 +108,6 @@ public:
 	virtual void 		initInstance(); // Called after construction to initialize the class.
 protected:
 	virtual				~LLVOAvatar();
-	BOOL				loadSkeletonNode();
-	BOOL				loadMeshNodes();
-	virtual BOOL		loadLayersets();
 
 /**                    Initialization
  **                                                                            **
@@ -190,7 +184,7 @@ public:
 	void					dumpAnimationState();
 
 	virtual LLJoint*		getJoint(const std::string &name);
-	virtual LLJoint*     	getRootJoint() { return &mRoot; }
+	virtual LLJoint*     	getRootJoint() { return mRoot; }
 	
 	void					resetJointPositions( void );
 	void					resetJointPositionsToDefault( void );
@@ -224,7 +218,6 @@ public:
 public:
 	virtual bool 	isSelf() const { return false; } // True if this avatar is for this viewer's agent
 	/*virtual*/BOOL	isUsingBakedTextures() const { return mUseServerBakes; } // e.g. false if in appearance edit mode		
-	bool isBuilt() const { return mIsBuilt; }
 
 private: //aligned members
 	LL_ALIGN_16(LLVector4a	mImpostorExtents[2]);
@@ -343,7 +336,6 @@ protected:
 /**                    State
  **                                                                            **
  *******************************************************************************/
-
 /********************************************************************************
  **                                                                            **
  **                    SKELETON
@@ -351,74 +343,22 @@ protected:
 
 public:
 	void				updateHeadOffset();
-	F32					getPelvisToFoot() const { return mPelvisToFoot; }
 	void				setPelvisOffset( bool hasOffset, const LLVector3& translation, F32 offset ) ;
 	bool				hasPelvisOffset( void ) { return mHasPelvisOffset; }
 	void				postPelvisSetRecalc( void );
 	void				setPelvisOffset( F32 pelvixFixupAmount );
 
+	/*virtual*/ BOOL	loadSkeletonNode();
+	/*virtual*/ void	buildCharacter();
+
 	bool				mHasPelvisOffset;
 	LLVector3			mPelvisOffset;
 	F32					mLastPelvisToFoot;
 	F32					mPelvisFixup;
 	F32					mLastPelvisFixup;
 
-	LLVector3			mHeadOffset; // current head position
-	LLViewerJoint		mRoot;
-
-	typedef std::map<std::string, LLJoint*> joint_map_t;
-	joint_map_t			mJointMap;
-
-protected:
-	static BOOL			parseSkeletonFile(const std::string& filename);
-	void				buildCharacter();
-	virtual BOOL		loadAvatar();
-
-	BOOL				setupBone(const LLVOAvatarBoneInfo* info, LLViewerJoint* parent, S32 &current_volume_num, S32 &current_joint_num);
-	BOOL				buildSkeleton(const LLVOAvatarSkeletonInfo *info);
-private:
-	BOOL				mIsBuilt; // state of deferred character building
-	S32					mNumJoints;
-	LLViewerJoint*		mSkeleton;
-	
-	//--------------------------------------------------------------------
-	// Pelvis height adjustment members.
-	//--------------------------------------------------------------------
-public:
-	LLVector3			mBodySize;
 	S32					mLastSkeletonSerialNum;
-private:
-	F32					mPelvisToFoot;
 
-	//--------------------------------------------------------------------
-	// Cached pointers to well known joints
-	//--------------------------------------------------------------------
-public:
-	LLViewerJoint* 		mPelvisp;
-	LLViewerJoint* 		mTorsop;
-	LLViewerJoint* 		mChestp;
-	LLViewerJoint* 		mNeckp;
-	LLViewerJoint* 		mHeadp;
-	LLViewerJoint* 		mSkullp;
-	LLViewerJoint* 		mEyeLeftp;
-	LLViewerJoint* 		mEyeRightp;
-	LLViewerJoint* 		mHipLeftp;
-	LLViewerJoint* 		mHipRightp;
-	LLViewerJoint* 		mKneeLeftp;
-	LLViewerJoint* 		mKneeRightp;
-	LLViewerJoint* 		mAnkleLeftp;
-	LLViewerJoint* 		mAnkleRightp;
-	LLViewerJoint* 		mFootLeftp;
-	LLViewerJoint* 		mFootRightp;
-	LLViewerJoint* 		mWristLeftp;
-	LLViewerJoint* 		mWristRightp;
-
-	//--------------------------------------------------------------------
-	// XML parse tree
-	//--------------------------------------------------------------------
-private:
-	static LLXmlTree 	sXMLTree; // avatar config file
-	static LLXmlTree 	sSkeletonXMLTree; // avatar skeleton file
 
 /**                    Skeleton
  **                                                                            **
@@ -640,8 +580,6 @@ public:
 private:
 	static const LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary *getDictionary() { return sAvatarDictionary; }
 	static LLAvatarAppearanceDefines::LLAvatarAppearanceDictionary* sAvatarDictionary;
-	static LLVOAvatarSkeletonInfo* 					sAvatarSkeletonInfo;
-	static LLVOAvatarXmlInfo* 						sAvatarXmlInfo;
 
 	//--------------------------------------------------------------------
 	// Messaging
@@ -671,13 +609,10 @@ protected:
 	virtual void restoreMeshData();
 private:
 	virtual void	dirtyMesh(S32 priority); // Dirty the avatar mesh, with priority
+	LLViewerJoint*	getViewerJoint(S32 idx);
 	S32 			mDirtyMesh; // 0 -- not dirty, 1 -- morphed, 2 -- LOD
 	BOOL			mMeshTexturesDirty;
 
-	typedef std::multimap<std::string, LLPolyMesh*> polymesh_map_t;
-	polymesh_map_t 									mMeshes;
-	std::vector<LLViewerJoint *> 					mMeshLOD;
-
 	//--------------------------------------------------------------------
 	// Destroy invisible mesh
 	//--------------------------------------------------------------------
@@ -698,6 +633,7 @@ public:
 	void 			processAvatarAppearance(LLMessageSystem* mesgsys);
 	void 			hideSkirt();
 	void			startAppearanceAnimation();
+	/*virtual*/ void bodySizeChanged();
 	
 	//--------------------------------------------------------------------
 	// Appearance morphing
@@ -839,15 +775,6 @@ private:
 	BOOL 		mTurning; // controls hysteresis on avatar rotation
 	F32			mSpeed; // misc. animation repeated state
 
-	//--------------------------------------------------------------------
-	// Collision volumes
-	//--------------------------------------------------------------------
-public:
-  	S32			mNumCollisionVolumes;
-	LLViewerJointCollisionVolume* mCollisionVolumes;
-protected:
-	BOOL		allocateCollisionVolumes(U32 num);
-
 	//--------------------------------------------------------------------
 	// Dimensions
 	//--------------------------------------------------------------------
@@ -858,7 +785,6 @@ public:
 	void 		resolveRayCollisionAgent(const LLVector3d start_pt, const LLVector3d end_pt, LLVector3d &out_pos, LLVector3 &out_norm);
 	void 		slamPosition(); // Slam position to transmitted position (for teleport);
 protected:
-	void 		computeBodySize();
 
 	//--------------------------------------------------------------------
 	// Material being stepped on
@@ -1025,90 +951,6 @@ protected:
 
 protected: // Shared with LLVOAvatarSelf
 
-	struct LLVOAvatarXmlInfo
-	{
-		LLVOAvatarXmlInfo();
-		~LLVOAvatarXmlInfo();
-
-		BOOL 	parseXmlSkeletonNode(LLXmlTreeNode* root);
-		BOOL 	parseXmlMeshNodes(LLXmlTreeNode* root);
-		BOOL 	parseXmlColorNodes(LLXmlTreeNode* root);
-		BOOL 	parseXmlLayerNodes(LLXmlTreeNode* root);
-		BOOL 	parseXmlDriverNodes(LLXmlTreeNode* root);
-		BOOL	parseXmlMorphNodes(LLXmlTreeNode* root);
-
-		struct LLVOAvatarMeshInfo
-		{
-			typedef std::pair<LLPolyMorphTargetInfo*,BOOL> morph_info_pair_t;
-			typedef std::vector<morph_info_pair_t> morph_info_list_t;
-
-			LLVOAvatarMeshInfo() : mLOD(0), mMinPixelArea(.1f) {}
-			~LLVOAvatarMeshInfo()
-			{
-				morph_info_list_t::iterator iter;
-				for (iter = mPolyMorphTargetInfoList.begin(); iter != mPolyMorphTargetInfoList.end(); iter++)
-				{
-					delete iter->first;
-				}
-				mPolyMorphTargetInfoList.clear();
-			}
-
-			std::string mType;
-			S32			mLOD;
-			std::string	mMeshFileName;
-			std::string	mReferenceMeshName;
-			F32			mMinPixelArea;
-			morph_info_list_t mPolyMorphTargetInfoList;
-		};
-		typedef std::vector<LLVOAvatarMeshInfo*> mesh_info_list_t;
-		mesh_info_list_t mMeshInfoList;
-
-		typedef std::vector<LLPolySkeletalDistortionInfo*> skeletal_distortion_info_list_t;
-		skeletal_distortion_info_list_t mSkeletalDistortionInfoList;
-	
-		struct LLVOAvatarAttachmentInfo
-		{
-			LLVOAvatarAttachmentInfo()
-				: mGroup(-1), mAttachmentID(-1), mPieMenuSlice(-1), mVisibleFirstPerson(FALSE),
-				  mIsHUDAttachment(FALSE), mHasPosition(FALSE), mHasRotation(FALSE) {}
-			std::string mName;
-			std::string mJointName;
-			LLVector3 mPosition;
-			LLVector3 mRotationEuler;
-			S32 mGroup;
-			S32 mAttachmentID;
-			S32 mPieMenuSlice;
-			BOOL mVisibleFirstPerson;
-			BOOL mIsHUDAttachment;
-			BOOL mHasPosition;
-			BOOL mHasRotation;
-		};
-		typedef std::vector<LLVOAvatarAttachmentInfo*> attachment_info_list_t;
-		attachment_info_list_t mAttachmentInfoList;
-	
-		LLTexGlobalColorInfo *mTexSkinColorInfo;
-		LLTexGlobalColorInfo *mTexHairColorInfo;
-		LLTexGlobalColorInfo *mTexEyeColorInfo;
-
-		typedef std::vector<LLTexLayerSetInfo*> layer_info_list_t;
-		layer_info_list_t mLayerInfoList;
-
-		typedef std::vector<LLDriverParamInfo*> driver_info_list_t;
-		driver_info_list_t mDriverInfoList;
-
-		struct LLVOAvatarMorphInfo
-		{
-			LLVOAvatarMorphInfo()
-				: mInvert(FALSE) {}
-			std::string mName;
-			std::string mRegion;
-			std::string mLayer;
-			BOOL mInvert;
-		};
-
-		typedef std::vector<LLVOAvatarMorphInfo*> morph_info_list_t;
-		morph_info_list_t	mMorphMaskInfoList;
-	};
 
 /**                    Support classes
  **                                                                            **
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index fc52347041..f832a126bd 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -255,7 +255,7 @@ BOOL LLVOAvatarSelf::loadAvatarSelf()
 	return success;
 }
 
-BOOL LLVOAvatarSelf::buildSkeletonSelf(const LLVOAvatarSkeletonInfo *info)
+BOOL LLVOAvatarSelf::buildSkeletonSelf(const LLAvatarSkeletonInfo *info)
 {
 	LLMemType mt(LLMemType::MTYPE_AVATAR);
 
@@ -589,7 +589,7 @@ LLVOAvatarSelf::~LLVOAvatarSelf()
 BOOL LLVOAvatarSelf::loadLayersets()
 {
 	BOOL success = TRUE;
-	for (LLVOAvatarXmlInfo::layer_info_list_t::const_iterator iter = sAvatarXmlInfo->mLayerInfoList.begin();
+	for (LLAvatarXmlInfo::layer_info_list_t::const_iterator iter = sAvatarXmlInfo->mLayerInfoList.begin();
 		 iter != sAvatarXmlInfo->mLayerInfoList.end(); 
 		 ++iter)
 	{
@@ -952,7 +952,7 @@ void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp)
 void LLVOAvatarSelf::idleUpdateTractorBeam()
 {
 	// This is only done for yourself (maybe it should be in the agent?)
-	if (!needsRenderBeam() || !mIsBuilt)
+	if (!needsRenderBeam() || !isBuilt())
 	{
 		mBeam = NULL;
 	}
diff --git a/indra/newview/llvoavatarself.h b/indra/newview/llvoavatarself.h
index 75c2743ab0..bdc1ccf133 100755
--- a/indra/newview/llvoavatarself.h
+++ b/indra/newview/llvoavatarself.h
@@ -67,7 +67,7 @@ public:
 protected:
 	/*virtual*/ BOOL		loadAvatar();
 	BOOL					loadAvatarSelf();
-	BOOL					buildSkeletonSelf(const LLVOAvatarSkeletonInfo *info);
+	BOOL					buildSkeletonSelf(const LLAvatarSkeletonInfo *info);
 	BOOL					buildMenus();
 	/*virtual*/ BOOL		loadLayersets();
 
-- 
cgit v1.2.3