diff --git a/indra/cmake/00-Common.cmake b/indra/cmake/00-Common.cmake
index beb4f181b5f52f0dae5c81f4669ff76b1e594fab..8b0864a5395c5a9e2a8d124967074aa5e19693a0 100644
--- a/indra/cmake/00-Common.cmake
+++ b/indra/cmake/00-Common.cmake
@@ -38,7 +38,7 @@ if (WINDOWS)
   set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /MP"
       CACHE STRING "C++ compiler debug options" FORCE)
   set(CMAKE_CXX_FLAGS_RELWITHDEBINFO 
-      "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /Gm /INCREMENTAL"
+      "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /Gm"
       CACHE STRING "C++ compiler release-with-debug options" FORCE)
   set(CMAKE_CXX_FLAGS_RELEASE
       "${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP"
diff --git a/indra/cmake/GooglePerfTools.cmake b/indra/cmake/GooglePerfTools.cmake
index 946fc6b375edc1599712b4bde9f2fda19876b4ec..ee231dcde6850ff52a51dcdb0c2519121fbb3946 100644
--- a/indra/cmake/GooglePerfTools.cmake
+++ b/indra/cmake/GooglePerfTools.cmake
@@ -6,7 +6,7 @@ if (STANDALONE)
 else (STANDALONE)
   use_prebuilt_binary(google)
   if (WINDOWS)
-    use_prebuilt_binary(google-perftools)
+    use_prebuilt_binary(tcmalloc)
     set(TCMALLOC_LIBRARIES 
         debug libtcmalloc_minimal-debug
         optimized libtcmalloc_minimal)
@@ -29,8 +29,7 @@ if (GOOGLE_PERFTOOLS_FOUND)
 endif (GOOGLE_PERFTOOLS_FOUND)
 
 if (WINDOWS)
-    # *TODO -reenable this once we get server usage sorted out
-    #set(USE_GOOGLE_PERFTOOLS ON)
+    set(USE_GOOGLE_PERFTOOLS ON)
 endif (WINDOWS)
 
 if (USE_GOOGLE_PERFTOOLS)
diff --git a/indra/llmath/lloctree.h b/indra/llmath/lloctree.h
index 73910ef98df38bf0663f496bc171c47495ef9be3..63adfa85b2781b9bc12a5d34a3fdae6fb7eaaccd 100644
--- a/indra/llmath/lloctree.h
+++ b/indra/llmath/lloctree.h
@@ -95,22 +95,30 @@ public:
 	typedef LLOctreeNode<T>		oct_node;
 	typedef LLOctreeListener<T>	oct_listener;
 
+	/*void* operator new(size_t size)
+	{
+		return ll_aligned_malloc_16(size);
+	}
+
+	void operator delete(void* ptr)
+	{
+		ll_aligned_free_16(ptr);
+	}*/
+
 	LLOctreeNode(	const LLVector4a& center, 
 					const LLVector4a& size, 
 					BaseType* parent, 
-					S32 octant = -1)
+					U8 octant = 255)
 	:	mParent((oct_node*)parent), 
 		mOctant(octant) 
 	{ 
-		mD = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*4);
-
-		mD[CENTER] = center;
-		mD[SIZE] = size;
+		mCenter = center;
+		mSize = size;
 
 		updateMinMax();
-		if ((mOctant == -1) && mParent)
+		if ((mOctant == 255) && mParent)
 		{
-			mOctant = ((oct_node*) mParent)->getOctant(mD[CENTER]);
+			mOctant = ((oct_node*) mParent)->getOctant(mCenter);
 		}
 
 		clearChildren();
@@ -124,30 +132,27 @@ public:
 		{
 			delete getChild(i);
 		} 
-
-		ll_aligned_free_16(mD);
 	}
 
 	inline const BaseType* getParent()	const			{ return mParent; }
 	inline void setParent(BaseType* parent)				{ mParent = (oct_node*) parent; }
-	inline const LLVector4a& getCenter() const			{ return mD[CENTER]; }
-	inline const LLVector4a& getSize() const			{ return mD[SIZE]; }
-	inline void setCenter(const LLVector4a& center)		{ mD[CENTER] = center; }
-	inline void setSize(const LLVector4a& size)			{ mD[SIZE] = size; }
+	inline const LLVector4a& getCenter() const			{ return mCenter; }
+	inline const LLVector4a& getSize() const			{ return mSize; }
+	inline void setCenter(const LLVector4a& center)		{ mCenter = center; }
+	inline void setSize(const LLVector4a& size)			{ mSize = size; }
     inline oct_node* getNodeAt(T* data)					{ return getNodeAt(data->getPositionGroup(), data->getBinRadius()); }
-	inline S32 getOctant() const						{ return mOctant; }
-	inline void setOctant(S32 octant)					{ mOctant = octant; }
+	inline U8 getOctant() const							{ return mOctant; }
 	inline const oct_node*	getOctParent() const		{ return (const oct_node*) getParent(); }
 	inline oct_node* getOctParent() 					{ return (oct_node*) getParent(); }
 	
-	S32 getOctant(const LLVector4a& pos) const			//get the octant pos is in
+	U8 getOctant(const LLVector4a& pos) const			//get the octant pos is in
 	{
-		return pos.greaterThan(mD[CENTER]).getGatheredBits() & 0x7;
+		return (U8) (pos.greaterThan(mCenter).getGatheredBits() & 0x7);
 	}
 	
 	inline bool isInside(const LLVector4a& pos, const F32& rad) const
 	{
-		return rad <= mD[SIZE][0]*2.f && isInside(pos); 
+		return rad <= mSize[0]*2.f && isInside(pos); 
 	}
 
 	inline bool isInside(T* data) const			
@@ -157,13 +162,13 @@ public:
 
 	bool isInside(const LLVector4a& pos) const
 	{
-		S32 gt = pos.greaterThan(mD[MAX]).getGatheredBits() & 0x7;
+		S32 gt = pos.greaterThan(mMax).getGatheredBits() & 0x7;
 		if (gt)
 		{
 			return false;
 		}
 
-		S32 lt = pos.lessEqual(mD[MIN]).getGatheredBits() & 0x7;
+		S32 lt = pos.lessEqual(mMin).getGatheredBits() & 0x7;
 		if (lt)
 		{
 			return false;
@@ -174,8 +179,8 @@ public:
 	
 	void updateMinMax()
 	{
-		mD[MAX].setAdd(mD[CENTER], mD[SIZE]);
-		mD[MIN].setSub(mD[CENTER], mD[SIZE]);
+		mMax.setAdd(mCenter, mSize);
+		mMin.setSub(mCenter, mSize);
 	}
 
 	inline oct_listener* getOctListener(U32 index) 
@@ -195,7 +200,7 @@ public:
 			return false;
 		}
 
-		F32 size = mD[SIZE][0];
+		F32 size = mSize[0];
 		F32 p_size = size * 2.f;
 
 		return (radius <= 0.001f && size <= 0.001f) ||
@@ -234,6 +239,29 @@ public:
 	void accept(tree_traveler* visitor) const		{ visitor->visit(this); }
 	void accept(oct_traveler* visitor) const		{ visitor->visit(this); }
 	
+	void validateChildMap()
+	{
+		for (U32 i = 0; i < 8; i++)
+		{
+			U8 idx = mChildMap[i];
+			if (idx != 255)
+			{
+				LLOctreeNode<T>* child = mChild[idx];
+
+				if (child->getOctant() != i)
+				{
+					llerrs << "Invalid child map, bad octant data." << llendl;
+				}
+
+				if (getOctant(child->getCenter()) != child->getOctant())
+				{
+					llerrs << "Invalid child octant compared to position data." << llendl;
+				}
+			}
+		}
+	}
+
+
 	oct_node* getNodeAt(const LLVector4a& pos, const F32& rad)
 	{ 
 		LLOctreeNode<T>* node = this;
@@ -241,25 +269,19 @@ public:
 		if (node->isInside(pos, rad))
 		{		
 			//do a quick search by octant
-			S32 octant = node->getOctant(pos);
-			BOOL keep_going = TRUE;
-
+			U8 octant = node->getOctant(pos);
+			
 			//traverse the tree until we find a node that has no node
 			//at the appropriate octant or is smaller than the object.  
 			//by definition, that node is the smallest node that contains 
 			// the data
-			while (keep_going && node->getSize()[0] >= rad)
+			U8 next_node = node->mChildMap[octant];
+			
+			while (next_node != 255 && node->getSize()[0] >= rad)
 			{	
-				keep_going = FALSE;
-				for (U32 i = 0; i < node->getChildCount() && !keep_going; i++)
-				{
-					if (node->getChild(i)->getOctant() == octant)
-					{
-						node = node->getChild(i);
-						octant = node->getOctant(pos);
-						keep_going = TRUE;
-					}
-				}
+				node = node->getChild(next_node);
+				octant = node->getOctant(pos);
+				next_node = node->mChildMap[octant];
 			}
 		}
 		else if (!node->contains(rad) && node->getParent())
@@ -439,6 +461,9 @@ public:
 	void clearChildren()
 	{
 		mChild.clear();
+
+		U32* foo = (U32*) mChildMap;
+		foo[0] = foo[1] = 0xFFFFFFFF;
 	}
 
 	void validate()
@@ -496,6 +521,8 @@ public:
 		}
 #endif
 
+		mChildMap[child->getOctant()] = (U8) mChild.size();
+
 		mChild.push_back(child);
 		child->setParent(this);
 
@@ -517,6 +544,8 @@ public:
 			listener->handleChildRemoval(this, getChild(index));
 		}
 
