diff --git a/indra/newview/lltexlayer.cpp b/indra/newview/lltexlayer.cpp
index 1feb987682fb7609fcbba34bd3e9075122c031dc..d8b9bc2329f02447f9bc90ccf2d387c78357b544 100644
--- a/indra/newview/lltexlayer.cpp
+++ b/indra/newview/lltexlayer.cpp
@@ -581,6 +581,10 @@ void LLTexLayerSetBuffer::doUpdate()
 	}
 
 	restartUpdateTimer();
+
+	// need to swtich to using this layerset if this is the first update
+	// after getting the lowest LOD
+	mTexLayerSet->getAvatar()->updateMeshTextures();
 	
 	// Print out notification that we uploaded this texture.
 	if (gSavedSettings.getBOOL("DebugAvatarRezTime"))
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 6392aad2488fde55a9320a9c80a458a5567ebc38..c688338000901e5a9d84c9ef9bac054f93200a89 100644
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -702,8 +702,10 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 		mBakedTextureDatas[i].mTextureIndex = LLVOAvatarDictionary::bakedToLocalTextureIndex((EBakedTextureIndex)i);
 	}
 
-	mDirtyMesh = 2;	// Dirty geometry, need to regenerate.
+	mDirtyMesh = TRUE;	// Dirty geometry, need to regenerate.
 	mMeshTexturesDirty = FALSE;
+	mShadow0Facep = NULL;
+	mShadow1Facep = NULL;
 	mHeadp = NULL;
 
 	mIsBuilt = FALSE;
@@ -739,6 +741,12 @@ LLVOAvatar::LLVOAvatar(const LLUUID& id,
 
 	mRippleTimeLast = 0.f;
 
+	mShadowImagep = LLViewerTextureManager::getFetchedTextureFromFile("foot_shadow.j2c");
+	
+	// GL NOT ACTIVE HERE
+	//gGL.getTexUnit(0)->bind(mShadowImagep.get());
+	//mShadowImagep->setAddressMode(LLTexUnit::TAM_CLAMP);
+	
 	mInAir = FALSE;
 
 	mStepOnLand = TRUE;
@@ -1967,7 +1975,7 @@ void LLVOAvatar::updateMeshData()
 			}
 			if(num_vertices < 1)//skip empty meshes
 			{
-				continue ;
+				break ;
 			}
 			if(last_v_num > 0)//put the last inserted part into next vertex buffer.
 			{
@@ -1989,8 +1997,6 @@ void LLVOAvatar::updateMeshData()
 			// resize immediately
 			facep->setSize(num_vertices, num_indices);
 
-			bool terse_update = false;
-
 			if(facep->mVertexBuffer.isNull())
 			{
 				facep->mVertexBuffer = new LLVertexBufferAvatar();
@@ -1998,16 +2004,8 @@ void LLVOAvatar::updateMeshData()
 			}
 			else
 			{
-				if (facep->mVertexBuffer->getRequestedIndices() == num_indices &&
-					facep->mVertexBuffer->getRequestedVerts() == num_vertices)
-				{
-					terse_update = true;
-				}
-				else
-				{
 				facep->mVertexBuffer->resizeBuffer(num_vertices, num_indices) ;
 			}
-			}
 		
 			facep->setGeomIndex(0);
 			facep->setIndicesIndex(0);
@@ -2021,7 +2019,7 @@ void LLVOAvatar::updateMeshData()
 
 			for(S32 k = j ; k < part_index ; k++)
 			{
-				mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR, terse_update);
+				mMeshLOD[k]->updateFaceData(facep, mAdjustedPixelArea, k == MESH_ID_HAIR);
 			}
 
 			stop_glerror();
@@ -2431,6 +2429,12 @@ void LLVOAvatar::idleUpdateMisc(bool detailed_update)
 	LLJoint::sNumUpdates = 0;
 	LLJoint::sNumTouches = 0;
 
+	// *NOTE: this is necessary for the floating name text above your head.
+	if (mDrawable.notNull())
+	{
+		gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_SHADOW, TRUE);
+	}
+
 	BOOL visible = isVisible() || mNeedsAnimUpdate;
 
 	// update attachments positions
