diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 949057df04948213197a3d6f42e44cbb7f8ed519..9256e3959cdfa96912b7a9a62f5ce552c70d5f0b 100644
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -124,7 +124,7 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
 	{
 		GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second);
 		LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
-		if (mShaderLevel > 0)
+		if (shaderhandle > 0)
 		{
 			attachObject(shaderhandle);
 		}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
index 44468cdfa296fdcb29ef7f6cca60666a44327127..b45884265724179033113f1da8634b3950881a94 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
@@ -13,7 +13,7 @@ void main()
 	gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; 
 	gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0;
 	
-	vary_normal = normalize(gl_NormalMatrix * gl_Normal);
+	vary_nomral = normalize(gl_NormalMatrix * gl_Normal);
 
 	gl_FrontColor = gl_Color;
 }
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index ae30af3647838d4403cb2764ce0864c4afe36c26..a99b80d6185b2f817254502c2e66a61a3c15718c 100644
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -248,11 +248,6 @@ void LLFacePool::dirtyTextures(const std::set<LLViewerFetchedTexture*>& textures
 {
 }
 
-BOOL LLFacePool::moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data)
-{
-	return TRUE;
-}
-
 // static
 S32 LLFacePool::drawLoop(face_array_t& face_list)
 {
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index 67870c10e93112486dfac9a3d54db09611599ab7..e46d503db32e5a096169a88cf00cde0ba2efb00e 100644
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -187,8 +187,6 @@ class LLFacePool : public LLDrawPool
 	virtual void resetDrawOrders();
 	void resetAll();
 
-	BOOL moveFace(LLFace *face, LLDrawPool *poolp, BOOL copy_data = FALSE);
-
 	void destroy();
 
 	void buildEdges();
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 62226383a4bac125e905d05eb1cac5f912918c51..02c7e3bb6f639be7964d7761ba5046af4d43d724 100644
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -39,13 +39,17 @@
 #include "m3math.h"
 
 #include "lldrawable.h"
+#include "lldrawpoolbump.h"
 #include "llface.h"
+#include "llmeshrepository.h"
 #include "llsky.h"
 #include "llviewercamera.h"
 #include "llviewerregion.h"
 #include "noise.h"
 #include "pipeline.h"
 #include "llviewershadermgr.h"
+#include "llvovolume.h"
+#include "llvolume.h"
 #include "llappviewer.h"
 #include "llrendersphere.h"
 #include "llviewerpartsim.h"
@@ -94,6 +98,8 @@ static BOOL sRenderingSkinned = FALSE;
 S32 normal_channel = -1;
 S32 specular_channel = -1;
 S32 diffuse_channel = -1;
+S32 cube_channel = -1;
+
 
 static LLFastTimer::DeclareTimer FTM_SHADOW_AVATAR("Avatar Shadow");
 
@@ -358,7 +364,7 @@ S32 LLDrawPoolAvatar::getNumPasses()
 	}
 	else if (getVertexShaderLevel() > 0)
 	{
-		return 4;
+		return 5;
 	}
 	else
 	{
@@ -402,7 +408,10 @@ void LLDrawPoolAvatar::beginRenderPass(S32 pass)
 		beginSkinned();
 		break;
 	case 3:
-		beginRigged();
+		beginRiggedSimple();
+		break;
+	case 4:
+		beginRiggedShinySimple();
 		break;
 	}
 }
@@ -429,7 +438,10 @@ void LLDrawPoolAvatar::endRenderPass(S32 pass)
 		endSkinned();
 		break;
 	case 3:
-		endRigged();
+		endRiggedSimple();
+		break;
+	case 4:
+		endRiggedShinySimple();
 		break;
 	}
 }
@@ -616,14 +628,15 @@ void LLDrawPoolAvatar::endSkinned()
 	gGL.getTexUnit(0)->activate();
 }
 
-void LLDrawPoolAvatar::beginRigged()
+void LLDrawPoolAvatar::beginRiggedSimple()
 {
 	sVertexProgram = &gSkinnedObjectSimpleProgram;
+	diffuse_channel = 0;
 	gSkinnedObjectSimpleProgram.bind();
 	LLVertexBuffer::sWeight4Loc = gSkinnedObjectSimpleProgram.getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
 }
 