+		
+
 		if (destroy)
 		{
 			mChild[index]->destroy();
@@ -524,6 +553,15 @@ public:
 		}
 		mChild.erase(mChild.begin() + index);
 
+		//rebuild child map
+		U32* foo = (U32*) mChildMap;
+		foo[0] = foo[1] = 0xFFFFFFFF;
+
+		for (U32 i = 0; i < mChild.size(); ++i)
+		{
+			mChildMap[mChild[i]->getOctant()] = i;
+		}
+
 		checkAlive();
 	}
 
@@ -562,15 +600,20 @@ protected:
 		MIN = 3
 	} eDName;
 
-	LLVector4a* mD;
+	LLVector4a mCenter;
+	LLVector4a mSize;
+	LLVector4a mMax;
+	LLVector4a mMin;
 	
 	oct_node* mParent;
-	S32 mOctant;
+	U8 mOctant;
 
 	child_list mChild;
+	U8 mChildMap[8];
+
 	element_list mData;
 		
-};
+}; 
 
 //just like a regular node, except it might expand on insert and compress on balance
 template <class T>
@@ -613,6 +656,8 @@ public:
 			//destroy child
 			child->clearChildren();
 			delete child;
+
+			return false;
 		}
 		
 		return true;
@@ -639,7 +684,7 @@ public:
 		const LLVector4a& v = data->getPositionGroup();
 
 		LLVector4a val;
-		val.setSub(v, BaseType::mD[BaseType::CENTER]);
+		val.setSub(v, BaseType::mCenter);
 		val.setAbs(val);
 		S32 lt = val.lessThan(MAX_MAG).getGatheredBits() & 0x7;
 
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index ab9f8c4c240ad7fd5526a4ed545e79bc1227cee4..24528a8ce9e3b18bfa7c243cf95c8ff1b65971ce 100644
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -94,6 +94,8 @@ const F32 SKEW_MAX	=  0.95f;
 const F32 SCULPT_MIN_AREA = 0.002f;
 const S32 SCULPT_MIN_AREA_DETAIL = 1;
 
+extern BOOL gDebugGL;
+
 BOOL check_same_clock_dir( const LLVector3& pt1, const LLVector3& pt2, const LLVector3& pt3, const LLVector3& norm)
 {    
 	LLVector3 test = (pt2-pt1)%(pt3-pt2);
@@ -308,22 +310,26 @@ public:
 	}
 
 	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