@@ -3783,20 +3787,13 @@ U32 LLVOAvatar::renderSkinned(EAvatarRenderPass pass)
 		return num_indices;
 	}
 
-	LLFace* face = mDrawable->getFace(0);
-
-	bool needs_rebuild = !face || face->mVertexBuffer.isNull() || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY);
-
-	if (needs_rebuild || mDirtyMesh)
+	if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY))
 	{	//LOD changed or new mesh created, allocate new vertex buffer if needed
-		if (needs_rebuild || mDirtyMesh >= 2 || mVisibilityRank <= 4)
-		{
 		updateMeshData();
-			mDirtyMesh = 0;
+		mDirtyMesh = FALSE;
 		mNeedsSkin = TRUE;
 		mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
 	}
-	}
 
 	if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) <= 0)
 	{
@@ -4043,6 +4040,54 @@ U32 LLVOAvatar::renderRigid()
 	return num_indices;
 }
 
+U32 LLVOAvatar::renderFootShadows()
+{
+	U32 num_indices = 0;
+
+	if (!mIsBuilt)
+	{
+		return 0;
+	}
+
+	if (isSelf() && (!gAgent.needsRenderAvatar() || !gAgent.needsRenderHead()))
+	{
+		return 0;
+	}
+	
+	if (!mIsBuilt)
+	{
+		return 0;
+	}
+	
+	// Don't render foot shadows if your lower body is completely invisible.
+	// (non-humanoid avatars rule!)
+	if (!isTextureVisible(TEX_LOWER_BAKED))
+	{
+		return 0;
+	}
+
+	// Update the shadow, tractor, and text label geometry.
+	if (mDrawable->isState(LLDrawable::REBUILD_SHADOW) && !isImpostor())
+	{
+		updateShadowFaces();
+		mDrawable->clearState(LLDrawable::REBUILD_SHADOW);
+	}
+
+	U32 foot_mask = LLVertexBuffer::MAP_VERTEX |
+					LLVertexBuffer::MAP_TEXCOORD0;
+
+	LLGLDepthTest test(GL_TRUE, GL_FALSE);
+	//render foot shadows
+	LLGLEnable blend(GL_BLEND);
+	gGL.getTexUnit(0)->bind(mShadowImagep, TRUE);
+	glColor4fv(mShadow0Facep->getRenderColor().mV);
+	mShadow0Facep->renderIndexed(foot_mask);
+	glColor4fv(mShadow1Facep->getRenderColor().mV);
+	mShadow1Facep->renderIndexed(foot_mask);
+	
+	return num_indices;
+}
+
 U32 LLVOAvatar::renderImpostor(LLColor4U color, S32 diffuse_channel)
 {
 	if (!mImpostor.isComplete())
@@ -4168,6 +4213,11 @@ void LLVOAvatar::updateTextures()
 	{
 		setDebugText(llformat("%4.0f:%4.0f", fsqrtf(mMinPixelArea),fsqrtf(mMaxPixelArea)));
 	}	
+	
+	if( render_avatar )
+	{
+		mShadowImagep->addTextureStats(mPixelArea);
+	}
 }
 
 
@@ -5434,7 +5484,7 @@ BOOL LLVOAvatar::updateJointLODs()
  		if (res)
 		{
 			sNumLODChangesThisFrame++;
-			dirtyMesh(2);
+			dirtyMesh();
 			return TRUE;
 		}
 	}
@@ -5458,9 +5508,18 @@ LLDrawable *LLVOAvatar::createDrawable(LLPipeline *pipeline)
 	mDrawable->addFace(poolp, NULL);
 	mDrawable->setRenderType(LLPipeline::RENDER_TYPE_AVATAR);
 	
+	LLFace *facep;
+
+	// Add faces for the foot shadows
+	facep = mDrawable->addFace((LLFacePool*) NULL, mShadowImagep);
+	mShadow0Facep = facep;
+
+	facep = mDrawable->addFace((LLFacePool*) NULL, mShadowImagep);
+	mShadow1Facep = facep;
+
 	mNumInitFaces = mDrawable->getNumFaces() ;
 
-	dirtyMesh(2);
+	dirtyMesh();
 	return mDrawable;
 }
 
@@ -5499,6 +5558,107 @@ BOOL LLVOAvatar::updateGeometry(LLDrawable *drawable)
 	return TRUE;
 }
 