-void LLDrawPoolAvatar::endRigged()
+void LLDrawPoolAvatar::endRiggedSimple()
 {
 	sVertexProgram = NULL;
 	LLVertexBuffer::unbind();
@@ -631,6 +644,23 @@ void LLDrawPoolAvatar::endRigged()
 	LLVertexBuffer::sWeight4Loc = -1;
 }
 
+void LLDrawPoolAvatar::beginRiggedShinySimple()
+{
+	sVertexProgram = &gSkinnedObjectShinySimpleProgram;
+	sVertexProgram->bind();
+	LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, diffuse_channel, cube_channel, false);
+	LLVertexBuffer::sWeight4Loc = sVertexProgram->getAttribLocation(LLViewerShaderMgr::OBJECT_WEIGHT);
+}
+
+void LLDrawPoolAvatar::endRiggedShinySimple()
+{
+	LLVertexBuffer::unbind();
+	LLDrawPoolBump::unbindCubeMap(sVertexProgram, 2, diffuse_channel, cube_channel, false);
+	sVertexProgram->unbind();
+	sVertexProgram = NULL;
+	LLVertexBuffer::sWeight4Loc = -1;
+}
+
 void LLDrawPoolAvatar::beginDeferredRigged()
 {
 	sVertexProgram = &gDeferredSkinnedDiffuseProgram;
@@ -790,9 +820,16 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 
 	if (pass == 3)
 	{
-		avatarp->renderSkinnedAttachments();
+		renderRiggedSimple(avatarp);
+		return;
+	}
+
+	if (pass == 4)
+	{
+		renderRiggedShinySimple(avatarp);
 		return;
 	}
+
 	
 	if (sShaderLevel > 0)
 	{
@@ -830,13 +867,146 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 	}
 }
 