-	{
+	{ //this is a depth first traversal, so it's safe to assum all children have complete
+		//bounding data
+
 		LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
 
 		LLVector4a& min = node->mExtents[0];
 		LLVector4a& max = node->mExtents[1];
 
-		if (branch->getElementCount() != 0)
-		{
+		if (!branch->getData().empty())
+		{ //node has data, find AABB that binds data set
 			const LLVolumeTriangle* tri = *(branch->getData().begin());
-						
+			
+			//initialize min/max to first available vertex
 			min = *(tri->mV[0]);
 			max = *(tri->mV[0]);
 			
 			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = 
 				branch->getData().begin(); iter != branch->getData().end(); ++iter)
-			{
+			{ //for each triangle in node
+
 				//stretch by triangles in node
 				tri = *iter;
 				
@@ -335,33 +341,27 @@ public:
 				max.setMax(max, *tri->mV[1]);
 				max.setMax(max, *tri->mV[2]);
 			}
-
-			for (S32 i = 0; i < branch->getChildCount(); ++i)
-			{  //stretch by child extents
-				LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
-				min.setMin(min, child->mExtents[0]);
-				max.setMax(min, child->mExtents[1]);
-			}
 		}
-		else if (branch->getChildCount() != 0)
-		{
+		else if (!branch->getChildren().empty())
+		{ //no data, but child nodes exist
 			LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(0)->getListener(0);
 
+			//initialize min/max to extents of first child
 			min = child->mExtents[0];
 			max = child->mExtents[1];
-
-			for (S32 i = 1; i < branch->getChildCount(); ++i)
-			{  //stretch by child extents
-				child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
-				min.setMin(min, child->mExtents[0]);
-				max.setMax(max, child->mExtents[1]);
-			}
 		}
 		else
 		{
 			llerrs << "WTF? Empty leaf" << llendl;
 		}
-		
+
+		for (S32 i = 0; i < branch->getChildCount(); ++i)
+		{  //stretch by child extents
+			LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+			min.setMin(min, child->mExtents[0]);
+			max.setMax(max, child->mExtents[1]);
+		}
+
 		node->mBounds[0].setAdd(min, max);
 		node->mBounds[0].mul(0.5f);
 
@@ -370,7 +370,6 @@ public:
 	}
 };
 
-
 //-------------------------------------------------------------------
 // statics
 //-------------------------------------------------------------------
@@ -1991,7 +1990,7 @@ void LLVolumeFace::VertexData::init()
 {
 	if (!mData)
 	{
-		mData = (LLVector4a*) ll_aligned_malloc_16(32);
+		mData = new LLVector4a[2];
 	}
 }
 
@@ -2020,7 +2019,7 @@ const LLVolumeFace::VertexData& LLVolumeFace::VertexData::operator=(const LLVolu
 
 LLVolumeFace::VertexData::~VertexData()
 {
-	ll_aligned_free_16(mData);
+	delete [] mData;
 }
 
 LLVector4a& LLVolumeFace::VertexData::getPosition()
@@ -2258,12 +2257,12 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 					U32 cur_influence = 0;
 					LLVector4 wght(0,0,0,0);
 
-					while (joint != END_INFLUENCES)
+					while (joint != END_INFLUENCES && idx < weights.size())
 					{
 						U16 influence = weights[idx++];
 						influence |= ((U16) weights[idx++] << 8);
 
-						F32 w = llmin((F32) influence / 65535.f, 0.99999f);
+						F32 w = llclamp((F32) influence / 65535.f, 0.f, 0.99999f);
 						wght.mV[cur_influence++] = (F32) joint + w;
 
 						if (cur_influence >= 4)
@@ -2570,14 +2569,13 @@ void LLVolume::makeTetrahedron()
 	mIsTetrahedron = TRUE;
 }
 
-void LLVolume::copyVolumeFaces(LLVolume* volume)
+void LLVolume::copyVolumeFaces(const LLVolume* volume)
 {
 	mVolumeFaces = volume->mVolumeFaces;
 	mSculptLevel = 0;
 	mIsTetrahedron = FALSE;
 }
 
-
 S32	LLVolume::getNumFaces() const
 {
 #if LL_MESH_ENABLED
@@ -5232,7 +5230,7 @@ LLVolumeFace::LLVolumeFace() :
 	mWeights(NULL),
 	mOctree(NULL)
 {
-	mExtents = (LLVector4a*) ll_aligned_malloc_16(48);
+	mExtents = new LLVector4a[3];
 	mCenter = mExtents+2;
 }
 
@@ -5253,7 +5251,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
 	mWeights(NULL),
 	mOctree(NULL)
 { 
-	mExtents = (LLVector4a*) ll_aligned_malloc_16(48);
+	mExtents = new LLVector4a[3];
 	mCenter = mExtents+2;
 	*this = src;
 }
@@ -5288,7 +5286,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 
 	if (mNumVertices)
 	{
-		S32 vert_size = mNumVertices*4*sizeof(F32);
+		S32 vert_size = mNumVertices*sizeof(LLVector4a);
 		S32 tc_size = (mNumVertices*8+0xF) & ~0xF;
 			
 		LLVector4a::memcpyNonAliased16((F32*) mPositions, (F32*) src.mPositions, vert_size);
@@ -5303,7 +5301,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 		}
 		else
 		{
-			ll_aligned_free_16(mBinormals);
+			delete [] mBinormals;
 			mBinormals = NULL;
 		}
 
@@ -5314,7 +5312,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 		}
 		else
 		{
-			ll_aligned_free_16(mWeights);
+			delete [] mWeights;
 			mWeights = NULL;
 		}
 	}
@@ -5332,7 +5330,7 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 
 LLVolumeFace::~LLVolumeFace()
 {
-	ll_aligned_free_16(mExtents);
+	delete [] mExtents;
 	mExtents = NULL;
 
 	freeData();
@@ -5340,17 +5338,17 @@ LLVolumeFace::~LLVolumeFace()
 
 void LLVolumeFace::freeData()
 {
-	ll_aligned_free_16(mPositions);
+	delete [] mPositions;
 	mPositions = NULL;
-	ll_aligned_free_16(mNormals);
+	delete []  mNormals;
 	mNormals = NULL;
-	ll_aligned_free_16(mTexCoords);
+	delete [] mTexCoords;
 	mTexCoords = NULL;
-	ll_aligned_free_16(mIndices);
+	delete [] mIndices;
 	mIndices = NULL;
-	ll_aligned_free_16(mBinormals);
+	delete [] mBinormals;
 	mBinormals = NULL;
-	ll_aligned_free_16(mWeights);
+	delete [] mWeights;
 	mWeights = NULL;
 
 	delete mOctree;
@@ -5463,56 +5461,73 @@ void LLVolumeFace::optimize(F32 angle_cutoff)
 }
 
 
-void LLVolumeFace::createOctree()
+void LLVolumeFace::createOctree(F32 scaler, const LLVector4a& center, const LLVector4a& size)
 {
-	LLVector4a center;
-	LLVector4a size;
-	center.splat(0.f);
-	size.splat(1.f);
+	if (mOctree)
+	{
+		return;
+	}
 
 	mOctree = new LLOctreeRoot<LLVolumeTriangle>(center, size, NULL);
 	new LLVolumeOctreeListener(mOctree);
 
 	for (U32 i = 0; i < mNumIndices; i+= 3)
-	{
+	{ //for each triangle
 		LLPointer<LLVolumeTriangle> tri = new LLVolumeTriangle();
 				
 		const LLVector4a& v0 = mPositions[mIndices[i]];
 		const LLVector4a& v1 = mPositions[mIndices[i+1]];
 		const LLVector4a& v2 = mPositions[mIndices[i+2]];
 
+		//store pointers to vertex data
 		tri->mV[0] = &v0;
 		tri->mV[1] = &v1;
 		tri->mV[2] = &v2;
 
+		//store indices
 		tri->mIndex[0] = mIndices[i];
 		tri->mIndex[1] = mIndices[i+1];
 		tri->mIndex[2] = mIndices[i+2];
 
+		//get minimum point
 		LLVector4a min = v0;
 		min.setMin(min, v1);
 		min.setMin(min, v2);
 
+		//get maximum point
 		LLVector4a max = v0;
 		max.setMax(max, v1);
 		max.setMax(max, v2);
 
+		//compute center
 		LLVector4a center;
 		center.setAdd(min, max);
 		center.mul(0.5f);
 
 		*tri->mPositionGroup = center;
 
+		//compute "radius"
 		LLVector4a size;
 		size.setSub(max,min);
 		
-		tri->mRadius = size.getLength3().getF32() * 0.5f;
+		tri->mRadius = size.getLength3().getF32() * scaler;
 		
+		//insert
 		mOctree->insert(tri);
 	}
 
+	//remove unneeded octree layers
+	while (!mOctree->balance())	{ }
+
+	//calculate AABB for each node
 	LLVolumeOctreeRebound rebound(this);
 	rebound.traverse(mOctree);
+
+	if (gDebugGL)
+	{
+		LLVolumeOctreeValidate validate;
+		validate.traverse(mOctree);
+	}
 }
 
 
@@ -6146,21 +6161,21 @@ void LLVolumeFace::createBinormals()
 
 void LLVolumeFace::resizeVertices(S32 num_verts)
 {
-	ll_aligned_free_16(mPositions);
-	ll_aligned_free_16(mNormals);
-	ll_aligned_free_16(mBinormals);
-	ll_aligned_free_16(mTexCoords);
+	delete [] mPositions;
+	delete [] mNormals;
+	delete [] mBinormals;
+	delete [] mTexCoords;
 
 	mBinormals = NULL;
 
 	if (num_verts)
 	{
-		mPositions = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
-		mNormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+		mPositions = new LLVector4a[num_verts]; 
+		mNormals = new LLVector4a[num_verts]; 
 
 		//pad texture coordinate block end to allow for QWORD reads
 		S32 size = ((num_verts*8) + 0xF) & ~0xF;
-		mTexCoords = (LLVector2*) ll_aligned_malloc_16(size);
+		mTexCoords = new LLVector2[size/8];
 	}
 	else
 	{
@@ -6184,20 +6199,20 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
 	S32 old_size = mNumVertices*16;
 
 	//positions
-	LLVector4a* dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
+	LLVector4a* dst = new LLVector4a[new_verts];
 	if (mPositions)
 	{
 		LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mPositions, old_size);
-		ll_aligned_free_16(mPositions);
+		delete [] mPositions;
 	}
 	mPositions = dst;
 
 	//normals
-	dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
+	dst = new LLVector4a[new_verts]; 
 	if (mNormals)
 	{
 		LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mNormals, old_size);
-		ll_aligned_free_16(mNormals);
+		delete [] mNormals;
 	}
 	mNormals = dst;
 
@@ -6205,19 +6220,18 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
 	new_size = ((new_verts*8)+0xF) & ~0xF;
 	old_size = ((mNumVertices*8)+0xF) & ~0xF;
 
-	dst = (LLVector4a*) ll_aligned_malloc_16(new_size);
 	{
-		LLVector2* dst = (LLVector2*) ll_aligned_malloc_16(new_size);
+		LLVector2* dst = new LLVector2[new_size/8]; 
 		if (mTexCoords)
 		{
 			LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mTexCoords, old_size);
-			ll_aligned_free_16(mTexCoords);
+			delete [] mTexCoords;
 		}
+		mTexCoords = dst;
 	}
-	mTexCoords = (LLVector2*) dst;
 
 	//just clear binormals
-	ll_aligned_free_16(mBinormals);
+	delete [] mBinormals;
 	mBinormals = NULL;
 
 	mPositions[mNumVertices] = pos;
@@ -6229,26 +6243,26 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
 
 void LLVolumeFace::allocateBinormals(S32 num_verts)
 {
-	ll_aligned_free_16(mBinormals);
-	mBinormals = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+	delete [] mBinormals;
+	mBinormals = new LLVector4a[num_verts]; 
 }
 
 void LLVolumeFace::allocateWeights(S32 num_verts)
 {
-	ll_aligned_free_16(mWeights);
-	mWeights = (LLVector4a*) ll_aligned_malloc_16(num_verts*16);
+	delete [] mWeights; 
+	mWeights = new LLVector4a[num_verts]; 
 }
 
 void LLVolumeFace::resizeIndices(S32 num_indices)
 {
-	ll_aligned_free_16(mIndices);
-
+	delete [] mIndices;
+	
 	if (num_indices)
 	{
 		//pad index block end to allow for QWORD reads
 		S32 size = ((num_indices*2) + 0xF) & ~0xF;
 		
-		mIndices = (U16*) ll_aligned_malloc_16(size);	
+		mIndices = new U16[size/2];
 	}
 	else
 	{
@@ -6266,11 +6280,11 @@ void LLVolumeFace::pushIndex(const U16& idx)
 	S32 old_size = ((mNumIndices*2)+0xF) & ~0xF;
 	if (new_size != old_size)
 	{
-		U16* dst = (U16*) ll_aligned_malloc_16(new_size);
+		U16* dst = new U16[new_size/2];
 		if (mIndices)
 		{
 			LLVector4a::memcpyNonAliased16((F32*) dst, (F32*) mIndices, old_size);
-			ll_aligned_free_16(mIndices);
+			delete [] mIndices;
 		}
 		mIndices = dst;
 	}
@@ -6313,9 +6327,9 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
 	}
 
 	//allocate new buffer space
-	LLVector4a* new_pos = (LLVector4a*) ll_aligned_malloc_16(new_count*16);
-	LLVector4a* new_norm = (LLVector4a*) ll_aligned_malloc_16(new_count*16);
-	LLVector2* new_tc = (LLVector2*) ll_aligned_malloc_16((new_count*8+0xF) & ~0xF);
+	LLVector4a* new_pos = new LLVector4a[new_count];
+	LLVector4a* new_norm = new LLVector4a[new_count];
+	LLVector2* new_tc = new LLVector2[((new_count*8+0xF) & ~0xF)/8];
 	
 
 	if (mNumVertices > 0)
@@ -6326,10 +6340,10 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
 	}
 
 	//free old buffer space
-	ll_aligned_free_16(mPositions);
-	ll_aligned_free_16(mNormals);
-	ll_aligned_free_16(mTexCoords);
-
+	delete [] mPositions;
+	delete [] mNormals;
+	delete [] mTexCoords;
+	
 	//point to new buffers
 	mPositions = new_pos;
 	mNormals = new_norm;
@@ -6379,7 +6393,7 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
 	new_count = mNumIndices + face.mNumIndices;
 
 	//allocate new index buffer
-	U16* new_indices = (U16*) ll_aligned_malloc_16((new_count*2+0xF) & ~0xF);
+	U16* new_indices = new U16[((new_count*2+0xF) & ~0xF)/2];
 	if (mNumIndices > 0)
 	{ //copy old index buffer
 		S32 old_size = (mNumIndices*2+0xF) & ~0xF;
@@ -6387,8 +6401,8 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
 	}
 
 	//free old index buffer
-	ll_aligned_free_16(mIndices);
-
+	delete [] mIndices;
+	
 	//point to new index buffer
 	mIndices = new_indices;
 
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index af28337f57d6022f0c98035dca35996b421191e5..32364bd4b80063f6302374a56ef12982e8ab0492 100644
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -882,7 +882,7 @@ public:
 	};
 
 	void optimize(F32 angle_cutoff = 2.f);
-	void createOctree();
+	void createOctree(F32 scaler = 0.25f, const LLVector4a& center = LLVector4a(0,0,0), const LLVector4a& size = LLVector4a(0.5f,0.5f,0.5f));
 
 	enum
 	{
@@ -1044,7 +1044,7 @@ public:
 	LLVector3			mLODScaleBias;		// vector for biasing LOD based on scale
 	
 	void sculpt(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, S32 sculpt_level);
-	void copyVolumeFaces(LLVolume* volume);
+	void copyVolumeFaces(const LLVolume* volume);
 
 private:
 	void sculptGenerateMapVertices(U16 sculpt_width, U16 sculpt_height, S8 sculpt_components, const U8* sculpt_data, U8 sculpt_type);
diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp
index 194b1faf81f157cbe2bba7eec112f22521ff1e61..cb6211f63c4a7f22b2aa192c63cd1970deb6b93b 100644
--- a/indra/llmath/llvolumeoctree.cpp
+++ b/indra/llmath/llvolumeoctree.cpp
@@ -126,8 +126,8 @@ void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>
 	const F32* center = vl->mBounds[0].getF32();
 	const F32* size = vl->mBounds[1].getF32();*/
 
-	//if (LLLineSegmentBoxIntersect(mStart.getF32(), mEnd.getF32(), vl->mBounds[0].getF32(), vl->mBounds[1].getF32()))
-	if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
+	//if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
+	if (LLLineSegmentBoxIntersect(mStart.getF32ptr(), mEnd.getF32ptr(), vl->mBounds[0].getF32ptr(), vl->mBounds[1].getF32ptr()))
 	{
 		node->accept(this);
 		for (S32 i = 0; i < node->getChildCount(); ++i)
@@ -206,3 +206,60 @@ const F32& LLVolumeTriangle::getBinRadius() const
 }
 
 
+//TEST CODE
+
+void LLVolumeOctreeValidate::visit(const LLOctreeNode<LLVolumeTriangle>* branch)
+{
+	LLVolumeOctreeListener* node = (LLVolumeOctreeListener*) branch->getListener(0);
+
+	//make sure bounds matches extents
+	LLVector4a& min = node->mExtents[0];
+	LLVector4a& max = node->mExtents[1];
+
+	LLVector4a& center = node->mBounds[0];
+	LLVector4a& size = node->mBounds[1];
+
+	LLVector4a test_min, test_max;
+	test_min.setSub(center, size);
+	test_max.setAdd(center, size);
+
+	if (!test_min.equals3(min, 0.001f) ||
+		!test_max.equals3(max, 0.001f))
+	{
+		llerrs << "Bad bounding box data found." << llendl;
+	}
+
+	test_min.sub(LLVector4a(0.001f));
+	test_max.add(LLVector4a(0.001f));
+
+	for (U32 i = 0; i < branch->getChildCount(); ++i)
+	{
+		LLVolumeOctreeListener* child = (LLVolumeOctreeListener*) branch->getChild(i)->getListener(0);
+
+		//make sure all children fit inside this node
+		if (child->mExtents[0].lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ) ||
+			child->mExtents[1].greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ))
+		{
+			llerrs << "Child protrudes from bounding box." << llendl;
+		}
+	}
+
+	//children fit, check data
+	for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin(); 
+			iter != branch->getData().end(); ++iter)
+	{
+		const LLVolumeTriangle* tri = *iter;
+
+		//validate triangle
+		for (U32 i = 0; i < 3; i++)
+		{
+			if (tri->mV[i]->greaterThan(test_max).areAnySet(LLVector4Logical::MASK_XYZ) ||
+				tri->mV[i]->lessThan(test_min).areAnySet(LLVector4Logical::MASK_XYZ))
+			{
+				llerrs << "Triangle protrudes from node." << llendl;
+			}
+		}
+	}
+}
+
+
diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h
index 00316264987eae53d7d2d766b0514d3b4866da1e..0a02a2c5972cade84cb80287c3de6aa0f8d98db9 100644
--- a/indra/llmath/llvolumeoctree.h
+++ b/indra/llmath/llvolumeoctree.h
@@ -88,8 +88,6 @@ public:
 	F32* mClosestT;
 	bool mHitFace;
 