+//-----------------------------------------------------------------------------
+// updateShadowFaces()
+//-----------------------------------------------------------------------------
+void LLVOAvatar::updateShadowFaces()
+{
+	LLFace *face0p = mShadow0Facep;
+	LLFace *face1p = mShadow1Facep;
+
+	//
+	// render avatar shadows
+	//
+	if (mInAir || mUpdatePeriod >= IMPOSTOR_PERIOD)
+	{
+		face0p->setSize(0, 0);
+		face1p->setSize(0, 0);
+		return;
+	}
+
+	LLSprite sprite(mShadowImagep.notNull() ? mShadowImagep->getID() : LLUUID::null);
+	sprite.setFollow(FALSE);
+	const F32 cos_angle = gSky.getSunDirection().mV[2];
+	F32 cos_elev = sqrt(1 - cos_angle * cos_angle);
+	if (cos_angle < 0) cos_elev = -cos_elev;
+	sprite.setSize(0.4f + cos_elev * 0.8f, 0.3f);
+	LLVector3 sun_vec = gSky.mVOSkyp ? gSky.mVOSkyp->getToSun() : LLVector3(0.f, 0.f, 0.f);
+
+	if (mShadowImagep->hasGLTexture())
+	{
+		LLVector3 normal;
+		LLVector3d shadow_pos;
+		LLVector3 shadow_pos_agent;
+		F32 foot_height;
+
+		if (mFootLeftp)
+		{
+			LLVector3 joint_world_pos = mFootLeftp->getWorldPosition();
+			// this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now
+			// but we make an explicit ray trace call in expectation of future improvements
+			resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos), 
+									 gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal);
+			shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos);
+			foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ];
+
+			// Pull sprite in direction of surface normal
+			shadow_pos_agent += normal * SHADOW_OFFSET_AMT;
+
+			// Render sprite
+			sprite.setNormal(normal);
+			if (isSelf() && gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
+			{
+				sprite.setColor(0.f, 0.f, 0.f, 0.f);
+			}
+			else
+			{
+				sprite.setColor(0.f, 0.f, 0.f, clamp_rescale(foot_height, MIN_SHADOW_HEIGHT, MAX_SHADOW_HEIGHT, 0.5f, 0.f));
+			}
+			sprite.setPosition(shadow_pos_agent);
+
+			LLVector3 foot_to_knee = mKneeLeftp->getWorldPosition() - joint_world_pos;
+			//foot_to_knee.normalize();
+			foot_to_knee -= projected_vec(foot_to_knee, sun_vec);
+			sprite.setYaw(azimuth(sun_vec - foot_to_knee));
+		
+			sprite.updateFace(*face0p);
+		}
+
+		if (mFootRightp)
+		{
+			LLVector3 joint_world_pos = mFootRightp->getWorldPosition();
+			// this only does a ray straight down from the foot, as our client-side ray-tracing is very limited now
+			// but we make an explicit ray trace call in expectation of future improvements
+			resolveRayCollisionAgent(gAgent.getPosGlobalFromAgent(joint_world_pos), 
+									 gAgent.getPosGlobalFromAgent(gSky.getSunDirection() + joint_world_pos), shadow_pos, normal);
+			shadow_pos_agent = gAgent.getPosAgentFromGlobal(shadow_pos);
+			foot_height = joint_world_pos.mV[VZ] - shadow_pos_agent.mV[VZ];
+
+			// Pull sprite in direction of surface normal
+			shadow_pos_agent += normal * SHADOW_OFFSET_AMT;
+
+			// Render sprite
+			sprite.setNormal(normal);
+			if (isSelf() && gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
+			{
+				sprite.setColor(0.f, 0.f, 0.f, 0.f);
+			}
+			else
+			{
+				sprite.setColor(0.f, 0.f, 0.f, clamp_rescale(foot_height, MIN_SHADOW_HEIGHT, MAX_SHADOW_HEIGHT, 0.5f, 0.f));
+			}
+			sprite.setPosition(shadow_pos_agent);
+
+			LLVector3 foot_to_knee = mKneeRightp->getWorldPosition() - joint_world_pos;
+			//foot_to_knee.normalize();
+			foot_to_knee -= projected_vec(foot_to_knee, sun_vec);
+			sprite.setYaw(azimuth(sun_vec - foot_to_knee));
+	
+			sprite.updateFace(*face1p);
+		}
+	}
+}
+
 //-----------------------------------------------------------------------------
 // updateSexDependentLayerSets()
 //-----------------------------------------------------------------------------