+void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face, U32 data_mask)
+{
+	LLVertexBuffer* buff = face->mVertexBuffer;
+
+	if (!buff || 
+		!buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) ||
+		buff->getRequestedVerts() != vol_face.mVertices.size())
+	{
+		face->setGeomIndex(0);
+		face->setIndicesIndex(0);
+		face->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
+
+		face->mVertexBuffer = new LLVertexBuffer(data_mask, 0);
+		face->mVertexBuffer->allocateBuffer(vol_face.mVertices.size(), vol_face.mIndices.size(), true);
+
+		U16 offset = 0;
+		
+		LLMatrix4 mat_vert = skin->mBindShapeMatrix;
+		glh::matrix4f m((F32*) mat_vert.mMatrix);
+		m = m.inverse().transpose();
+		
+		F32 mat3[] = 
+		{ m.m[0], m.m[1], m.m[2],
+		  m.m[4], m.m[5], m.m[6],
+		  m.m[8], m.m[9], m.m[10] };
+
+		LLMatrix3 mat_normal(mat3);				
+
+		face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
+		buff = face->mVertexBuffer;
+	}
+}
+
+void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, const U32 data_mask)
+{
+	for (U32 i = 0; i < mRiggedFace[type].size(); ++i)
+	{
+		LLFace* face = mRiggedFace[type][i];
+		LLDrawable* drawable = face->getDrawable();
+		if (!drawable)
+		{
+			continue;
+		}
+
+		LLVOVolume* vobj = drawable->getVOVolume();
+
+		if (!vobj)
+		{
+			continue;
+		}
+
+		LLVolume* volume = vobj->getVolume();
+		S32 te = face->getTEOffset();
+
+		if (!volume || volume->getNumVolumeFaces() <= te)
+		{
+			continue;
+		}
+
+		LLUUID mesh_id = volume->getParams().getSculptID();
+		if (mesh_id.isNull())
+		{
+			continue;
+		}
+
+		const LLMeshSkinInfo* skin = gMeshRepo.getSkinInfo(mesh_id);
+		if (!skin)
+		{
+			continue;
+		}
+
+		const LLVolumeFace& vol_face = volume->getVolumeFace(te);
+		updateRiggedFaceVertexBuffer(face, skin, volume, vol_face, data_mask);
+		
+		LLVertexBuffer* buff = face->mVertexBuffer;
+
+		if (buff)
+		{
+			LLMatrix4 mat[64];
+
+			for (U32 i = 0; i < skin->mJointNames.size(); ++i)
+			{
+				LLJoint* joint = avatar->getJoint(skin->mJointNames[i]);
+				if (joint)
+				{
+					mat[i] = skin->mInvBindMatrix[i];
+					mat[i] *= joint->getWorldMatrix();
+				}
+			}
+			
+			LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette", 
+				skin->mJointNames.size(),
+				FALSE,
+				(GLfloat*) mat[0].mMatrix);
+			LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette[0]", 
+				skin->mJointNames.size(),
+				FALSE,
+				(GLfloat*) mat[0].mMatrix);
+
+			buff->setBuffer(data_mask);
+
+			U16 start = face->getGeomStart();
+			U16 end = start + face->getGeomCount()-1;
+			S32 offset = face->getIndicesStart();
+			U32 count = face->getIndicesCount();
+
+			gGL.getTexUnit(0)->bind(face->getTexture());
+			buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);		
+		}
+	}
+}
+
+void LLDrawPoolAvatar::renderRiggedSimple(LLVOAvatar* avatar)
+{
+	const U32 data_mask =	LLVertexBuffer::MAP_VERTEX | 
+							LLVertexBuffer::MAP_NORMAL | 
+							LLVertexBuffer::MAP_TEXCOORD0 |
+							LLVertexBuffer::MAP_COLOR |
+							LLVertexBuffer::MAP_WEIGHT4;
+
+	renderRigged(avatar, RIGGED_SIMPLE, data_mask);
+}
+
+	
+void LLDrawPoolAvatar::renderRiggedShinySimple(LLVOAvatar* avatar)
+{
+	const U32 data_mask =	LLVertexBuffer::MAP_VERTEX | 
+							LLVertexBuffer::MAP_NORMAL | 
+							LLVertexBuffer::MAP_TEXCOORD0 |
+							LLVertexBuffer::MAP_COLOR |
+							LLVertexBuffer::MAP_WEIGHT4;
+
+	renderRigged(avatar, RIGGED_SHINY_SIMPLE, data_mask);
+}
+
 //-----------------------------------------------------------------------------
 // renderForSelect()
 //-----------------------------------------------------------------------------
 void LLDrawPoolAvatar::renderForSelect()
 {
-
-
 	if (mDrawFace.empty())
 	{
 		return;
@@ -930,6 +1100,64 @@ LLColor3 LLDrawPoolAvatar::getDebugColor() const
 	return LLColor3(0.f, 1.f, 0.f);
 }
 
+void LLDrawPoolAvatar::addRiggedFace(LLFace* facep, U32 type)
+{
+	if (facep->getReferenceIndex() != -1)
+	{
+		llerrs << "Tried to add a rigged face that's referenced elsewhere." << llendl;
+	}	
+
+	if (type >= NUM_RIGGED_PASSES)
+	{
+		llerrs << "Invalid rigged face type." << llendl;
+	}
+
+	facep->setReferenceIndex(mRiggedFace[type].size());
+	facep->mDrawPoolp = this;
+	mRiggedFace[type].push_back(facep);
+}
+
+void LLDrawPoolAvatar::removeRiggedFace(LLFace* facep, U32 type)
+{
+	S32 index = facep->getReferenceIndex();
+	if (index == -1)
+	{
+		llerrs << "Tried to remove rigged face with invalid index." << llendl;
+	}
+
+	if (type > RIGGED_UNKNOWN)
+	{
+		llerrs << "Invalid rigged face type." << llendl;
+	}
+
+	facep->setReferenceIndex(-1);
+	facep->mDrawPoolp = NULL;
+
+	if (type == RIGGED_UNKNOWN)
+	{
+		for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
+		{
+			if (mRiggedFace[i].size() > index && mRiggedFace[i][index] == facep)
+			{
+				type = i;
+				break;
+			}
+		}
+	}
+
+	if (type >= NUM_RIGGED_PASSES)
+	{
+		llerrs << "Could not find face for removal from current drawpool." << llendl;
+	}
+
+	mRiggedFace[type].erase(mRiggedFace[type].begin()+index);
+
+	for (S32 i = index; i < mRiggedFace[type].size(); ++i)
+	{ //bump indexes of currently held faces down after removal
+		mRiggedFace[type][i]->setReferenceIndex(i);
+	}
+}
+
 LLVertexBufferAvatar::LLVertexBufferAvatar()
 : LLVertexBuffer(sDataMask, 
 	GL_STREAM_DRAW_ARB) //avatars are always stream draw due to morph targets
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index b42cc54622c21feb60b0425f1392f7fced2e0d68..0ebb035f2a42d2fb730666cd532c5790f2d70fa4 100644
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -37,6 +37,11 @@
 
 class LLVOAvatar;
 class LLGLSLShader;
+class LLFace;
+class LLMeshSkinInfo;
+class LLVolume;
+class LLVolumeFace;
+
 
 class LLDrawPoolAvatar : public LLFacePool
 {
@@ -91,12 +96,14 @@ class LLDrawPoolAvatar : public LLFacePool
 	void beginRigid();
 	void beginImpostor();
 	void beginSkinned();
-	void beginRigged();
-		
+	void beginRiggedSimple();
+	void beginRiggedShinySimple();
+
 	void endRigid();
 	void endImpostor();
 	void endSkinned();
-	void endRigged();
+	void endRiggedSimple();
+	void endRiggedShinySimple();
 
 	void beginDeferredImpostor();
 	void beginDeferredRigid();
@@ -108,11 +115,40 @@ class LLDrawPoolAvatar : public LLFacePool
 	void endDeferredSkinned();
 	void endDeferredRigged();
 		
+	void updateRiggedFaceVertexBuffer(LLFace* facep, 
+									  const LLMeshSkinInfo* skin, 
+									  LLVolume* volume,
+									  const LLVolumeFace& vol_face, 
+									  U32 data_mask);
+
+	void renderRigged(LLVOAvatar* avatar, U32 type, const U32 data_mask);
+	void renderRiggedSimple(LLVOAvatar* avatar);
+	void renderRiggedShinySimple(LLVOAvatar* avatar);
+
 	/*virtual*/ LLViewerTexture *getDebugTexture();
 	/*virtual*/ LLColor3 getDebugColor() const; // For AGP debug display
 
 	void renderAvatars(LLVOAvatar *single_avatar, S32 pass = -1); // renders only one avatar if single_avatar is not null.
 
+	typedef enum
+	{
+		RIGGED_SIMPLE = 0,
+		RIGGED_SHINY_SIMPLE,
+		RIGGED_SHINY_FULLBRIGHT,
+		RIGGED_SHINY_BUMP,
+		RIGGED_BUMP,
+		RIGGED_FULLBRIGHT,
+		RIGGED_ALPHA,
+		NUM_RIGGED_PASSES,
+		RIGGED_UNKNOWN,
+	} eRiggedPass;
+
+	
+	void addRiggedFace(LLFace* facep, U32 type);
+	void removeRiggedFace(LLFace* facep, U32 type = RIGGED_UNKNOWN); 
+
+	std::vector<LLFace*> mRiggedFace[NUM_RIGGED_PASSES];
+
 	static BOOL sSkipOpaque;
 	static BOOL sSkipTransparent;
 	static LLGLSLShader* sVertexProgram;
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index 8f3e775976cf4b3550fa285ca8b7dd0c5b879ca1..2f449fa42f5c6523a44605c3d00044bfd371c3f3 100644
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -323,30 +323,43 @@ void LLDrawPoolBump::beginShiny(bool invisible)
 		sVertexMask = VERTEX_MASK_SHINY | LLVertexBuffer::MAP_TEXCOORD0;
 	}
 	
-	if (LLPipeline::sUnderWaterRender)
+	if (getVertexShaderLevel() > 0)
 	{
-		shader = &gObjectShinyWaterProgram;
+		if (LLPipeline::sUnderWaterRender)
+		{
+			shader = &gObjectShinyWaterProgram;
+		}
+		else
+		{
+			shader = &gObjectShinyProgram;
+		}
+		shader->bind();
 	}
 	else
 	{
-		shader = &gObjectShinyProgram;
+		shader = NULL;
 	}
 
+	bindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible);
+}
+
+//static
+void LLDrawPoolBump::bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
+{
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
-		if (!invisible && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0 )
+		if (!invisible && shader )
 		{
 			LLMatrix4 mat;
 			mat.initRows(LLVector4(gGLModelView+0),
 						 LLVector4(gGLModelView+4),
 						 LLVector4(gGLModelView+8),
 						 LLVector4(gGLModelView+12));
-			shader->bind();
 			LLVector3 vec = LLVector3(gShinyOrigin) * mat;
 			LLVector4 vec4(vec, gShinyOrigin.mV[3]);
 			shader->uniform4fv(LLViewerShaderMgr::SHINY_ORIGIN, 1, vec4.mV);			
-			if (mVertexShaderLevel > 1)
+			if (shader_level > 1)
 			{
 				cube_map->setMatrix(1);
 				// Make sure that texture coord generation happens for tex unit 1, as that's the one we use for 
@@ -408,22 +421,16 @@ void LLDrawPoolBump::renderShiny(bool invisible)
 	}
 }
 
-void LLDrawPoolBump::endShiny(bool invisible)
+//static
+void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible)
 {
-	LLFastTimer t(FTM_RENDER_SHINY);
-	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
-		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
-	{
-		return;
-	}
-
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
 		cube_map->disable();
 		cube_map->restoreMatrix();
 
-		if (!invisible && mVertexShaderLevel > 1)
+		if (!invisible && shader_level > 1)
 		{
 			shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
 					
@@ -434,7 +441,6 @@ void LLDrawPoolBump::endShiny(bool invisible)
 					shader->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 				}
 			}