-	LLOctreeTriangleRayIntersect() { };
-
 	LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, 
 								   const LLVolumeFace* face, F32* closest_t,
 								   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal);
@@ -134,5 +132,9 @@ public:
 	virtual const F32& getBinRadius() const;
 };
 
+class LLVolumeOctreeValidate : public LLOctreeTraveler<LLVolumeTriangle>
+{
+	virtual void visit(const LLOctreeNode<LLVolumeTriangle>* branch);
+};
 
 #endif
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 73f752b2181869cba0584e7af67f0307d8fc2634..0f2d46151164d296784b4ccf513a260c00d8eb94 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -1422,9 +1422,7 @@ if (WINDOWS)
     
     set_target_properties(${VIEWER_BINARY_NAME}
         PROPERTIES
-        # *TODO -reenable this once we get server usage sorted out
-        #LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:\"__tcmalloc\""
-        LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS"
+        LINK_FLAGS "/debug /NODEFAULTLIB:LIBCMT /SUBSYSTEM:WINDOWS /INCLUDE:__tcmalloc"
         LINK_FLAGS_DEBUG "/NODEFAULTLIB:\"LIBCMT;LIBCMTD;MSVCRT\" /INCREMENTAL:NO"
         LINK_FLAGS_RELEASE ${release_flags}
         )
@@ -1640,6 +1638,7 @@ if (WINDOWS)
 endif (WINDOWS)
 
 target_link_libraries(${VIEWER_BINARY_NAME}
+	${GOOGLE_PERFTOOLS_LIBRARIES}
     ${LLAUDIO_LIBRARIES}
     ${LLCHARACTER_LIBRARIES}
     ${LLIMAGE_LIBRARIES}
@@ -1676,7 +1675,6 @@ target_link_libraries(${VIEWER_BINARY_NAME}
     ${OPENSSL_LIBRARIES}
     ${CRYPTO_LIBRARIES}
     ${LLLOGIN_LIBRARIES}
-    ${GOOGLE_PERFTOOLS_LIBRARIES}
     ${LLCONVEXDECOMP_LIBRARY}
     )
 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 68f52e04bc54ac97f1734653bf85fa26dd30d49e..efbb62011c54666161a39b25652cfebe0b0cbd1e 100644
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -189,6 +189,11 @@ LLVOVolume* LLDrawable::getVOVolume() const
 	}
 }
 