@@ -5514,12 +5674,9 @@ void LLVOAvatar::updateSexDependentLayerSets( BOOL upload_bake )
 //-----------------------------------------------------------------------------
 void LLVOAvatar::dirtyMesh()
 {
-	dirtyMesh(1);
-}
-void LLVOAvatar::dirtyMesh(S32 priority)
-{
-	mDirtyMesh = llmax(mDirtyMesh, priority);
+	mDirtyMesh = TRUE;
 }
+
 //-----------------------------------------------------------------------------
 // hideSkirt()
 //-----------------------------------------------------------------------------
@@ -5553,6 +5710,7 @@ BOOL LLVOAvatar::setParent(LLViewerObject* parent)
 
 void LLVOAvatar::addChild(LLViewerObject *childp)
 {
+	childp->extractAttachmentItemID(); // find the inventory item this object is associated with.
 	LLViewerObject::addChild(childp);
 	if (childp->mDrawable)
 	{
@@ -5641,15 +5799,6 @@ BOOL LLVOAvatar::canAttachMoreObjects() const
 	return (getNumAttachments() < MAX_AGENT_ATTACHMENTS);
 }
 
-//-----------------------------------------------------------------------------
-// canAttachMoreObjects()
-// Returns true if we can attach <n> more objects.
-//-----------------------------------------------------------------------------
-BOOL LLVOAvatar::canAttachMoreObjects(U32 n) const
-{
-	return (getNumAttachments() + n) <= MAX_AGENT_ATTACHMENTS;
-}
-
 //-----------------------------------------------------------------------------
 // lazyAttach()
 //-----------------------------------------------------------------------------
@@ -6102,10 +6251,14 @@ void LLVOAvatar::updateMeshTextures()
 			// When an avatar is changing clothes and not in Appearance mode,
 			// use the last-known good baked texture until it finish the first
 			// render of the new layerset.
+
+			const BOOL layerset_invalid = !mBakedTextureDatas[i].mTexLayerSet 
+										  || !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized()
+										  || !mBakedTextureDatas[i].mTexLayerSet->isLocalTextureDataAvailable();
+
 			use_lkg_baked_layer[i] = (!is_layer_baked[i] 
 									  && (mBakedTextureDatas[i].mLastTextureIndex != IMG_DEFAULT_AVATAR) 
-									  && mBakedTextureDatas[i].mTexLayerSet 
-									  && !mBakedTextureDatas[i].mTexLayerSet->getComposite()->isInitialized());
+									  && layerset_invalid);
 			if (use_lkg_baked_layer[i])
 			{
 				mBakedTextureDatas[i].mTexLayerSet->setUpdatesEnabled(TRUE);
@@ -7793,15 +7946,18 @@ BOOL LLVOAvatar::updateLOD()
 	BOOL res = updateJointLODs();
 
 	LLFace* facep = mDrawable->getFace(0);
-	if (facep->mVertexBuffer.isNull())
+	if (facep->mVertexBuffer.isNull() ||
+		(LLVertexBuffer::sEnableVBOs &&
+		((facep->mVertexBuffer->getUsage() == GL_STATIC_DRAW ? TRUE : FALSE) !=
+		 (facep->getPool()->getVertexShaderLevel() > 0 ? TRUE : FALSE))))
 	{
-		dirtyMesh(2);
+		mDirtyMesh = TRUE;
 	}
 
-	if (mDirtyMesh >= 2 || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY))
+	if (mDirtyMesh || mDrawable->isState(LLDrawable::REBUILD_GEOMETRY))
 	{	//LOD changed or new mesh created, allocate new vertex buffer if needed
 		updateMeshData();
-		mDirtyMesh = 0;
+		mDirtyMesh = FALSE;
 		mNeedsSkin = TRUE;
 		mDrawable->clearState(LLDrawable::REBUILD_GEOMETRY);
 	}