-			shader->unbind();
 		}
 	}
 	gGL.getTexUnit(diffuse_channel)->disable();
@@ -442,6 +448,22 @@ void LLDrawPoolBump::endShiny(bool invisible)
 
 	gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+}
+
+void LLDrawPoolBump::endShiny(bool invisible)
+{
+	LLFastTimer t(FTM_RENDER_SHINY);
+	if ((!invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_SHINY))|| 
+		(invisible && !gPipeline.hasRenderBatches(LLRenderPass::PASS_INVISI_SHINY)))
+	{
+		return;
+	}
+
+	unbindCubeMap(shader, mVertexShaderLevel, diffuse_channel, cube_channel, invisible);
+	if (shader)
+	{
+		shader->unbind();
+	}
 
 	diffuse_channel = -1;
 	cube_channel = 0;
diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h
index 2019f1df2698c45a7ef014363c14a0f129cdd94f..89bbefe7785670ff4309a0218c61ee92669ca3bc 100644
--- a/indra/newview/lldrawpoolbump.h
+++ b/indra/newview/lldrawpoolbump.h
@@ -41,6 +41,7 @@
 class LLImageRaw;
 class LLSpatialGroup;
 class LLDrawInfo;
+class LLGLSLShader;
 class LLViewerFetchedTexture;
 
 class LLDrawPoolBump : public LLRenderPass