+const LLMatrix4& LLDrawable::getRenderMatrix() const
+{ 
+	return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix();
+}
+
 BOOL LLDrawable::isLight() const
 {
 	LLViewerObject* objectp = mVObjp;
@@ -713,8 +718,7 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update)
 		LLVOVolume* volume = getVOVolume();
 		if (volume)
 		{
-			volume->updateRelativeXform();
-			pos = volume->getRelativeXform().getTranslation();
+			pos.set(getPositionGroup().getF32ptr());
 			if (isStatic())
 			{
 				pos += volume->getRegion()->getOriginAgent();
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index fc90bc57c4e051bf58f87d5c58e55d6c5c1c2dee..a17e2172aa842a0f22188c73293841b6c510c15f 100644
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -101,7 +101,7 @@ public:
 	LLVOVolume*	getVOVolume() const; // cast mVObjp tp LLVOVolume if OK
 
 	const LLMatrix4&      getWorldMatrix() const		{ return mXform.getWorldMatrix(); }
-	const LLMatrix4&	  getRenderMatrix() const		{ return isRoot() ? getWorldMatrix() : getParent()->getWorldMatrix(); }
+	const LLMatrix4&	  getRenderMatrix() const;
 	void				  setPosition(LLVector3 v) const { }
 	const LLVector3&	  getPosition() const			{ return mXform.getPosition(); }
 	const LLVector3&      getWorldPosition() const		{ return mXform.getPositionW(); }
@@ -250,35 +250,37 @@ public:
 	
 	typedef enum e_drawable_flags
 	{
- 		IN_REBUILD_Q1	= 0x00000002,
- 		IN_REBUILD_Q2	= 0x00000004,
- 		IN_LIGHT_Q		= 0x00000008,
-		EARLY_MOVE		= 0x00000010,
-		MOVE_UNDAMPED	= 0x00000020,
-		ON_MOVE_LIST	= 0x00000040,
-		USE_BACKLIGHT	= 0x00000080,
-		UV				= 0x00000100,
-		UNLIT			= 0x00000200,
-		LIGHT			= 0x00000400,
-		LIGHTING_BUILT	= 0x00000800,
-		REBUILD_VOLUME  = 0x00001000,	//volume changed LOD or parameters, or vertex buffer changed
-		REBUILD_TCOORD	= 0x00002000,	//texture coordinates changed
-		REBUILD_COLOR	= 0x00004000,	//color changed
-		REBUILD_POSITION= 0x00010000,	//vertex positions/normals changed
+ 		IN_REBUILD_Q1	= 0x00000001,
+ 		IN_REBUILD_Q2	= 0x00000002,
+ 		IN_LIGHT_Q		= 0x00000004,
+		EARLY_MOVE		= 0x00000008,
+		MOVE_UNDAMPED	= 0x00000010,
+		ON_MOVE_LIST	= 0x00000020,
+		USE_BACKLIGHT	= 0x00000040,
+		UV				= 0x00000080,
+		UNLIT			= 0x00000100,
+		LIGHT			= 0x00000200,
+		LIGHTING_BUILT	= 0x00000400,
+		REBUILD_VOLUME  = 0x00000800,	//volume changed LOD or parameters, or vertex buffer changed
+		REBUILD_TCOORD	= 0x00001000,	//texture coordinates changed
+		REBUILD_COLOR	= 0x00002000,	//color changed
+		REBUILD_POSITION= 0x00004000,	//vertex positions/normals changed
 		REBUILD_GEOMETRY= REBUILD_POSITION|REBUILD_TCOORD|REBUILD_COLOR,
 		REBUILD_MATERIAL= REBUILD_TCOORD|REBUILD_COLOR,
 		REBUILD_ALL		= REBUILD_GEOMETRY|REBUILD_VOLUME,
-		ON_SHIFT_LIST	= 0x00100000,
-		BLOCKER			= 0x00400000,
-		ACTIVE			= 0x00800000,
-		DEAD			= 0x01000000,
-		INVISIBLE		= 0x02000000, // stay invisible until flag is cleared
- 		NEARBY_LIGHT	= 0x04000000, // In gPipeline.mNearbyLightSet
-		BUILT			= 0x08000000,
-		FORCE_INVISIBLE = 0x10000000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
-		CLEAR_INVISIBLE = 0x20000000, // clear FORCE_INVISIBLE next draw frame
-		REBUILD_SHADOW =  0x40000000,
-		HAS_ALPHA		= 0x80000000,
+		REBUILD_RIGGED	= 0x00008000,
+		ON_SHIFT_LIST	= 0x00010000,
+		BLOCKER			= 0x00020000,
+		ACTIVE			= 0x00040000,
+		DEAD			= 0x00080000,
+		INVISIBLE		= 0x00100000, // stay invisible until flag is cleared
+ 		NEARBY_LIGHT	= 0x00200000, // In gPipeline.mNearbyLightSet
+		BUILT			= 0x00400000,
+		FORCE_INVISIBLE = 0x00800000, // stay invis until CLEAR_INVISIBLE is set (set of orphaned)
+		CLEAR_INVISIBLE = 0x01000000, // clear FORCE_INVISIBLE next draw frame
+		REBUILD_SHADOW =  0x02000000,
+		HAS_ALPHA		= 0x04000000,
+		RIGGED			= 0x08000000,
 	} EDrawableFlags;
 
 	LLXformMatrix       mXform;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index ccc060f3fa2af23b9d7f82a2ea1a4c4553d820e1..5cf6082f124ac7db4e3aea790ca05b0c7c16ebd4 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -1325,6 +1325,12 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 #if LL_MESH_ENABLED
 void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
 {
+	LLVector4a* weight = vol_face.mWeights;
+	if (!weight)
+	{
+		return;
+	}
+
 	LLVertexBuffer* buffer = face->mVertexBuffer;
 
 	U32 data_mask = 0;
@@ -1403,8 +1409,6 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
 			}
 		}
 
-		LLVector4a* weight = vol_face.mWeights;
-
 		LLMatrix4a bind_shape_matrix;
 		bind_shape_matrix.loadu(skin->mBindShapeMatrix);
 
@@ -1422,7 +1426,7 @@ void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace*
 			{
 				F32 w = weight[j][k];
 
-				idx[k] = (S32) floorf(w);
+				idx[k] = llclamp((S32) floorf(w), 0, 63);
 				wght[k] = w - floorf(w);
 				scale += wght[k];
 			}
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 7c24eb77cd740801257513de659572b2cf1468e9..3fa60e9f1edc73dae772a1dfa01b9f70b6151f8d 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -556,8 +556,36 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 		}
 
 		glColor4fv(color.mV);
-		mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
-		mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
+	
+		if (mDrawablep->isState(LLDrawable::RIGGED))
+		{
+			LLVOVolume* volume = mDrawablep->getVOVolume();
+			if (volume)
+			{
+				LLRiggedVolume* rigged = volume->getRiggedVolume();
+				if (rigged)
+				{
+					LLGLEnable offset(GL_POLYGON_OFFSET_FILL);
+					glPolygonOffset(-1.f, -1.f);
+					glMultMatrixf((F32*) volume->getRelativeXform().mMatrix);
+					const LLVolumeFace& vol_face = rigged->getVolumeFace(getTEOffset());
+					LLVertexBuffer::unbind();
+					glVertexPointer(3, GL_FLOAT, 16, vol_face.mPositions);
+					if (vol_face.mTexCoords)
+					{
+						glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+						glTexCoordPointer(2, GL_FLOAT, 8, vol_face.mTexCoords);
+					}
+					glDrawElements(GL_TRIANGLES, vol_face.mNumIndices, GL_UNSIGNED_SHORT, vol_face.mIndices);
+					glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+				}
+			}
+		}
+		else
+		{
+			mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
+			mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
+		}
 
 		gGL.popMatrix();
 	}
@@ -720,7 +748,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 	LLMemType mt1(LLMemType::MTYPE_DRAWABLE);
 
 	//get bounding box