@@ -79,6 +80,9 @@ protected :
 	void renderBump();
 	void endBump();
 
+	static void bindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
+	static void unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32& diffuse_channel, S32& cube_channel, bool invisible);
+
 	virtual S32 getNumDeferredPasses();
 	/*virtual*/ void beginDeferredPass(S32 pass);
 	/*virtual*/ void endDeferredPass(S32 pass);
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 7866e49bae4b779762464d7ca9d867a146a4f8a5..0e0b8447caff81a3da49e3c7f878e6fa61e11379 100644
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -205,7 +205,12 @@ void LLFace::destroy()
 	if (mDrawPoolp)
 	{
 		LLFastTimer t(FTM_DESTROY_DRAWPOOL);
+
+		if (this->isState(LLFace::RIGGED) && mDrawPoolp->getType() == LLDrawPool::POOL_AVATAR)
 		mDrawPoolp->removeFace(this);
+
+		
+		
 		mDrawPoolp = NULL;
 	}
 
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index bbf8de04bc98047cbced42b3d6906d67276de39b..2b8fdf2e5827f5841e7c68fdd9401a78c427f905 100644
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -234,6 +234,7 @@ class LLFace
 private:
 	friend class LLGeometryManager;
 	friend class LLVolumeGeometryManager;
+	friend class LLDrawPoolAvatar;
 
 	U32			mState;
 	LLFacePool*	mDrawPoolp;
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 6bd3ceb8a85bcc9e5677808e61de19cbf8e3e896..3aecd0175d28c489563636b5d78a7fe32f84f220 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -5219,6 +5219,25 @@ void LLViewerObject::resetChildrenPosition(const LLVector3& offset, BOOL simplif
 	return ;
 }
 
+//virtual
+LLVOAvatar* LLViewerObject::getAvatar() const
+{
+	if (isAttachment())
+	{
+		LLViewerObject* vobj = (LLViewerObject*) getParent();
+
+		while (vobj && !vobj->asAvatar())
+		{
+			vobj = (LLViewerObject*) vobj->getParent();
+		}
+
+		return (LLVOAvatar*) vobj;
+	}
+
+	return NULL;
+}
+
+
 class ObjectPhysicsProperties : public LLHTTPNode
 {
 public:
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 594d7a0827882a4f81e2c9c817fbdd54611426af..0fd0cbfa604af97f86e4a5c7f81949118ed9bd38 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -181,6 +181,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	void			setOnActiveList(BOOL on_active)		{ mOnActiveList = on_active; }
 
 	virtual BOOL	isAttachment() const { return FALSE; }
+	virtual LLVOAvatar* getAvatar() const;  //get the avatar this object is attached to, or NULL if object is not an attachment
 	virtual BOOL	isHUDAttachment() const { return FALSE; }
 	virtual void 	updateRadius() {};
 	virtual F32 	getVObjRadius() const; // default implemenation is mDrawable->getRadius()
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index d978e856a609c3da57e6078957f0251ce62d436b..fe68d6eaa4cc2854ff2bf685f10c94906f3bdaa8 100644
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -79,6 +79,7 @@ LLGLSLShader		gObjectShinyWaterProgram;
 
 //object hardware skinning shaders
 LLGLSLShader		gSkinnedObjectSimpleProgram;
+LLGLSLShader		gSkinnedObjectShinySimpleProgram;
 
 //environment shaders
 LLGLSLShader		gTerrainProgram;
@@ -154,6 +155,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gObjectFullbrightProgram);
 	mShaderList.push_back(&gObjectFullbrightShinyProgram);
 	mShaderList.push_back(&gSkinnedObjectSimpleProgram);
+	mShaderList.push_back(&gSkinnedObjectShinySimpleProgram);
 	mShaderList.push_back(&gTerrainProgram);
 	mShaderList.push_back(&gTerrainWaterProgram);
 	mShaderList.push_back(&gObjectSimpleWaterProgram);
@@ -505,6 +507,9 @@ void LLViewerShaderMgr::setShaders()
 			if (!loadShadersDeferred())
 			{
 				gSavedSettings.setBOOL("RenderDeferred", FALSE);
+				reentrance = false;
+				setShaders();
+				return;
 			}
 #endif
 		}
@@ -557,6 +562,8 @@ void LLViewerShaderMgr::unloadShaders()
 	gObjectShinyWaterProgram.unload();
 
 	gSkinnedObjectSimpleProgram.unload();
+	gSkinnedObjectShinySimpleProgram.unload();
+	
 
 	gWaterProgram.unload();
 	gUnderWaterProgram.unload();
@@ -917,7 +924,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredGIProgram.unload();
 		gDeferredGIFinalProgram.unload();
 		gDeferredWaterProgram.unload();
-		return FALSE;
+		return TRUE;
 	}
 
 	mVertexShaderLevel[SHADER_AVATAR] = 1;
@@ -1251,6 +1258,8 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightProgram.unload();
 		gObjectFullbrightWaterProgram.unload();
 		gSkinnedObjectSimpleProgram.unload();
+		gSkinnedObjectShinySimpleProgram.unload();
+	
 		return FALSE;
 	}
 