-	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
+	if (mDrawablep->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED))
 	{
 		//VECTORIZE THIS
 		LLMatrix4a mat_vert;
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index fa5d9b0892c1598c377a05ef5daee3985473db6c..653f838779801f85e588389ec7ffd450a26dc18b 100644
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -1016,10 +1016,12 @@ S32 LLFloaterTools::calcRenderCost()
 		LLSelectNode *select_node = *selection_iter;
 		if (select_node)
 		{
-			LLVOVolume *viewer_volume = (LLVOVolume*)select_node->getObject();
-			if (viewer_volume)
+			LLViewerObject *vobj = select_node->getObject();
+			if (vobj->getVolume())
 			{
-				cost += viewer_volume->getRenderCost(textures);
+				LLVOVolume* volume = (LLVOVolume*) vobj;
+
+				cost += volume->getRenderCost(textures);
 				for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter)
 				{
 					// add the cost of each individual texture in the linkset
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index ff2929695db6f52e25b40193fb3856ffce8013ab..21f7e780e22db3e5ab3aa8fba8c1ad13e2f1c11f 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -5395,6 +5395,42 @@ BOOL LLSelectNode::allowOperationOnNode(PermissionBit op, U64 group_proxy_power)
 	return (mPermissions->allowOperationBy(op, proxy_agent_id, group_id));
 }
 
+
+//helper function for pushing relevant vertices from drawable to GL
+void pushWireframe(LLDrawable* drawable)
+{
+	if (drawable->isState(LLDrawable::RIGGED))
+	{ //render straight from rigged volume if this is a rigged attachment
+		LLVOVolume* vobj = drawable->getVOVolume();
+		if (vobj)
+		{
+			vobj->updateRiggedVolume();
+			LLRiggedVolume* rigged_volume = vobj->getRiggedVolume();
+			if (rigged_volume)
+			{
+				LLVertexBuffer::unbind();
+				gGL.pushMatrix();
+				glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
+				for (S32 i = 0; i < rigged_volume->getNumVolumeFaces(); ++i)
+				{
+					const LLVolumeFace& face = rigged_volume->getVolumeFace(i);
+					glVertexPointer(3, GL_FLOAT, 16, face.mPositions);
+					glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+				}
+				gGL.popMatrix();
+			}
+		}
+	}
+	else
+	{
+		for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+		{
+			LLFace* face = drawable->getFace(i);
+			pushVerts(face, LLVertexBuffer::MAP_VERTEX);
+		}
+	}
+}
+
 void LLSelectNode::renderOneWireframe(const LLColor4& color)
 {
 	LLViewerObject* objectp = getObject();
@@ -5442,11 +5478,7 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color)
 		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 		{
 			glColor4f(color.mV[VRED], color.mV[VGREEN], color.mV[VBLUE], 0.4f);
-			for (S32 i = 0; i < drawable->getNumFaces(); ++i)
-			{
-				LLFace* face = drawable->getFace(i);
-				pushVerts(face, LLVertexBuffer::MAP_VERTEX);
-			}
+			pushWireframe(drawable);
 		}
 	}
 
@@ -5455,13 +5487,9 @@ void LLSelectNode::renderOneWireframe(const LLColor4& color)
 
 	glColor4f(color.mV[VRED]*2, color.mV[VGREEN]*2, color.mV[VBLUE]*2, LLSelectMgr::sHighlightAlpha*2);
 	LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
-	glPolygonOffset(3.f, 2.f);
+	glPolygonOffset(3.f, 3.f);
 	glLineWidth(3.f);
-	for (S32 i = 0; i < drawable->getNumFaces(); ++i)
-	{
-		LLFace* face = drawable->getFace(i);
-		pushVerts(face, LLVertexBuffer::MAP_VERTEX);
-	}
+	pushWireframe(drawable);
 	glLineWidth(1.f);
 	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 	gGL.popMatrix();
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index 425fa4233912219bda923c90a925407f41acc072..0f9f35dc5771d4fcb9dee3900f1e7b08c59cd384 100644
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -3035,11 +3035,11 @@ class LLRenderOctreeRaycast : public LLOctreeTriangleRayIntersect
 {
 public:
 	
-	LLRenderOctreeRaycast(const LLVector3& start, const LLVector3& end)
+	
+	LLRenderOctreeRaycast(const LLVector4a& start, const LLVector4a& dir, F32* closest_t)
+		: LLOctreeTriangleRayIntersect(start, dir, NULL, closest_t, NULL, NULL, NULL, NULL)
 	{
-		mStart.load3(start.mV);
-		mEnd.load3(end.mV);
-		mDir.setSub(mEnd, mStart);
+
 	}
 
 	void visit(const LLOctreeNode<LLVolumeTriangle>* branch)
@@ -3047,9 +3047,22 @@ public:
 		LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) branch->getListener(0);
 
 		LLVector3 center, size;
-		center.set(vl->mBounds[0].getF32ptr());
-		size.set(vl->mBounds[1].getF32ptr());
+		
+		if (branch->getData().empty())
+		{
+			gGL.color3f(1.f,0.2f,0.f);
+			center.set(branch->getCenter().getF32ptr());
+			size.set(branch->getSize().getF32ptr());
+		}
+		else
+		{
+			gGL.color3f(0.75f, 1.f, 0.f);
+			center.set(vl->mBounds[0].getF32ptr());
+			size.set(vl->mBounds[1].getF32ptr());
+		}
 
+		drawBoxOutline(center, size);	
+		
 		for (U32 i = 0; i < 2; i++)
 		{
 			LLGLDepthTest depth(GL_TRUE, GL_FALSE, i == 1 ? GL_LEQUAL : GL_GREATER);
@@ -3061,9 +3074,14 @@ public:
 			else
 			{
 				gGL.color4f(0,0.5f,0.5f, 0.25f);
+				drawBoxOutline(center, size);
+			}
+			
+			if (i == 1)
+			{
+				gGL.flush();
+				glLineWidth(3.f);
 			}
-
-			drawBoxOutline(center, size);
 
 			gGL.begin(LLRender::TRIANGLES);
 			for (LLOctreeNode<LLVolumeTriangle>::const_element_iter iter = branch->getData().begin();
@@ -3077,6 +3095,12 @@ public:
 				gGL.vertex3fv(tri->mV[2]->getF32ptr());
 			}	
 			gGL.end();
+
+			if (i == 1)
+			{
+				gGL.flush();
+				glLineWidth(1.f);
+			}
 		}
 	}
 };
@@ -3096,26 +3120,63 @@ void renderRaycast(LLDrawable* drawablep)
 
 			LLVOVolume* vobj = drawablep->getVOVolume();
 			LLVolume* volume = vobj->getVolume();
-			for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+
+			bool transform = true;
+			if (drawablep->isState(LLDrawable::RIGGED))
 			{
-				const LLVolumeFace& face = volume->getVolumeFace(i);
-				if (!face.mOctree)
+				volume = vobj->getRiggedVolume();
+				transform = false;
+			}
+
+			if (volume)
+			{
+				for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
 				{
-					((LLVolumeFace*) &face)->createOctree(); 
-				}
+					const LLVolumeFace& face = volume->getVolumeFace(i);
+					if (!face.mOctree)
+					{
+						((LLVolumeFace*) &face)->createOctree(); 
+					}
 
-				gGL.pushMatrix();
-				glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
-				LLVector3 start, end;
-				start = vobj->agentPositionToVolume(gDebugRaycastStart);
-				end = vobj->agentPositionToVolume(gDebugRaycastEnd);
+					gGL.pushMatrix();
+					glMultMatrixf((F32*) vobj->getRelativeXform().mMatrix);
 
-				LLRenderOctreeRaycast render(start, end);
-				gGL.flush();
-				glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-				render.traverse(face.mOctree);
-				gGL.popMatrix();		
-				glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+					LLVector3 start, end;
+					if (transform)
+					{
+						start = vobj->agentPositionToVolume(gDebugRaycastStart);
+						end = vobj->agentPositionToVolume(gDebugRaycastEnd);
+					}
+					else
+					{
+						start = gDebugRaycastStart;
+						end = gDebugRaycastEnd;
+					}
+
+					LLVector4a starta, enda;
+					starta.load3(start.mV);
+					enda.load3(end.mV);
+					LLVector4a dir;
+					dir.setSub(enda, starta);
+
+					F32 t = 1.f;
+
+					LLRenderOctreeRaycast render(starta, dir, &t);
+					gGL.flush();
+					glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+
+					{
+						//render face positions
+						LLVertexBuffer::unbind();
+						glColor4f(0,1,1,0.5f);
+						glVertexPointer(3, GL_FLOAT, sizeof(LLVector4a), face.mPositions);
+						glDrawElements(GL_TRIANGLES, face.mNumIndices, GL_UNSIGNED_SHORT, face.mIndices);
+					}
+						
+					render.traverse(face.mOctree);
+					gGL.popMatrix();		
+					glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+				}
 			}
 		}
 		else if (drawablep->isAvatar())
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index fd2212f25d3c46fd82f9c93d15d853e950d39cc5..4c1a1958e880c36ca7ab61a7738c668affd3d20f 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -3279,6 +3279,15 @@ const LLVector3 LLViewerObject::getPositionEdit() const
 
 const LLVector3 LLViewerObject::getRenderPosition() const
 {
+	if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
+	{
+		LLVOAvatar* avatar = getAvatar();
+		if (avatar)
+		{
+			return avatar->getPositionAgent();
+		}
+	}
+
 	if (mDrawable.isNull() || mDrawable->getGeneration() < 0)
 	{
 		return getPositionAgent();
@@ -3297,6 +3306,11 @@ const LLVector3 LLViewerObject::getPivotPositionAgent() const
 const LLQuaternion LLViewerObject::getRenderRotation() const
 {
 	LLQuaternion ret;
+	if (mDrawable.notNull() && mDrawable->isState(LLDrawable::RIGGED))
+	{
+		return ret;
+	}
+	
 	if (mDrawable.isNull() || mDrawable->isStatic())
 	{
 		ret = getRotationEdit();
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 5448e7dcd9e36d02ef9c1576f2f4357690063722..f09ce5b363f73a9f8079eda2e3cfc80cd4768df8 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -41,9 +41,11 @@
 #include "llviewercontrol.h"
 #include "lldir.h"
 #include "llflexibleobject.h"
+#include "llfloatertools.h"
 #include "llmaterialtable.h"
 #include "llprimitive.h"
 #include "llvolume.h"
+#include "llvolumeoctree.h"
 #include "llvolumemgr.h"
 #include "llvolumemessage.h"
 #include "material_codes.h"
@@ -70,6 +72,7 @@
 #include "llselectmgr.h"
 #include "pipeline.h"
 #include "llsdutil.h"
+#include "llmatrix4a.h"
 #include "llmediaentry.h"
 #include "llmediadataclient.h"
 #include "llmeshrepository.h"
@@ -1355,7 +1358,14 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 
 	LLVector4a min,max;
 
-	BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION);
+	BOOL rebuild = mDrawable->isState(LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION | LLDrawable::REBUILD_RIGGED);
+
+	bool rigged = false;
+	LLVolume* volume = mRiggedVolume;
+	if (!volume)
+	{
+		volume = getVolume();
+	}
 
 	for (S32 i = 0; i < getVolume()->getNumVolumeFaces(); i++)
 	{
@@ -1364,7 +1374,7 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 		{
 			continue;
 		}
-		res &= face->genVolumeBBoxes(*getVolume(), i,
+		res &= face->genVolumeBBoxes(*volume, i,
 										mRelativeXform, mRelativeXformInvTrans,
 										(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
 		
@@ -1415,7 +1425,21 @@ void LLVOVolume::updateRelativeXform()
 	
 	LLDrawable* drawable = mDrawable;
 	
-	if (drawable->isActive())
+	if (drawable->isState(LLDrawable::RIGGED) && mRiggedVolume.notNull())
+	{ //rigged volume (which is in agent space) is used for generating bounding boxes etc
+	  //inverse of render matrix should go to partition space
+		mRelativeXform = getRenderMatrix();
+
+		F32* dst = (F32*) mRelativeXformInvTrans.mMatrix;
+		F32* src = (F32*) mRelativeXform.mMatrix;
+		dst[0] = src[0]; dst[1] = src[1]; dst[2] = src[2];
+		dst[3] = src[4]; dst[4] = src[5]; dst[5] = src[6];
+		dst[6] = src[8]; dst[7] = src[9]; dst[8] = src[10];
+		
+		mRelativeXform.invert();
+		mRelativeXformInvTrans.transpose();
+	}
+	else if (drawable->isActive())
 	{				
 		// setup relative transforms
 		LLQuaternion delta_rot;
@@ -1497,11 +1521,22 @@ void LLVOVolume::updateRelativeXform()
 
 static LLFastTimer::DeclareTimer FTM_GEN_FLEX("Generate Flexies");
 static LLFastTimer::DeclareTimer FTM_UPDATE_PRIMITIVES("Update Primitives");
+static LLFastTimer::DeclareTimer FTM_UPDATE_RIGGED_VOLUME("Update Rigged");
 
 BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 {
 	LLFastTimer t(FTM_UPDATE_PRIMITIVES);
 	
+	if (mDrawable->isState(LLDrawable::REBUILD_RIGGED))
+	{
+		{
+			LLFastTimer t(FTM_UPDATE_RIGGED_VOLUME);
+			updateRiggedVolume();
+		}
+		genBBoxes(FALSE);
+		mDrawable->clearState(LLDrawable::REBUILD_RIGGED);
+	}
+
 	if (mVolumeImpl != NULL)
 	{
 		BOOL res;
@@ -1597,7 +1632,7 @@ BOOL LLVOVolume::updateGeometry(LLDrawable *drawable)
 	{
 		LLPipeline::sCompiles++;
 	}
-	
+		
 	mVolumeChanged = FALSE;
 	mLODChanged = FALSE;
 	mSculptChanged = FALSE;
@@ -2724,6 +2759,11 @@ BOOL LLVOVolume::isVolumeGlobal() const
 	{
 		return mVolumeImpl->isVolumeGlobal() ? TRUE : FALSE;
 	}
+	else if (mRiggedVolume.notNull())
+	{
+		return TRUE;
+	}
+
 	return FALSE;
 }
 
@@ -3390,12 +3430,37 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 	BOOL ret = FALSE;
 
 	LLVolume* volume = getVolume();
+
+	bool transform = true;
+
+	if (mDrawable->isState(LLDrawable::RIGGED))
+	{
+		if (LLFloater::isVisible(gFloaterTools) && getAvatar()->isSelf())
+		{
+			gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_RIGGED, TRUE);
+			volume = mRiggedVolume;
+			transform = false;
+		}
+		else
+		{ //cannot pick rigged attachments on other avatars or when not in build mode
+			return FALSE;
+		}
+	}
+	
 	if (volume)
 	{	
 		LLVector3 v_start, v_end, v_dir;
 	
-		v_start = agentPositionToVolume(start);
-		v_end = agentPositionToVolume(end);
+		if (transform)
+		{
+			v_start = agentPositionToVolume(start);
+			v_end = agentPositionToVolume(end);
+		}
+		else
+		{
+			v_start = start;
+			v_end = end;
+		}
 		
 		LLVector3 p;
 		LLVector3 n;
@@ -3455,18 +3520,40 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 					
 					if (intersection != NULL)
 					{
-						*intersection = volumePositionToAgent(p);  // must map back to agent space
+						if (transform)
+						{
+							*intersection = volumePositionToAgent(p);  // must map back to agent space
+						}
+						else
+						{
+							*intersection = p;
+						}
 					}
 
 					if (normal != NULL)
 					{
-						*normal = volumeDirectionToAgent(n);
+						if (transform)
+						{
+							*normal = volumeDirectionToAgent(n);
+						}
+						else
+						{
+							*normal = n;
+						}
+
 						(*normal).normVec();
 					}
 
 					if (bi_normal != NULL)
 					{
-						*bi_normal = volumeDirectionToAgent(bn);
+						if (transform)
+						{
+							*bi_normal = volumeDirectionToAgent(bn);
+						}
+						else
+						{
+							*bi_normal = bn;
+						}
 						(*bi_normal).normVec();
 					}
 
@@ -3484,6 +3571,201 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 	return ret;
 }
 
+bool LLVOVolume::treatAsRigged()
+{
+	return LLFloater::isVisible(gFloaterTools) && 
+			isAttachment() && 
+			getAvatar() &&
+			getAvatar()->isSelf() &&
+			mDrawable.notNull() &&
+			mDrawable->isState(LLDrawable::RIGGED);
+}
+
+LLRiggedVolume* LLVOVolume::getRiggedVolume()
+{
+	return mRiggedVolume;
+}
+
+void LLVOVolume::clearRiggedVolume()
+{
+	if (mRiggedVolume.notNull())
+	{
+		mRiggedVolume = NULL;
+		updateRelativeXform();
+	}
+}
+
+void LLVOVolume::updateRiggedVolume()
+{
+	//Update mRiggedVolume to match current animation frame of avatar. 
+	//Also update position/size in octree.  
+
+	if (!treatAsRigged())
+	{
+		clearRiggedVolume();
+		
+		return;
+	}
+
+	LLVolume* volume = getVolume();
+
+	const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(volume->getParams().getSculptID());
+
+	if (!skin)
+	{
+		clearRiggedVolume();
+		return;
+	}
+
+	LLVOAvatar* avatar = getAvatar();
+
+	if (!avatar)
+	{
+		clearRiggedVolume();
+		return;
+	}
+
+	if (!mRiggedVolume)
+	{
+		LLVolumeParams p;
+		mRiggedVolume = new LLRiggedVolume(p);
+		updateRelativeXform();
+	}
+
+	mRiggedVolume->update(skin, avatar, volume);
+
+}
+
+static LLFastTimer::DeclareTimer FTM_SKIN_RIGGED("Skin");
+static LLFastTimer::DeclareTimer FTM_RIGGED_OCTREE("Octree");
+
+void LLRiggedVolume::update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* volume)
+{
+	bool copy = false;
+	if (volume->getNumVolumeFaces() != getNumVolumeFaces())
+	{ 
+		copy = true;
+	}
+
+	for (S32 i = 0; i < volume->getNumVolumeFaces() && !copy; ++i)
+	{
+		const LLVolumeFace& src_face = volume->getVolumeFace(i);
+		const LLVolumeFace& dst_face = getVolumeFace(i);
+
+		if (src_face.mNumIndices != dst_face.mNumIndices ||
+			src_face.mNumVertices != dst_face.mNumVertices)
+		{
+			copy = true;
+		}
+	}
+
+	if (copy)
+	{
+		copyVolumeFaces(volume);	
+	}
+
+	//build matrix palette
+	LLMatrix4a mp[64];
+	LLMatrix4* mat = (LLMatrix4*) mp;
+	
+	for (U32 j = 0; j < skin->mJointNames.size(); ++j)
+	{
+		LLJoint* joint = avatar->getJoint(skin->mJointNames[j]);
+		if (joint)
+		{
+			mat[j] = skin->mInvBindMatrix[j];
+			mat[j] *= joint->getWorldMatrix();
+		}
+	}
+
+	for (S32 i = 0; i < volume->getNumVolumeFaces(); ++i)
+	{
+		const LLVolumeFace& vol_face = volume->getVolumeFace(i);
+		
+		LLVolumeFace& dst_face = mVolumeFaces[i];
+		
+		LLVector4a* weight = vol_face.mWeights;
+
+		LLMatrix4a bind_shape_matrix;
+		bind_shape_matrix.loadu(skin->mBindShapeMatrix);
+
+		LLVector4a* pos = dst_face.mPositions;
+
+		{
+			LLFastTimer t(FTM_SKIN_RIGGED);
+
+			for (U32 j = 0; j < dst_face.mNumVertices; ++j)
+			{
+				LLMatrix4a final_mat;
+				final_mat.clear();
+
+				S32 idx[4];
+
+				LLVector4 wght;
+
+				F32 scale = 0.f;
+				for (U32 k = 0; k < 4; k++)
+				{
+					F32 w = weight[j][k];
+
+					idx[k] = (S32) floorf(w);
+					wght[k] = w - floorf(w);
+					scale += wght[k];
+				}
+
+				wght *= 1.f/scale;
+
+				for (U32 k = 0; k < 4; k++)
+				{
+					F32 w = wght[k];
+
+					LLMatrix4a src;
+					src.setMul(mp[idx[k]], w);
+
+					final_mat.add(src);
+				}
+
+				
+				LLVector4a& v = vol_face.mPositions[j];
+				LLVector4a t;
+				LLVector4a dst;
+				bind_shape_matrix.affineTransform(v, t);
+				final_mat.affineTransform(t, dst);
+				pos[j] = dst;
+			}
+
+			//update bounding box
+			LLVector4a& min = dst_face.mExtents[0];
+			LLVector4a& max = dst_face.mExtents[1];
+
+			min = pos[0];
+			max = pos[1];
+
+			for (U32 j = 1; j < dst_face.mNumVertices; ++j)
+			{
+				min.setMin(min, pos[j]);
+				max.setMax(max, pos[j]);
+			}
+
+			dst_face.mCenter->setAdd(dst_face.mExtents[0], dst_face.mExtents[1]);
+			dst_face.mCenter->mul(0.5f);
+
+		}
+
+		{
+			LLFastTimer t(FTM_RIGGED_OCTREE);
+			delete dst_face.mOctree;
+			dst_face.mOctree = NULL;
+
+			LLVector4a size;
+			size.setSub(dst_face.mExtents[1], dst_face.mExtents[0]);
+			size.splat(size.getLength3().getF32()*0.5f);
+			
+			dst_face.createOctree(1.f);
+		}
+	}
+}
+
 U32 LLVOVolume::getPartitionType() const
 {
 	if (isHUDAttachment())
@@ -3732,6 +4014,8 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 		bool bake_sunlight = LLPipeline::sBakeSunlight && drawablep->isStatic();
 
+		bool is_rigged = false;
+
 		//for each face
 		for (S32 i = 0; i < drawablep->getNumFaces(); i++)
 		{
@@ -3747,8 +4031,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 					facep->mVertexBuffer = NULL;
 					facep->mLastVertexBuffer = NULL;
 				}
-				
+		
 				facep->setState(LLFace::RIGGED);
+				is_rigged = true;
 				
 				//get drawpool of avatar with rigged face
 				LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
@@ -3958,6 +4243,15 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 				facep->mLastVertexBuffer = NULL;
 			}		
 		}
+
+		if (is_rigged)
+		{
+			drawablep->setState(LLDrawable::RIGGED);
+		}
+		else
+		{
+			drawablep->clearState(LLDrawable::RIGGED);
+		}
 	}
 
 	group->mBufferUsage = useage;
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index eeb98726c9f8696fc7394928b50f2e23a7e9f267..f058710a27a11e42c382ba692d29c52de6ecb9d3 100644
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -46,6 +46,8 @@ class LLDrawPool;
 class LLSelectNode;
 class LLObjectMediaDataClient;
 class LLObjectMediaNavigateClient;
+class LLVOAvatar;
+class LLMeshSkinInfo;
 
 typedef std::vector<viewer_media_t> media_list_t;
 
@@ -54,6 +56,18 @@ enum LLVolumeInterfaceType
 	INTERFACE_FLEXIBLE = 1,
 };
 
+
+class LLRiggedVolume : public LLVolume
+{
+public:
+	LLRiggedVolume(const LLVolumeParams& params)
+		: LLVolume(params, 0.f)
+	{
+	}
+
+	void update(const LLMeshSkinInfo* skin, LLVOAvatar* avatar, const LLVolume* src_volume);
+};
+
 // Base class for implementations of the volume - Primitive, Flexible Object, etc.
 class LLVolumeInterface
 {
@@ -289,6 +303,21 @@ public:
 	void removeMDCImpl() { --mMDCImplCount; }
 	S32 getMDCImplCount() { return mMDCImplCount; }
 	
+
+	//rigged volume update (for raycasting)
+	void updateRiggedVolume();
+	LLRiggedVolume* getRiggedVolume();
+
+	//returns true if volume should be treated as a rigged volume
+	// - Build tools are open
+	// - object is an attachment
+	// - object is attached to self
+	// - object is rendered as rigged
+	bool treatAsRigged();
+
+	//clear out rigged volume and revert back to non-rigged state for picking/LOD/distance updates
+	void clearRiggedVolume();
+
 protected:
 	S32	computeLODDetail(F32	distance, F32 radius);
 	BOOL calcLOD();
@@ -322,6 +351,9 @@ private:
 	S32			mLastFetchedMediaVersion; // as fetched from the server, starts as -1
 	S32 mIndexInTex;
 	S32 mMDCImplCount;
+
+	LLPointer<LLRiggedVolume> mRiggedVolume;
+
 	// statics
 public:
 	static F32 sLODSlopDistanceFactor;// Changing this to zero, effectively disables the LOD transition slop 
diff --git a/install.xml b/install.xml
index 18d061e81faa417809dcc160348a5899f64f01a1..e896956c1b93d473baf02a6b1fa818c87ebc80e4 100644
--- a/install.xml
+++ b/install.xml
@@ -630,12 +630,12 @@
           </map>
         </map>
       </map>
-      <key>google-perftools</key>
+      <key>tcmalloc</key>
       <map>
         <key>copyright</key>
         <string>Copyright (c) 2005, Google Inc.</string>
         <key>description</key>
-        <string>Heap performance and validity checking tools from google. Includes TCMalloc, heap-checker, heap-profiler and cpu-profiler.</string>
+        <string>High performance memory allocator.</string>
         <key>license</key>
         <string>bsd</string>
         <key>packages</key>
@@ -643,9 +643,9 @@
           <key>windows</key>
           <map>
             <key>md5sum</key>
-            <string>32dba32ddd460a08e082898ebba6315c</string>
+            <string>8b11a7d3caee8a4ba70da41d6a5ee131</string>
             <key>url</key>
-            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/google-perftools-1.0-windows-20090406.tar.bz2</uri>
+            <uri>http://s3.amazonaws.com/viewer-source-downloads/install_pkgs/tcmalloc-1.6-windows-20100916b.tar.bz2</uri>
           </map>
         </map>
       </map>