@@ -1376,6 +1385,22 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gSkinnedObjectSimpleProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gSkinnedObjectShinySimpleProgram.mName = "Skinned Shiny Simple Shader";
+		gSkinnedObjectShinySimpleProgram.mFeatures.calculatesLighting = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.calculatesAtmospherics = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.hasGamma = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true;
+		gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true;
+		gSkinnedObjectShinySimpleProgram.mShaderFiles.clear();
+		gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinySimpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gSkinnedObjectShinySimpleProgram.mShaderFiles.push_back(make_pair("objects/shinyF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gSkinnedObjectShinySimpleProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gSkinnedObjectShinySimpleProgram.createShader(NULL, &mShinyUniforms);
+	}
+
 	if( !success )
 	{
 		mVertexShaderLevel[SHADER_OBJECT] = 0;
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index b279a59777b2c49b89509396a9096083ad8e1245..beac5462e2d91ee0ab856ce903ba398b6f180716 100644
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -315,6 +315,7 @@ extern LLGLSLShader			gObjectShinyProgram;
 extern LLGLSLShader			gObjectShinyWaterProgram;
 
 extern LLGLSLShader			gSkinnedObjectSimpleProgram;
+extern LLGLSLShader			gSkinnedObjectShinySimpleProgram;
 
 //environment shaders
 extern LLGLSLShader			gTerrainProgram;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 7cdbebf4d1c3356007162a25a064d1a843e2340c..c51a7d9cbb751473915e621502662cc562857757 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -3642,7 +3642,7 @@ bool LLVOAvatar::shouldAlphaMask()
 
 U32 LLVOAvatar::renderSkinnedAttachments()
 {
-	U32 num_indices = 0;
+	/*U32 num_indices = 0;
 	
 	const U32 data_mask =	LLVertexBuffer::MAP_VERTEX | 
 							LLVertexBuffer::MAP_NORMAL | 
@@ -3670,107 +3670,14 @@ U32 LLVOAvatar::renderSkinnedAttachments()
 						LLFace* face = drawable->getFace(i);
 						if (face->isState(LLFace::RIGGED))
 						{
-							LLVolume* volume = attached_object->getVolume();
-							if (!volume || volume->getNumVolumeFaces() <= i)
-							{
-								continue;
-							}
-
-							const LLVolumeFace& vol_face = volume->getVolumeFace(i);
-
-							const LLMeshSkinInfo* skin = NULL;
-							LLVertexBuffer* buff = face->mVertexBuffer;
-							LLUUID mesh_id = volume->getParams().getSculptID();;
-
-							if (!buff || 
-								!buff->hasDataType(LLVertexBuffer::TYPE_WEIGHT4) ||
-								buff->getRequestedVerts() != vol_face.mVertices.size())
-							{
-								face->mVertexBuffer = NULL;
-								face->mLastVertexBuffer = NULL;
-								buff = NULL;
-
-								if (mesh_id.notNull())
-								{
-									skin = gMeshRepo.getSkinInfo(mesh_id);
-									if (skin)
-									{
-										face->mVertexBuffer = new LLVertexBuffer(data_mask, 0);
-										face->mVertexBuffer->allocateBuffer(vol_face.mVertices.size(), vol_face.mIndices.size(), true);
-
-										face->setGeomIndex(0);
-										face->setIndicesIndex(0);
-										face->setSize(vol_face.mVertices.size(), vol_face.mIndices.size());
-
-										U16 offset = 0;
-										
-										LLMatrix4 mat_vert = skin->mBindShapeMatrix;
-										glh::matrix4f m((F32*) mat_vert.mMatrix);
-										m = m.inverse().transpose();
-										
-										F32 mat3[] = 
-										{ m.m[0], m.m[1], m.m[2],
-										  m.m[4], m.m[5], m.m[6],
-										  m.m[8], m.m[9], m.m[10] };
-
-										LLMatrix3 mat_normal(mat3);				
-
-										face->getGeometryVolume(*volume, i, mat_vert, mat_normal, offset, true);
-										buff = face->mVertexBuffer;
-									}
-								}
-							}								
 							
-							if (buff && mesh_id.notNull())
-							{
-								if (!skin)
-								{
-									skin = gMeshRepo.getSkinInfo(mesh_id);
-								}
-
-								if (skin)
-								{
-									LLMatrix4 mat[64];
-
-									for (U32 i = 0; i < skin->mJointNames.size(); ++i)
-									{
-										LLJoint* joint = getJoint(skin->mJointNames[i]);
-										if (joint)
-										{
-											mat[i] = skin->mInvBindMatrix[i];
-											mat[i] *= joint->getWorldMatrix();
-										}
-									}
-									
-									LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette", 
-										skin->mJointNames.size(),
-										FALSE,
-										(GLfloat*) mat[0].mMatrix);
-									LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette[0]", 
-										skin->mJointNames.size(),
-										FALSE,
-										(GLfloat*) mat[0].mMatrix);
-
-									buff->setBuffer(data_mask);
-
-									U16 start = face->getGeomStart();
-									U16 end = start + face->getGeomCount()-1;
-									S32 offset = face->getIndicesStart();
-									U32 count = face->getIndicesCount();
-
-									gGL.getTexUnit(0)->bind(face->getTexture());
-									buff->drawRange(LLRender::TRIANGLES, start, end, count, offset);
-									
-								}
-							}
-						}
-					}
 				}
 			}
 		}
 	}
 
-	return num_indices;
+	return num_indices;*/
+	return 0;
 }
 
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 96f69b36761c1bca489636a6cbe5a31ab4c55bc0..e49b33bd80d4504c9d18eaf7eeb65675fe132b5e 100644
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -52,6 +52,7 @@
 #include "object_flags.h"
 #include "llagentconstants.h"
 #include "lldrawable.h"
+#include "lldrawpoolavatar.h"
 #include "lldrawpoolbump.h"
 #include "llface.h"
 #include "llspatialpartition.h"
@@ -73,6 +74,8 @@
 #include "llmeshrepository.h"
 #include "llagent.h"
 #include "llviewermediafocus.h"
+#include "llvoavatar.h"
+
 
 const S32 MIN_QUIET_FRAMES_COALESCE = 30;
 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -3415,6 +3418,33 @@ void LLVolumeGeometryManager::getGeometry(LLSpatialGroup* group)
 static LLFastTimer::DeclareTimer FTM_REBUILD_VOLUME_VB("Volume");
 static LLFastTimer::DeclareTimer FTM_REBUILD_VBO("VBO Rebuilt");
 
+LLDrawPoolAvatar* get_avatar_drawpool(LLViewerObject* vobj)
+{
+	LLVOAvatar* avatar = vobj->getAvatar();
+					
+	if (avatar)
+	{
+		LLDrawable* drawable = avatar->mDrawable;
+		if (drawable && drawable->getNumFaces() > 0)
+		{
+			LLFace* face = drawable->getFace(0);
+			if (face)
+			{
+				LLDrawPool* drawpool = face->getPool();
+				if (drawpool)
+				{
+					if (drawpool->getType() == LLDrawPool::POOL_AVATAR)
+					{
+						return (LLDrawPoolAvatar*) drawpool;
+					}
+				}
+			}
+		}
+	}
+
+	return NULL;
+}
+		
 
 void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 {
@@ -3499,13 +3529,47 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 					facep->mVertexBuffer = NULL;
 					facep->mLastVertexBuffer = NULL;
 					facep->setState(LLFace::RIGGED);
+					
+					//get drawpool of avatar with rigged face
+					LLDrawPoolAvatar* pool = get_avatar_drawpool(vobj);
+					
+					if (pool)
+					{
+						const LLTextureEntry* te = facep->getTextureEntry();
+
+						//remove face from old pool if it exists
+						LLDrawPool* old_pool = facep->getPool();
+						if (old_pool && old_pool->getType() == LLDrawPool::POOL_AVATAR)
+						{
+							((LLDrawPoolAvatar*) old_pool)->removeRiggedFace(facep);
+						}
+
+						//add face to new pool
+						if (te->getShiny())
+						{
+							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY_SIMPLE);
+						}
+						else
+						{
+							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+						}
+					}
+
 				}
 
 				continue;
 			}
 			else
 			{
-				facep->clearState(LLFace::RIGGED);
+				if (facep->isState(LLFace::RIGGED))
+				{ //face is not rigged but used to be, remove from rigged face pool
+					LLDrawPoolAvatar* pool = (LLDrawPoolAvatar*) facep->getPool();
+					if (pool)
+					{
+						pool->removeRiggedFace(facep);
+					}
+					facep->clearState(LLFace::RIGGED);
+				}
 			}
 
 			if (cur_total > max_total || facep->getIndicesCount() <= 0 || facep->getGeomCount() <= 0)