diff --git a/.hgtags b/.hgtags
index 2e94290c50d2c53fc2e20b0876cde3a78dd1061f..5cdeede2eaa81915adea929a3f99f8e7c93ac805 100755
--- a/.hgtags
+++ b/.hgtags
@@ -465,3 +465,4 @@ fe4f7c5e9fd27e09d03deb1cc9ab3e5093f6309e 3.6.3-release
 83357f31d8dbf048a8bfdc323f363bf4d588aca1 CHOP-951-a
 91ed595b716f14f07409595b734fda891a59379e 3.6.4-release
 bf6d453046011a11de2643fac610cc5258650f82 3.6.5-release
+b62e417982d9d4f3ec49d0de3b3c2e37c6d394c1 3.6.6-release
diff --git a/NORSPEC-207.patch b/NORSPEC-207.patch
deleted file mode 100644
index a1c1447bdab6fdb46bd916532862eedb00bc36e0..0000000000000000000000000000000000000000
--- a/NORSPEC-207.patch
+++ /dev/null
@@ -1,164 +0,0 @@
-diff -r fe4bab01522e indra/llprimitive/llrendermaterialtable.cpp
---- a/indra/llprimitive/llrendermaterialtable.cpp	Wed May 15 17:57:21 2013 +0000
-+++ b/indra/llprimitive/llrendermaterialtable.cpp	Wed May 22 14:23:04 2013 -0700
-@@ -184,6 +184,44 @@
- 	}
- }
- 
-+// 'v' is an integer value for 100ths of radians (don't ask...)
-+//
-+void LLRenderMaterialEntry::LLRenderMaterial::setSpecularMapRotation(S32 v) const
-+{
-+	// Store the fact that we're using the new rotation rep
-+	//
-+	m_flags |= kNewSpecularMapRotation;
-+
-+	// Store 'sign bit' in our m_flags
-+	//
-+	m_flags &= ~kSpecularMapRotationNegative;
-+	m_flags |= (specularMapRotation < 0) ? kSpecularMapRotationNegative : 0;
-+
-+	specularRotation = abs(specularRotation);
-+	specularRotation = llmin(specularRotation, MAX_MATERIAL_MAP_ROTATION);
-+
-+	m_specularRotation = (U16)(abs(specularMapRotation));
-+}
-+
-+// 'v' is an integer value for 100ths of radians (don't ask...)
-+//
-+void LLRenderMaterialEntry::LLRenderMaterial::setNormalMapRotation(S32 v) const
-+{
-+
-+	// Store the fact that we're using the new rep for this material
-+	//
-+	m_flags |= kNewNormalMapRotation;
-+
-+	// Store 'sign bit' in our m_flags
-+	//
-+	m_flags &= ~kNormalMapRotationNegative;
-+	m_flags |= (normalMapRotation < 0) ? kNormalMapRotationNegative : 0;
-+
-+	normalRotation = abs(normalRotation);
-+	normalRotation = llmin(normalRotation, MAX_MATERIAL_MAP_ROTATION);
-+
-+	m_normalRotation = (U16)(abs(normalMapRotation));
-+}
- 
- void LLRenderMaterialEntry::LLRenderMaterial::asLLSD( LLSD& dest ) const
- {
-@@ -193,20 +231,45 @@
- 	dest["NormOffsetY"] = (S32)m_normalOffsetY;
- 	dest["NormRepeatX"] = m_normalRepeatX;
- 	dest["NormRepeatY"] = m_normalRepeatY;
--	dest["NormRotation"] = (S32)m_normalRotation;
-+
-+	S32 value = (S32)m_normalMapRotation;
-+
-+	// If we don't have the flag for new rotations set,
-+	// then we need to convert it now
-+	if (!(m_flags & kNewNormalMapRotation))
-+	{
-+		F32 old_radians = ((F32)m_normalMapRotation / 10000.0f)
-+		S32 new_val	    = (S32)(old_radians * 100.0f);
-+		setNormalMapRotation(new_Val);
-+	}
-+
-+	dest["NormRotation"] = (m_flags & kNormalMapRotationNegative) ? -(S32)m_normalRotation : (S32)m_normalRotation;
- 
- 	dest["SpecOffsetX"] = (S32)m_specularOffsetX;
- 	dest["SpecOffsetY"] = (S32)m_specularOffsetY;
- 	dest["SpecRepeatX"] = m_specularRepeatX;
- 	dest["SpecRepeatY"] = m_specularRepeatY;
--	dest["SpecRotation"] = (S32)m_specularRotation;
-+
-+
-+	value = (S32)m_specularRotation;
-+
-+	// If we don't have the flag for new rotations set,
-+	// then we need to convert it now
-+	if (!(m_flags & kNewSpecularMapRotation))
-+	{
-+		F32 old_radians = ((F32)m_specularMapRotation / 10000.0f)
-+		S32 new_val	    = (S32)(old_radians * 100.0f);
-+		setSpecularMapRotation(new_Val);
-+	}
-+
-+	dest["SpecRotation"] = (m_flags & kSpecularMapRotationNegative) ? -(S32)m_specularRotation : (S32)m_specularRotation;
- 
- 	dest["SpecMap"] = m_specularMap;
- 	dest["SpecColor"] = m_specularLightColor.getValue();
- 	dest["SpecExp"] = (S32)m_specularLightExponent;
- 	dest["EnvIntensity"] = (S32)m_environmentIntensity;
- 	dest["AlphaMaskCutoff"] = (S32)m_alphaMaskCutoff;
--	dest["DiffuseAlphaMode"] = (S32)m_diffuseAlphaMode;
-+	dest["DiffuseAlphaMode"] = (S32)(m_diffuseAlphaMode & 0xF);
- 	
- }
- 
-@@ -217,7 +280,10 @@
- 	m_normalOffsetY = (U16)materialDefinition["NormOffsetY"].asInteger();
- 	m_normalRepeatX = materialDefinition["NormRepeatX"].asInteger();
- 	m_normalRepeatY = materialDefinition["NormRepeatY"].asInteger();
--	m_normalRotation = (U16)materialDefinition["NormRotation"].asInteger();
-+
-+	S32 normalRotation = materialDefinition["NormRotation"].asInteger();
-+
-+	setNormalMapRotation(normalRotation);
- 
- 	m_specularMap = materialDefinition["SpecMap"].asUUID();
- 
-@@ -225,7 +291,10 @@
- 	m_specularOffsetY = (U16)materialDefinition["SpecOffsetY"].asInteger();
- 	m_specularRepeatX = materialDefinition["SpecRepeatX"].asInteger();
- 	m_specularRepeatY = materialDefinition["SpecRepeatY"].asInteger();
--	m_specularRotation = (U16)materialDefinition["SpecRotation"].asInteger();
-+
-+	S32 specularRotation = materialDefinition["SpecRotation"].asInteger();
-+
-+	setSpecularMapRotation(specularRotation);
- 
- 	m_specularLightColor.setValue( materialDefinition["SpecColor"] );
- 	m_specularLightExponent = (U8)materialDefinition["SpecExp"].asInteger();
-diff -r fe4bab01522e indra/llprimitive/llrendermaterialtable.h
---- a/indra/llprimitive/llrendermaterialtable.h	Wed May 15 17:57:21 2013 +0000
-+++ b/indra/llprimitive/llrendermaterialtable.h	Wed May 22 14:23:04 2013 -0700
-@@ -89,11 +89,17 @@
- 
- 	void computeID();
- 
-+
- 	struct LLRenderMaterial
- 	{
- 		void asLLSD( LLSD& dest ) const;
- 		void setFromLLSD( const LLSD& materialDefinition );
- 
-+		void setNormalMapRotation(S32 v);
-+		void setSpecularMapRotation(S32 v);
-+
-+		const S32 MAX_MATERIAL_MAP_ROTATION = 62800;
-+
- 		// 36 bytes
- 		LLUUID m_normalMap;
- 		LLUUID m_specularMap;
-@@ -119,7 +125,20 @@
- 		U8 m_specularLightExponent;
- 		U8 m_environmentIntensity;
- 		U8 m_alphaMaskCutoff;
--		U8 m_diffuseAlphaMode;
-+		U8 m_diffuseAlphaMode : 4;
-+		U8 m_flags            : 4;
-+	};
-+
-+	// Flags stored in LLRenderMaterial::m_flags to differentiate 'old' rotation format
-+	// which doesn't handle negative or large rotations correctly from new format.
-+	// All ancient materials will have these flags unset as the values for diffuseAlphaMode
-+	// from which the bits were stolen never used more than the bottom 2 bits.
-+	//
-+	enum RenderMaterialFlags {
-+	 kNewNormalMapRotation 		= 0x1,
-+	 kNewSpecularMapRotation 	= 0x2,
-+	 kNormalMapRotationNegative 	= 0x4,
-+	 kSpecularMapRotationNegative   = 0x8
- 	};
- 
- 	friend struct eastl::hash<LLRenderMaterial>;
diff --git a/autobuild.xml b/autobuild.xml
index e047d4d686a2aa2ffee04af65ba66813020ed168..b1478a46b24017b18aee5e26009cca3a3b24d54e 100755
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -2638,7 +2638,6 @@
                 <array>
                   <string>/build</string>
                   <string>"/cfg=Release|Win32"</string>
-                  <string>"/CL_ADD=/m:1"</string>
                 </array>
               </map>
               <key>configure</key>
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index a0802c6adfe997952e56a84a5477d5f47d1c0143..b7815b0e3586829015c9119fc2c19fe94063ee29 100755
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -226,7 +226,7 @@ void LLVolatileAPRPool::clearVolatileAPRPool()
 		llassert_always(mNumActiveRef > 0) ;
 	}
 
-	llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
+	llassert(mNumTotalRef <= (FULL_VOLATILE_APR_POOL << 2)) ;
 }
 
 BOOL LLVolatileAPRPool::isFull()
diff --git a/indra/llmath/llvector4a.inl b/indra/llmath/llvector4a.inl
index 7c52ffef2171c6caecd8c16af7793def0d99f74b..558fe0932315f0cbbf133d0356e949fb62df7810 100755
--- a/indra/llmath/llvector4a.inl
+++ b/indra/llmath/llvector4a.inl
@@ -409,6 +409,26 @@ inline void LLVector4a::normalize3fast()
 	mQ = _mm_mul_ps( mQ, approxRsqrt );
 }
 
+inline void LLVector4a::normalize3fast_checked(LLVector4a* d)
+{
+	if (!isFinite3())
+	{
+		*this = d ? *d : LLVector4a(0,1,0,1);
+		return;
+	}
+
+	LLVector4a lenSqrd; lenSqrd.setAllDot3( *this, *this );
+
+	if (lenSqrd.getF32ptr()[0] <= FLT_EPSILON)
+	{
+		*this = d ? *d : LLVector4a(0,1,0,1);
+		return;
+	}
+
+	const LLQuad approxRsqrt = _mm_rsqrt_ps(lenSqrd.mQ);
+	mQ = _mm_mul_ps( mQ, approxRsqrt );
+}
+
 // Return true if this vector is normalized with respect to x,y,z up to tolerance
 inline LLBool32 LLVector4a::isNormalized3( F32 tolerance ) const
 {
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 14cebfe5aa7d85c7ff10b6edf92cdaeee91f3e69..a030d889afc04abeb92b0d7cbf93333264cf4386 100755
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -136,6 +136,82 @@ BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* cent
 	return true;
 }
 
+// Finds tangent vec based on three vertices with texture coordinates.
+// Fills in dummy values if the triangle has degenerate texture coordinates.
+void calc_tangent_from_triangle(
+	LLVector4a&			normal,
+	LLVector4a&			tangent_out,
+	const LLVector4a& v1,
+	const LLVector2&  w1,
+	const LLVector4a& v2,
+	const LLVector2&  w2,
+	const LLVector4a& v3,
+	const LLVector2&  w3)
+{
+	const F32* v1ptr = v1.getF32ptr();
+	const F32* v2ptr = v2.getF32ptr();
+	const F32* v3ptr = v3.getF32ptr();
+
+	float x1 = v2ptr[0] - v1ptr[0];
+	float x2 = v3ptr[0] - v1ptr[0];
+	float y1 = v2ptr[1] - v1ptr[1];
+	float y2 = v3ptr[1] - v1ptr[1];
+	float z1 = v2ptr[2] - v1ptr[2];
+	float z2 = v3ptr[2] - v1ptr[2];
+
+	float s1 = w2.mV[0] - w1.mV[0];
+	float s2 = w3.mV[0] - w1.mV[0];
+	float t1 = w2.mV[1] - w1.mV[1];
+	float t2 = w3.mV[1] - w1.mV[1];
+
+	F32 rd = s1*t2-s2*t1;
+
+	float r = ((rd*rd) > FLT_EPSILON) ? 1.0F / rd : 1024.f; //some made up large ratio for division by zero
+
+	llassert(llfinite(r));
+	llassert(!llisnan(r));
+
+	LLVector4a sdir(
+		(t2 * x1 - t1 * x2) * r,
+		(t2 * y1 - t1 * y2) * r,
+		(t2 * z1 - t1 * z2) * r);
+
+	LLVector4a tdir(
+		(s1 * x2 - s2 * x1) * r,
+		(s1 * y2 - s2 * y1) * r,
+		(s1 * z2 - s2 * z1) * r);
+
+	LLVector4a	n = normal;
+	LLVector4a	t = sdir;
+
+	LLVector4a ncrosst;
+	ncrosst.setCross3(n,t);
+
+	// Gram-Schmidt orthogonalize
+	n.mul(n.dot3(t).getF32());
+
+	LLVector4a tsubn;
+	tsubn.setSub(t,n);
+
+	if (tsubn.dot3(tsubn).getF32() > F_APPROXIMATELY_ZERO)
+	{
+		tsubn.normalize3fast_checked();
+
+		// Calculate handedness
+		F32 handedness = ncrosst.dot3(tdir).getF32() < 0.f ? -1.f : 1.f;
+
+		tsubn.getF32ptr()[3] = handedness;
+
+		tangent_out = tsubn;
+	}
+	else
+	{
+		// degenerate, make up a value
+		//
+		tangent_out.set(0,0,1,1);
+	}
+
+}
 
 
 // intersect test between triangle vert0, vert1, vert2 and a ray from orig in direction dir.
@@ -5908,10 +5984,10 @@ void LLVolumeFace::cacheOptimize()
 		wght = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
 	}
 
-	LLVector4a* binorm = NULL;
+	LLVector4a* tangent = NULL;
 	if (mTangents)
 	{
-		binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+		tangent = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
 	}
 
 	//allocate mapping of old indices to new indices
@@ -5936,7 +6012,7 @@ void LLVolumeFace::cacheOptimize()
 			}
 			if (mTangents)
 			{
-				binorm[cur_idx] = mTangents[idx];
+				tangent[cur_idx] = mTangents[idx];
 			}
 
 			cur_idx++;
@@ -5958,7 +6034,7 @@ void LLVolumeFace::cacheOptimize()
 	mNormals = norm;
 	mTexCoords = tc;
 	mWeights = wght;
-	mTangents = binorm;
+	mTangents = tangent;
 
 	//std::string result = llformat("ACMR pre/post: %.3f/%.3f  --  %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
 	//llinfos << result << llendl;
@@ -6306,6 +6382,43 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 
 	cuv = (min_uv + max_uv)*0.5f;
 
+
+	LLVector4a tangent;
+	calc_tangent_from_triangle(
+			*norm,
+			tangent,
+			*mCenter, cuv,
+			pos[0], tc[0],
+			pos[1], tc[1]);
+
+	if (tangent.getLength3() < 0.01)
+	{
+		tangent.set(1,0,0,1);
+	}
+	else
+	{
+		LLVector4a default_tangent;
+		default_tangent.set(1,0,0,1);
+		tangent.normalize3fast_checked(&default_tangent);
+	}
+
+	LLVector4a normal;
+	LLVector4a d0, d1;
+
+	d0.setSub(*mCenter, pos[0]);
+	d1.setSub(*mCenter, pos[1]);
+	
+	if (mTypeMask & TOP_MASK)
+	{
+		normal.setCross3(d0, d1);
+	}
+	else
+	{
+		normal.setCross3(d1, d0);
+	}
+
+	normal.normalize3fast_checked();
+
 	VertexData vd;
 	vd.setPosition(*mCenter);
 	vd.mTexCoord = cuv;
@@ -6318,6 +6431,14 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 		num_vertices++;
 	}
 		
+	allocateTangents(num_vertices);		
+
+	for (S32 i = 0; i < num_vertices; i++)
+	{
+		mTangents[i].load4a(tangent.getF32ptr());
+		norm[i].load4a(normal.getF32ptr());
+	}	
+
 	if (partial_build)
 	{
 		return TRUE;
@@ -6553,36 +6674,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 
 	}
 
-	LLVector4a d0,d1;
-
-	d0.setSub(mPositions[mIndices[1]], mPositions[mIndices[0]]);
-	d1.setSub(mPositions[mIndices[2]], mPositions[mIndices[0]]);
-
-	LLVector4a normal;
-	normal.setCross3(d0,d1);
-
-	if (normal.dot3(normal).getF32() > F_APPROXIMATELY_ZERO)
-	{
-		normal.normalize3fast();
-	}
-	else
-	{ //degenerate, make up a value
-		normal.set(0,0,1);
-	}
-
-	llassert(llfinite(normal.getF32ptr()[0]));
-	llassert(llfinite(normal.getF32ptr()[1]));
-	llassert(llfinite(normal.getF32ptr()[2]));
-
-	llassert(!llisnan(normal.getF32ptr()[0]));
-	llassert(!llisnan(normal.getF32ptr()[1]));
-	llassert(!llisnan(normal.getF32ptr()[2]));
-	
-	for (S32 i = 0; i < num_vertices; i++)
-	{
-		norm[i].load4a(normal.getF32ptr());
-	}
-
 	return TRUE;
 }
 
@@ -6611,11 +6702,13 @@ void LLVolumeFace::createTangents()
 		CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices/3, mIndices, mTangents);
 
 		//normalize tangents
+		LLVector4a default_norm;
+		default_norm.set(0,1,0,1);
 		for (U32 i = 0; i < mNumVertices; i++) 
 		{
-			//binorm[i].normalize3fast();
+			//tangent[i].normalize3fast();
 			//bump map/planar projection code requires normals to be normalized
-			mNormals[i].normalize3fast();
+			mNormals[i].normalize3fast_checked();
 		}
 	}
 }
@@ -6800,7 +6893,7 @@ void LLVolumeFace::appendFace(const LLVolumeFace& face, LLMatrix4& mat_in, LLMat
 
 		//transform appended face normal and store
 		norm_mat.rotate(src_norm[i], dst_norm[i]);
-		dst_norm[i].normalize3fast();
+		dst_norm[i].normalize3fast_checked();
 
 		//copy appended face texture coordinate
 		dst_tc[i] = src_tc[i];
@@ -7209,11 +7302,61 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 	return TRUE;
 }
 
+// Finds binormal based on three vertices with texture coordinates.
+// Fills in dummy values if the triangle has degenerate texture coordinates.
+void calc_binormal_from_triangle(LLVector4a& binormal,
+
+	const LLVector4a& pos0,
+	const LLVector2& tex0,
+	const LLVector4a& pos1,
+	const LLVector2& tex1,
+	const LLVector4a& pos2,
+	const LLVector2& tex2)
+{
+	LLVector4a rx0( pos0[VX], tex0.mV[VX], tex0.mV[VY] );
+	LLVector4a rx1( pos1[VX], tex1.mV[VX], tex1.mV[VY] );
+	LLVector4a rx2( pos2[VX], tex2.mV[VX], tex2.mV[VY] );
+	
+	LLVector4a ry0( pos0[VY], tex0.mV[VX], tex0.mV[VY] );
+	LLVector4a ry1( pos1[VY], tex1.mV[VX], tex1.mV[VY] );
+	LLVector4a ry2( pos2[VY], tex2.mV[VX], tex2.mV[VY] );
+
+	LLVector4a rz0( pos0[VZ], tex0.mV[VX], tex0.mV[VY] );
+	LLVector4a rz1( pos1[VZ], tex1.mV[VX], tex1.mV[VY] );
+	LLVector4a rz2( pos2[VZ], tex2.mV[VX], tex2.mV[VY] );
+	
+	LLVector4a lhs, rhs;
+
+	LLVector4a r0; 
+	lhs.setSub(rx0, rx1); rhs.setSub(rx0, rx2);
+	r0.setCross3(lhs, rhs);
+		
+	LLVector4a r1;
+	lhs.setSub(ry0, ry1); rhs.setSub(ry0, ry2);
+	r1.setCross3(lhs, rhs);
+
+	LLVector4a r2;
+	lhs.setSub(rz0, rz1); rhs.setSub(rz0, rz2);
+	r2.setCross3(lhs, rhs);
+
+	if( r0[VX] && r1[VX] && r2[VX] )
+	{
+		binormal.set(
+				-r0[VZ] / r0[VX],
+				-r1[VZ] / r1[VX],
+				-r2[VZ] / r2[VX]);
+		// binormal.normVec();
+	}
+	else
+	{
+		binormal.set( 0, 1 , 0 );
+	}
+}
+
 //adapted from Lengyel, Eric. “Computing Tangent Space Basis Vectors for an Arbitrary Mesh”. Terathon Software 3D Graphics Library, 2001. http://www.terathon.com/code/tangent.html
 void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal,
         const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent)
 {
-    //LLVector4a *tan1 = new LLVector4a[vertexCount * 2];
 	LLVector4a* tan1 = (LLVector4a*) ll_aligned_malloc_16(vertexCount*2*sizeof(LLVector4a));
 
     LLVector4a* tan2 = tan1 + vertexCount;
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index 597f0784904f9362dcdb369d1a0e4a4ef5148299..0db75a0e823208828841d84d3cfedc9f3fce74a9 100755
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -545,7 +545,7 @@ S32 LLTextureEntry::setMaterialID(const LLMaterialID& pMaterialID)
 		{
 			mMaterialUpdatePending = true;
 			mMaterialID = pMaterialID;
-			return TEM_CHANGE_NONE;
+			return TEM_CHANGE_TEXTURE;
 		}
 
 		mMaterialUpdatePending = false;
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index c3005f1722b2f4677588dba987a09770d6d2bc68..a157cd94c4535d82407b442deff61498cb68267a 100755
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -647,7 +647,8 @@ bool LLGLManager::initGL()
 		}
 #if LL_DARWIN
 		else if ((mGLRenderer.find("9400M") != std::string::npos)
-			  || (mGLRenderer.find("9600M") != std::string::npos))
+			  || (mGLRenderer.find("9600M") != std::string::npos)
+			  || (mGLRenderer.find("9800M") != std::string::npos))
 		{
 			mIsMobileGF = TRUE;
 		}
@@ -1155,7 +1156,7 @@ void LLGLManager::initExtensions()
 	glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, (GLint*) &mGLMaxVertexRange);
 	glGetIntegerv(GL_MAX_ELEMENTS_INDICES, (GLint*) &mGLMaxIndexRange);
 	glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*) &mGLMaxTextureSize);
-
+	
 #if (LL_WINDOWS || LL_LINUX || LL_SOLARIS) && !LL_MESA_HEADLESS
 	LL_DEBUGS("RenderInit") << "GL Probe: Getting symbols" << LL_ENDL;
 	if (mHasVertexBufferObject)
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index ac16e30796a96d4e27190151a7344f2a92a0afc7..40aff36dac3b4772b7f30f5c21ab246c96769482 100755
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -374,6 +374,11 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
 
 	// Create program
 	mProgramObject = glCreateProgramObjectARB();
+
+#if LL_DARWIN
+    // work-around missing mix(vec3,vec3,bvec3)
+    mDefines["OLD_SELECT"] = "1";
+#endif
 	
 	//compile new source
 	vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
diff --git a/indra/llrender/llrender.cpp b/indra/llrender/llrender.cpp
index c60eb8d9d9169271dad585f042c302e52f65e970..f2f1b62be0fc617a58600925a8efce279dbb0754 100755
--- a/indra/llrender/llrender.cpp
+++ b/indra/llrender/llrender.cpp
@@ -1849,35 +1849,36 @@ void LLRender::flush()
 			sUIVerts += mCount;
 		}
 		
-		if (gDebugGL)
+		//store mCount in a local variable to avoid re-entrance (drawArrays may call flush)
+		U32 count = mCount;
+
+		if (mMode == LLRender::QUADS && !sGLCoreProfile)
 		{
-			if (mMode == LLRender::QUADS && !sGLCoreProfile)
+			if (mCount%4 != 0)
 			{
-				if (mCount%4 != 0)
-				{
-					llerrs << "Incomplete quad rendered." << llendl;
-				}
+				count -= (mCount % 4);
+				llwarns << "Incomplete quad requested." << llendl;
 			}
-			
-			if (mMode == LLRender::TRIANGLES)
+		}
+
+		if (mMode == LLRender::TRIANGLES)
+		{
+			if (mCount%3 != 0)
 			{
-				if (mCount%3 != 0)
-				{
-					llerrs << "Incomplete triangle rendered." << llendl;
-				}
+				count -= (mCount % 3);
+				llwarns << "Incomplete triangle requested." << llendl;
 			}
-			
-			if (mMode == LLRender::LINES)
+		}
+
+		if (mMode == LLRender::LINES)
+		{
+			if (mCount%2 != 0)
 			{
-				if (mCount%2 != 0)
-				{
-					llerrs << "Incomplete line rendered." << llendl;
-				}
+				count -= (mCount % 2);
+				llwarns << "Incomplete line requested." << llendl;
 			}
 		}
-
-		//store mCount in a local variable to avoid re-entrance (drawArrays may call flush)
-		U32 count = mCount;
+		
 		mCount = 0;
 
 		if (mBuffer->useVBOs() && !mBuffer->isLocked())
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 5ea8387c044b4e131582a04c4f33ba335f57a461..c0602d79bd0b07cc58ade76ab65b80f691e04579 100755
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -79,7 +79,7 @@ LLRenderTarget::~LLRenderTarget()
 	release();
 }
 
-void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt)
+void LLRenderTarget::resize(U32 resx, U32 resy)
 { 
 	//for accounting, get the number of pixels added/subtracted
 	S32 pix_diff = (resx*resy)-(mResX*mResY);
@@ -87,10 +87,12 @@ void LLRenderTarget::resize(U32 resx, U32 resy, U32 color_fmt)
 	mResX = resx;
 	mResY = resy;
 
+	llassert(mInternalFormat.size() == mTex.size());
+
 	for (U32 i = 0; i < mTex.size(); ++i)
 	{ //resize color attachments
 		gGL.getTexUnit(0)->bindManual(mUsage, mTex[i]);
-		LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, color_fmt, mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
+		LLImageGL::setManualImage(LLTexUnit::getInternalType(mUsage), 0, mInternalFormat[i], mResX, mResY, GL_RGBA, GL_UNSIGNED_BYTE, NULL, false);
 		sBytesAllocated += pix_diff*4;
 	}
 
@@ -260,7 +262,7 @@ bool LLRenderTarget::addColorAttachment(U32 color_fmt)
 	}
 #endif
     
-    
+
 	return true;
 }
 
@@ -362,36 +364,56 @@ void LLRenderTarget::release()
 
 		sBytesAllocated -= mResX*mResY*4;
 	}
-	else if (mUseDepth && mFBO)
-	{ //detach shared depth buffer
+	else if (mFBO)
+	{
 		glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
-		if (mStencil)
-		{ //attached as a renderbuffer
-			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
-			glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
-			mStencil = false;
+
+		if (mUseDepth)
+		{ //detach shared depth buffer
+			if (mStencil)
+			{ //attached as a renderbuffer
+				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+				glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+				mStencil = false;
+			}
+			else
+			{ //attached as a texture
+				glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
+			}
+			mUseDepth = false;
 		}
-		else
-		{ //attached as a texture
-			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, LLTexUnit::getInternalType(mUsage), 0, 0);
+	}
+
+	// Detach any extra color buffers (e.g. SRGB spec buffers)
+	//
+	if (mFBO && (mTex.size() > 1))
+	{		
+		S32 z;
+		for (z = mTex.size() - 1; z >= 1; z--)
+		{
+			sBytesAllocated -= mResX*mResY*4;
+			glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+z, LLTexUnit::getInternalType(mUsage), 0, 0);
+			stop_glerror();
+			LLImageGL::deleteTextures(mUsage, mInternalFormat[z], 0, 1, &mTex[z], true);
 		}
-		mUseDepth = false;
 	}
 
 	if (mFBO)
 	{
 		glDeleteFramebuffers(1, (GLuint *) &mFBO);
+		stop_glerror();
 		mFBO = 0;
 	}
 
 	if (mTex.size() > 0)
 	{
-		sBytesAllocated -= mResX*mResY*4*mTex.size();
-		LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, mTex.size(), &mTex[0], true);
-		mTex.clear();
-		mInternalFormat.clear();
+		sBytesAllocated -= mResX*mResY*4;
+		LLImageGL::deleteTextures(mUsage, mInternalFormat[0], 0, 1, &mTex[0], true);
 	}
-	
+
+	mTex.clear();
+	mInternalFormat.clear();
+
 	mResX = mResY = 0;
 
 	sBoundTarget = NULL;
@@ -575,8 +597,10 @@ void LLRenderTarget::copyContentsToFramebuffer(LLRenderTarget& source, S32 srcX0
 {
 	if (!source.mFBO)
 	{
-		llerrs << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+		llwarns << "Cannot copy framebuffer contents for non FBO render targets." << llendl;
+		return;
 	}
+
 	{
 		GLboolean write_depth = mask & GL_DEPTH_BUFFER_BIT ? TRUE : FALSE;
 
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index 66a9874a6b20ddd5ba41964b07e436a8c8e3f3ca..336441661c765414b3fae2c4d0783a3eb3852e19 100755
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -79,7 +79,7 @@ class LLRenderTarget
 	// CAUTION: if the GL runs out of memory attempting to resize, this render target will be undefined
 	// DO NOT use for screen space buffers or for scratch space for an image that might be uploaded
 	// DO use for render targets that resize often and aren't likely to ruin someone's day if they break
-	void resize(U32 resx, U32 resy, U32 color_fmt);
+	void resize(U32 resx, U32 resy);
 
 	//add color buffer attachment
 	//limit of 4 color attachments per render target
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index fea4ee28198faa0ce693ca842fd3b66507daaac0..63404abeff9156b66a864765ef28913de3d32d73 100755
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -1137,11 +1137,13 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("projectionMap");
 	
 	mReservedUniforms.push_back("global_gamma");
-	mReservedUniforms.push_back("texture_gamma");
-	
+	mReservedUniforms.push_back("texture_gamma");	
+
 	mReservedUniforms.push_back("specular_color");
 	mReservedUniforms.push_back("env_intensity");
 
+	mReservedUniforms.push_back("display_gamma");
+
 	llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
 
 	std::set<std::string> dupe_check;
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index c049e935b83e8a50f813cf201c44639aeaa82a1a..3c282bf24f1a0bf7141340a1600f0814405e6adf 100755
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -167,11 +167,13 @@ class LLShaderMgr
 		DEFERRED_PROJECTION,
 		
 		GLOBAL_GAMMA,
-		TEXTURE_GAMMA,
-		
+		TEXTURE_GAMMA,		
+
 		SPECULAR_COLOR,
 		ENVIRONMENT_INTENSITY,
 		
+		DISPLAY_GAMMA,
+
 		END_RESERVED_UNIFORMS
 	} eGLSLReservedUniforms;
 
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 01541026b100d7967d8f332cce47054d0cff7753..6a7cec3bada18eec7f9c2997e16583134aa5c82f 100755
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -753,10 +753,10 @@ void LLVertexBuffer::drawRange(U32 mode, U32 start, U32 end, U32 count, U32 indi
 	U16* idx = ((U16*) getIndicesPointer())+indices_offset;
 
 	stop_glerror();
-	LLGLSLShader::startProfile();
-	glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
+		LLGLSLShader::startProfile();
+		glDrawRangeElements(sGLMode[mode], start, end, count, GL_UNSIGNED_SHORT, 
 		idx);
-	LLGLSLShader::stopProfile(count, mode);
+		LLGLSLShader::stopProfile(count, mode);
 	stop_glerror();
 
 	
@@ -2236,10 +2236,41 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 					required_mask |= required;
 				}
 			}
-
+        
 			if ((data_mask & required_mask) != required_mask)
 			{
-				llwarns << "Shader consumption mismatches data provision." << llendl;
+				
+				U32 unsatisfied_mask = (required_mask & ~data_mask);
+				U32 i = 0;
+
+				while (i < TYPE_MAX)
+				{
+                    U32 unsatisfied_flag = unsatisfied_mask & (1 << i);
+					switch (unsatisfied_flag)
+					{
+						case MAP_VERTEX: llinfos << "Missing vert pos" << llendl; break;
+						case MAP_NORMAL: llinfos << "Missing normals" << llendl; break;
+						case MAP_TEXCOORD0: llinfos << "Missing TC 0" << llendl; break;
+						case MAP_TEXCOORD1: llinfos << "Missing TC 1" << llendl; break;
+						case MAP_TEXCOORD2: llinfos << "Missing TC 2" << llendl; break;
+						case MAP_TEXCOORD3: llinfos << "Missing TC 3" << llendl; break;
+						case MAP_COLOR: llinfos << "Missing vert color" << llendl; break;
+						case MAP_EMISSIVE: llinfos << "Missing emissive" << llendl; break;
+						case MAP_TANGENT: llinfos << "Missing tangent" << llendl; break;
+						case MAP_WEIGHT: llinfos << "Missing weight" << llendl; break;
+						case MAP_WEIGHT4: llinfos << "Missing weightx4" << llendl; break;
+						case MAP_CLOTHWEIGHT: llinfos << "Missing clothweight" << llendl; break;
+						case MAP_TEXTURE_INDEX: llinfos << "Missing tex index" << llendl; break;
+						default: llinfos << "Missing who effin knows: " << unsatisfied_flag << llendl;
+					}					
+				}
+
+            if (unsatisfied_mask & (1 << TYPE_INDEX))
+            {
+               llinfos << "Missing indices" << llendl;
+            }
+
+				llerrs << "Shader consumption mismatches data provision." << llendl;
 			}
 		}
 	}
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 4f2c1d15f6df48073057472403968720cb96e72b..5b3413147c957b8ea5c1233ea0409dfa13288fc0 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-3.6.6
+3.6.7
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index 72fe21cf14be78b8d82f77bf2ed220082c78e8d0..388589a398b75c09b35e1d80c8acbe036a56eed2 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -3579,13 +3579,13 @@
     </map>
     <key>FilterItemsMaxTimePerFrameUnvisible</key>
     <map>
-        <key>Comment</key>
+      <key>Comment</key>
         <string>Max time devoted to items filtering per frame for non visible inventory listings (in milliseconds)</string>
-        <key>Persist</key>
-        <integer>1</integer>
-        <key>Type</key>
-        <string>S32</string>
-        <key>Value</key>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
         <integer>1</integer>
     </map>
     <key>FindLandArea</key>
@@ -8831,6 +8831,18 @@
     </array>
   </map>
 
+  <key>RenderSpecularPrecision</key>
+  <map>
+    <key>Comment</key>
+    <string>Force 32-bit floating point LUT</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>U32</string>
+    <key>Value</key>
+    <real>0</real>
+  </map>
+  
   <key>RenderSpecularResX</key>
   <map>
     <key>Comment</key>
@@ -9121,6 +9133,17 @@
       <key>Value</key>
       <real>1.0</real>
     </map>
+  <key>RenderDeferredDisplayGamma</key>
+  <map>
+    <key>Comment</key>
+    <string>Gamma ramp exponent for final correction before display gamma.</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>F32</string>
+    <key>Value</key>
+    <real>2.2</real>
+  </map>
     <key>RenderGLCoreProfile</key>
     <map>
       <key>Comment</key>
@@ -9848,6 +9871,17 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
+    <key>RenderWaterMaterials</key>
+    <map>
+      <key>Comment</key>
+      <string>Water planar reflections include materials rendering.</string>
+      <key>Persist</key>
+      <integer>1</integer>
+      <key>Type</key>
+      <string>S32</string>
+      <key>Value</key>
+      <integer>0</integer>
+    </map>
     <key>RenderWaterMipNormal</key>
     <map>
       <key>Comment</key>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index 0899caa2af6e84884ce371daa0caba5f8f5a0db9..cd7a76db28c67959f6e50f8487be938a0ccc0bca 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -35,6 +35,26 @@ out vec4 frag_color;
 #define frag_color gl_FragColor
 #endif
 
+uniform float display_gamma;
+uniform vec4 gamma;
+uniform vec4 lightnorm;
+uniform vec4 sunlight_color;
+uniform vec4 ambient;
+uniform vec4 blue_horizon;
+uniform vec4 blue_density;
+uniform float haze_horizon;
+uniform float haze_density;
+uniform float cloud_shadow;
+uniform float density_multiplier;
+uniform float distance_multiplier;
+uniform float max_y;
+uniform vec4 glow;
+uniform float scene_light_strength;
+uniform mat3 env_mat;
+uniform mat3 ssao_effect_mat;
+
+uniform vec3 sun_dir;
+
 #if HAS_SHADOW
 uniform sampler2DShadow shadowMap0;
 uniform sampler2DShadow shadowMap1;
@@ -53,14 +73,8 @@ uniform float shadow_bias;
 uniform sampler2D diffuseMap;
 #endif
 
-vec3 atmosLighting(vec3 light);
-vec3 scaleSoftClip(vec3 light);
-
-VARYING vec3 vary_ambient;
-VARYING vec3 vary_directional;
 VARYING vec3 vary_fragcoord;
 VARYING vec3 vary_position;
-VARYING vec3 vary_pointlight_col;
 VARYING vec2 vary_texcoord0;
 VARYING vec3 vary_norm;
 
@@ -68,12 +82,73 @@ VARYING vec3 vary_norm;
 VARYING vec4 vertex_color;
 #endif
 
+vec3 vary_PositionEye;
+vec3 vary_SunlitColor;
+vec3 vary_AmblitColor;
+vec3 vary_AdditiveColor;
+vec3 vary_AtmosAttenuation;
+
+uniform mat4 inv_proj;
+uniform vec2 screen_res;
+
 uniform vec4 light_position[8];
 uniform vec3 light_direction[8];
 uniform vec3 light_attenuation[8]; 
 uniform vec3 light_diffuse[8];
 
-uniform vec2 screen_res;
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
+vec3 decode_normal (vec2 enc)
+{
+    vec2 fenc = enc*4-2;
+    float f = dot(fenc,fenc);
+    float g = sqrt(1-f/4);
+    vec3 n;
+    n.xy = fenc*g;
+    n.z = 1-f/2;
+    return n;
+}
 
 vec3 calcDirectionalLight(vec3 n, vec3 l)
 {
@@ -82,7 +157,7 @@ vec3 calcDirectionalLight(vec3 n, vec3 l)
 	return vec3(a,a,a);
 }
 
-vec3 calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 diffuse, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
 {
 	//get light vector
 	vec3 lv = lp.xyz-v;
@@ -90,7 +165,9 @@ vec3 calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float
 	//get distance
 	float d = length(lv);
 	
-	float da = 0.0;
+	float da = 1.0;
+
+	vec3 col = vec3(0);
 
 	if (d > 0.0 && la > 0.0 && fa > 0.0)
 	{
@@ -99,20 +176,25 @@ vec3 calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float
 	
 		//distance attenuation
 		float dist = d/la;
-		da = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
-		da *= da;
-		da *= 1.4;
-	
+		float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
+		dist_atten *= dist_atten;
+		dist_atten *= 2.0;
 
 		// spotlight coefficient.
 		float spot = max(dot(-ln, lv), is_pointlight);
 		da *= spot*spot; // GL_SPOT_EXPONENT=2
 
 		//angular attenuation
-		da *= max(dot(n, lv), 0.0);		
+		da *= max(dot(n, lv), 0.0);
+
+		float lit = max(da * dist_atten,0.0);
+
+		col = light_col * lit * diffuse;
+
+		// no spec for alpha shader...
 	}
 
-	return vec3(da,da,da);	
+	return max(col, vec3(0.0,0.0,0.0));
 }
 
 #if HAS_SHADOW
@@ -135,6 +217,237 @@ float pcfShadow(sampler2DShadow shadowMap, vec4 stc)
 }
 #endif
 
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
+
+vec3 getSunlitColor()
+{
+	return vary_SunlitColor;
+}
+vec3 getAmblitColor()
+{
+	return vary_AmblitColor;
+}
+vec3 getAdditiveColor()
+{
+	return vary_AdditiveColor;
+}
+vec3 getAtmosAttenuation()
+{
+	return vary_AtmosAttenuation;
+}
+
+void setPositionEye(vec3 v)
+{
+	vary_PositionEye = v;
+}
+
+void setSunlitColor(vec3 v)
+{
+	vary_SunlitColor = v;
+}
+
+void setAmblitColor(vec3 v)
+{
+	vary_AmblitColor = v;
+}
+
+void setAdditiveColor(vec3 v)
+{
+	vary_AdditiveColor = v;
+}
+
+void setAtmosAttenuation(vec3 v)
+{
+	vary_AtmosAttenuation = v;
+}
+
+void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
+
+	vec3 P = inPositionEye;
+	setPositionEye(P);
+	
+	vec3 tmpLightnorm = lightnorm.xyz;
+
+	vec3 Pn = normalize(P);
+	float Plen = length(P);
+
+	vec4 temp1 = vec4(0);
+	vec3 temp2 = vec3(0);
+	vec4 blue_weight;
+	vec4 haze_weight;
+	vec4 sunlight = sunlight_color;
+	vec4 light_atten;
+
+	//sunlight attenuation effect (hue and brightness) due to atmosphere
+	//this is used later for sunlight modulation at various altitudes
+	light_atten = (blue_density + vec4(haze_density * 0.25)) * (density_multiplier * max_y);
+		//I had thought blue_density and haze_density should have equal weighting,
+		//but attenuation due to haze_density tends to seem too strong
+
+	temp1 = blue_density + vec4(haze_density);
+	blue_weight = blue_density / temp1;
+	haze_weight = vec4(haze_density) / temp1;
+
+	//(TERRAIN) compute sunlight from lightnorm only (for short rays like terrain)
+	temp2.y = max(0.0, tmpLightnorm.y);
+	temp2.y = 1. / temp2.y;
+	sunlight *= exp( - light_atten * temp2.y);
+
+	// main atmospheric scattering line integral
+	temp2.z = Plen * density_multiplier;
+
+	// Transparency (-> temp1)
+	// ATI Bugfix -- can't store temp1*temp2.z*distance_multiplier in a variable because the ati
+	// compiler gets confused.
+	temp1 = exp(-temp1 * temp2.z * distance_multiplier);
+
+	//final atmosphere attenuation factor
+	setAtmosAttenuation(temp1.rgb);
+	
+	//compute haze glow
+	//(can use temp2.x as temp because we haven't used it yet)
+	temp2.x = dot(Pn, tmpLightnorm.xyz);
+	temp2.x = 1. - temp2.x;
+		//temp2.x is 0 at the sun and increases away from sun
+	temp2.x = max(temp2.x, .03);	//was glow.y
+		//set a minimum "angle" (smaller glow.y allows tighter, brighter hotspot)
+	temp2.x *= glow.x;
+		//higher glow.x gives dimmer glow (because next step is 1 / "angle")
+	temp2.x = pow(temp2.x, glow.z);
+		//glow.z should be negative, so we're doing a sort of (1 / "angle") function
+
+	//add "minimum anti-solar illumination"
+	temp2.x += .25;
+	
+	//increase ambient when there are more clouds
+	vec4 tmpAmbient = ambient + (vec4(1.) - ambient) * cloud_shadow * 0.5;
+	
+	/*  decrease value and saturation (that in HSV, not HSL) for occluded areas
+	 * // for HSV color/geometry used here, see http://gimp-savvy.com/BOOK/index.html?node52.html
+	 * // The following line of code performs the equivalent of:
+	 * float ambAlpha = tmpAmbient.a;
+	 * float ambValue = dot(vec3(tmpAmbient), vec3(0.577)); // projection onto <1/rt(3), 1/rt(3), 1/rt(3)>, the neutral white-black axis
+	 * vec3 ambHueSat = vec3(tmpAmbient) - vec3(ambValue);
+	 * tmpAmbient = vec4(RenderSSAOEffect.valueFactor * vec3(ambValue) + RenderSSAOEffect.saturationFactor *(1.0 - ambFactor) * ambHueSat, ambAlpha);
+	 */
+	tmpAmbient = vec4(mix(ssao_effect_mat * tmpAmbient.rgb, tmpAmbient.rgb, ambFactor), tmpAmbient.a);
+
+	//haze color
+	setAdditiveColor(
+		vec3(blue_horizon * blue_weight * (sunlight*(1.-cloud_shadow) + tmpAmbient)
+	  + (haze_horizon * haze_weight) * (sunlight*(1.-cloud_shadow) * temp2.x
+		  + tmpAmbient)));
+
+	//brightness of surface both sunlight and ambient
+	setSunlitColor(vec3(sunlight * .5));
+	setAmblitColor(vec3(tmpAmbient * .25));
+	setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1));
+}
+
+vec3 atmosLighting(vec3 light)
+{
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor();
+	return (2.0 * light);
+}
+
+vec3 atmosTransport(vec3 light) {
+	light *= getAtmosAttenuation().r;
+	light += getAdditiveColor() * 2.0;
+	return light;
+}
+vec3 atmosGetDiffuseSunlightColor()
+{
+	return getSunlitColor();
+}
+
+vec3 scaleDownLight(vec3 light)
+{
+	return (light / vec3(scene_light_strength, scene_light_strength, scene_light_strength));
+}
+
+vec3 scaleUpLight(vec3 light)
+{
+	return (light * vec3(scene_light_strength, scene_light_strength, scene_light_strength));
+}
+
+vec3 atmosAmbient(vec3 light)
+{
+	return getAmblitColor() + (light * vec3(0.5f, 0.5f, 0.5f));
+}
+
+vec3 atmosAffectDirectionalLight(float lightIntensity)
+{
+	return getSunlitColor() * vec3(lightIntensity, lightIntensity, lightIntensity);
+}
+
+vec3 scaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+    vec3 zeroes = vec3(0.0f, 0.0f, 0.0f);
+    vec3 ones   = vec3(1.0f, 1.0f, 1.0f);
+
+	light = ones - clamp(light, zeroes, ones);
+	light = ones - pow(light, gamma.xxx);
+
+	return light;
+}
+
+vec3 fullbrightAtmosTransport(vec3 light) {
+	float brightness = dot(light.rgb, vec3(0.33333));
+
+	return mix(atmosTransport(light.rgb), light.rgb + getAdditiveColor().rgb, brightness * brightness);
+}
+
+vec3 fullbrightScaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+	return light;
+}
 
 void main() 
 {
@@ -143,13 +456,15 @@ void main()
 	
 	vec4 pos = vec4(vary_position, 1.0);
 	
+	float shadow = 1.0;
 
-#if HAS_SHADOW
-	float shadow = 0.0;
+#if HAS_SHADOW	
 	vec4 spos = pos;
 		
 	if (spos.z > -shadow_clip.w)
 	{	
+		shadow = 0.0;
+
 		vec4 lpos;
 		
 		vec4 near_split = shadow_clip*-0.75;
@@ -215,40 +530,77 @@ void main()
 #else
 	vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy);
 #endif
-	vec4 gamma_diff = diff;
 
-	diff.rgb = pow(diff.rgb, vec3(2.2f, 2.2f, 2.2f));
+#ifdef FOR_IMPOSTOR
+	vec4 color;
+	color.rgb = diff.rgb;
 
 #ifdef USE_VERTEX_COLOR
-	float vertex_color_alpha = vertex_color.a;	
+	float final_alpha = diff.a * vertex_color.a;
+	diff.rgb *= vertex_color.rgb;
 #else
-	float vertex_color_alpha = 1.0;
+	float final_alpha = diff.a;
 #endif
-	
-	vec3 normal = vary_norm; 
-	
-	vec3 l = light_position[0].xyz;
-	vec3 dlight = calcDirectionalLight(normal, l);
-	dlight = dlight * vary_directional.rgb * vary_pointlight_col;
 
-#if HAS_SHADOW
-	vec4 col = vec4(vary_ambient + dlight * shadow, vertex_color_alpha);
+	// Insure we don't pollute depth with invis pixels in impostor rendering
+	//
+	if (final_alpha < 0.01)
+	{
+		discard;
+	}
+#else
+
+#ifdef USE_VERTEX_COLOR
+	float final_alpha = diff.a * vertex_color.a;
+	diff.rgb *= vertex_color.rgb;
 #else
-	vec4 col = vec4(vary_ambient + dlight, vertex_color_alpha);
+	float final_alpha = diff.a;
 #endif
 
-	vec4 color = gamma_diff * col;
-	
-	color.rgb = atmosLighting(color.rgb);
 
+	vec4 gamma_diff = diff;	
+	diff.rgb = srgb_to_linear(diff.rgb);
+
+	vec3 norm = vary_norm; 
+
+	calcAtmospherics(pos.xyz, 1.0);
+
+	vec2 abnormal	= encode_normal(norm.xyz);
+		 norm.xyz   = decode_normal(abnormal.xy);
+
+	float da = dot(norm.xyz, sun_dir.xyz);
+
+    float final_da = da;
+          final_da = min(final_da, shadow);
+          final_da = max(final_da, 0.0f);
+		  final_da = min(final_da, 1.0f);
+		  final_da = pow(final_da, 1.0/1.3);
+
+	vec4 color = vec4(0,0,0,0);
+
+	color.rgb = atmosAmbient(color.rgb);
+	color.a   = final_alpha;
+
+	float ambient = abs(da);
+	ambient *= 0.5;
+	ambient *= ambient;
+	ambient = (1.0-ambient);
+
+	color.rgb *= ambient;
+	color.rgb += atmosAffectDirectionalLight(final_da);
+	color.rgb *= gamma_diff.rgb;
+
+	//color.rgb = mix(diff.rgb, color.rgb, final_alpha);
+
+	color.rgb = atmosLighting(color.rgb);
 	color.rgb = scaleSoftClip(color.rgb);
 
-	color.rgb = pow(color.rgb, vec3(2.2));
-	col = vec4(0,0,0,0);
+	vec4 light = vec4(0,0,0,0);
 
-	
-   #define LIGHT_LOOP(i) col.rgb += light_diffuse[i].rgb * calcPointLightOrSpotLight(pos.xyz, normal, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z);
+	color.rgb = srgb_to_linear(color.rgb);
 
+   #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, diff.rgb, pos.xyz, norm, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z);
+   
 	LIGHT_LOOP(1)
 	LIGHT_LOOP(2)
 	LIGHT_LOOP(3)
@@ -257,9 +609,19 @@ void main()
 	LIGHT_LOOP(6)
 	LIGHT_LOOP(7)
 
-	color.rgb += diff.rgb * pow(vary_pointlight_col, vec3(2.2)) * col.rgb;
+	// keep it linear
+	//
+	color.rgb += light.rgb;
 
-	color.rgb = pow(color.rgb, vec3(1.0/2.2));
+	// straight to display gamma, we're post-deferred
+	//
+	color.rgb = linear_to_srgb(color.rgb);
+
+#ifdef WATER_FOG
+	color = applyWaterFogDeferred(pos.xyz, color);
+#endif
+
+#endif
 
 	frag_color = color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index 9d3ba564cdc4556f18e3ef4a3eed801b48032168..60d414f2ff2c5ecb26fe7dcfbeadffd46c6857ab 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -55,67 +55,18 @@ mat4 getSkinnedTransform();
 #endif
 #endif
 
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
-void calcAtmospherics(vec3 inPositionEye);
-
-vec3 atmosAmbient(vec3 light);
-vec3 atmosAffectDirectionalLight(float lightIntensity);
-vec3 scaleDownLight(vec3 light);
-vec3 scaleUpLight(vec3 light);
-
-VARYING vec3 vary_ambient;
-VARYING vec3 vary_directional;
 VARYING vec3 vary_fragcoord;
 VARYING vec3 vary_position;
-VARYING vec3 vary_pointlight_col;
 
 #ifdef USE_VERTEX_COLOR
 VARYING vec4 vertex_color;
 #endif
 
 VARYING vec2 vary_texcoord0;
-
 VARYING vec3 vary_norm;
 
 uniform float near_clip;
 
-uniform vec4 light_position[8];
-uniform vec3 light_direction[8];
-uniform vec3 light_attenuation[8]; 
-uniform vec3 light_diffuse[8];
-
-uniform vec3 sun_dir;
-
-vec3 calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
-{
-	//get light vector
-	vec3 lv = lp.xyz-v;
-	
-	//get distance
-	float d = dot(lv,lv);
-	
-	float da = 0.0;
-
-	if (d > 0.0 && la > 0.0 && fa > 0.0)
-	{
-		//normalize light vector
-		lv = normalize(lv);
-	
-		//distance attenuation
-		float dist2 = d/la;
-		da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
-
-		// spotlight coefficient.
-		float spot = max(dot(-ln, lv), is_pointlight);
-		da *= spot*spot; // GL_SPOT_EXPONENT=2
-
-		//angular attenuation
-		da *= max(dot(n, lv), 0.0);		
-	}
-
-	return vec3(da,da,da);	
-}
-
 void main()
 {
 	vec4 pos;
@@ -168,43 +119,10 @@ void main()
 	vary_norm = norm;
 	vary_position = pos.xyz;
 
-	calcAtmospherics(pos.xyz);
-
-#ifndef USE_VERTEX_COLOR
-	vec4 diffuse_color = vec4(1,1,1,1);
-#endif
-	//vec4 color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.));
-	vec4 col = vec4(0.0, 0.0, 0.0, diffuse_color.a);
-	
-	vec3 diff = diffuse_color.rgb;
-
-	
-
-	vary_pointlight_col = diff;
-
-	
-	col.rgb = vec3(0,0,0);
-
-	// Add windlight lights
-	col.rgb = atmosAmbient(col.rgb);
-	
-	float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
-	ambient *= 0.5;
-	ambient *= ambient;
-	ambient = (1.0-ambient);
-
-	col.rgb *= ambient;
-
-	vary_ambient = col.rgb*diff.rgb;
-
-	vary_directional.rgb = atmosAffectDirectionalLight(1.0f);
-	
-	col.rgb = col.rgb*diff.rgb;
-	
 #ifdef USE_VERTEX_COLOR
-	vertex_color = col;
+	vertex_color = diffuse_color;
 #endif
-	
+
 #ifdef HAS_SKIN
 	vary_fragcoord.xyz = frag_pos.xyz + vec3(0,0,near_clip);
 #else
@@ -219,4 +137,3 @@ void main()
 #endif
 
 }
-
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
index 968a5f6b3df7fa57f19ca85c8f82eaed96bfb71c..a4f54dff707936918b25b6519b55ba0824ec7dbb 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
@@ -59,22 +59,6 @@ vec4 getPosition(vec2 pos_screen)
 	return pos;
 }
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -91,7 +75,6 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 void main() 
 {
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl
index 59d109b886a6f8a4d9d3c7019e3f5c9353c8428d..8525e13333eaa9fff6c2fd5d90b3655d2ef93b34 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl
@@ -50,7 +50,7 @@ void main()
 	{
 		discard;
 	}
-
+	
 	frag_data[0] = vec4(col.rgb, 0.0);
 	frag_data[1] = vec4(0,0,0,0);
 	vec3 nvn = normalize(vary_normal);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index dc1dead656120b9132133828001af2e5601c638e..f22b16965c471a07f49bbf671a75e1ef7e20a173 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -35,29 +35,143 @@ out vec4 frag_color;
 uniform sampler2D diffuseMap;
 #endif
 
+VARYING vec3 vary_position;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
-vec3 fullbrightAtmosTransport(vec3 light);
-vec3 fullbrightScaleSoftClip(vec3 light);
 
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
+vec3 fullbrightAtmosTransportDeferred(vec3 light)
+{
+	return light;
+}
+
+vec3 fullbrightScaleSoftClipDeferred(vec3 light)
+{
+	//soft clip effect:
+	return light;
+}
+
+#ifdef HAS_ALPHA_MASK
+uniform float minimum_alpha;
+#endif
+
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
 
 void main() 
 {
 #if HAS_DIFFUSE_LOOKUP
-	vec4 color = diffuseLookup(vary_texcoord0.xy)*vertex_color;
+	vec4 color = diffuseLookup(vary_texcoord0.xy);
 #else
-	vec4 color = texture2D(diffuseMap, vary_texcoord0.xy)*vertex_color;
+	vec4 color = texture2D(diffuseMap, vary_texcoord0.xy);
 #endif
 
-	color.rgb = pow(color.rgb,vec3(2.2f,2.2f,2.2f));
-	
-	color.rgb = fullbrightAtmosTransport(color.rgb);
+	float final_alpha = color.a * vertex_color.a;
 
-	color.rgb = fullbrightScaleSoftClip(color.rgb);
+#ifdef HAS_ALPHA_MASK
+	if (color.a < minimum_alpha)
+	{
+		discard;
+	}
+#endif
+
+	color.rgb *= vertex_color.rgb;
+	color.rgb = srgb_to_linear(color.rgb);
+	color.rgb = fullbrightAtmosTransportDeferred(color.rgb);
+	color.rgb = fullbrightScaleSoftClipDeferred(color.rgb);
+	
+	color.rgb = linear_to_srgb(color.rgb);
 
-	color.rgb = pow(color.rgb, vec3(1.0/2.2));
+#ifdef WATER_FOG
+	vec3 pos = vary_position;
+	vec4 fogged = applyWaterFogDeferred(pos, vec4(color.rgb, final_alpha));
+	color.rgb = fogged.rgb;
+	color.a   = fogged.a;
+#else
+	color.a   = final_alpha;
+#endif
 
-	frag_color = color;
+	frag_color.rgb = color.rgb;
+	frag_color.a   = color.a;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
index 3f09a153754d8c24333fed5465fb7ca6f17a880d..8e899e3e0f32df89f36b81531d979ced9b57f534 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
@@ -40,6 +40,9 @@ vec3 atmosAffectDirectionalLight(float lightIntensity);
 vec3 scaleDownLight(vec3 light);
 vec3 scaleUpLight(vec3 light);
 
+#ifdef WATER_FOG
+VARYING vec3 vary_position;
+#endif
 
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
@@ -53,7 +56,11 @@ void main()
 	passTextureIndex();
 
 	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-	
+
+#ifdef WATER_FOG
+	vary_position = pos.xyz;
+#endif
+
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
 	calcAtmospherics(pos.xyz);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
index bc0719cb82de9a8537dc4963fbb4b74175dca768..f8fdde43f9fe80a960de67e7b49d9503914c176d 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/impostorF.glsl
@@ -38,6 +38,42 @@ uniform sampler2D specularMap;
 
 VARYING vec2 vary_texcoord0;
 
+vec3 decode_normal (vec2 enc)
+{
+    vec2 fenc = enc*4-2;
+    float f = dot(fenc,fenc);
+    float g = sqrt(1-f/4);
+    vec3 n;
+    n.xy = fenc*g;
+    n.z = 1-f/2;
+    return n;
+}
+
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 void main() 
 {
 	vec4 col = texture2D(diffuseMap, vary_texcoord0.xy);
@@ -47,7 +83,12 @@ void main()
 		discard;
 	}
 
-	frag_data[0] = vec4(col.rgb, col.a * 0.005);
-	frag_data[1] = texture2D(specularMap, vary_texcoord0.xy);
-	frag_data[2] = vec4(texture2D(normalMap, vary_texcoord0.xy).xyz, 0.0);
+	vec4 norm = texture2D(normalMap,   vary_texcoord0.xy);
+	vec4 spec = texture2D(specularMap, vary_texcoord0.xy);
+
+	col.rgb = linear_to_srgb(col.rgb);
+
+	frag_data[0] = vec4(col.rgb, 0.0);
+	frag_data[1] = spec;
+	frag_data[2] = vec4(norm.xy,0,0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
index 618ea747f58c87d8b724b3da3593decb7222dd96..8202b4978fb893bd8a215b9c74c07bd4725e68df 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -29,6 +29,44 @@
 #define DIFFUSE_ALPHA_MODE_EMISSIVE 3
 
 uniform float emissive_brightness;
+uniform float display_gamma;
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
 
 #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
 
@@ -114,6 +152,52 @@ uniform vec3 light_direction[8];
 uniform vec3 light_attenuation[8]; 
 uniform vec3 light_diffuse[8];
 
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
+
 vec3 calcDirectionalLight(vec3 n, vec3 l)
 {
 	float a = max(dot(n,l),0.0);
@@ -142,7 +226,7 @@ vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spe
 		float dist = d/la;
 		float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
 		dist_atten *= dist_atten;
-		dist_atten *= 1.4;
+		dist_atten *= 2.0;
 
 		// spotlight coefficient.
 		float spot = max(dot(-ln, lv), is_pointlight);
@@ -199,10 +283,13 @@ vec4 getPosition_d(vec2 pos_screen, float depth)
 	return pos;
 }
 
+#ifndef WATER_FOG
 vec3 getPositionEye()
 {
 	return vary_PositionEye;
 }
+#endif
+
 vec3 getSunlitColor()
 {
 	return vary_SunlitColor;
@@ -428,22 +515,6 @@ VARYING vec3 vary_normal;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -460,7 +531,6 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 void main() 
 {
@@ -475,8 +545,8 @@ void main()
 #endif
 
 #if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
-	vec3 old_diffcol = diffcol.rgb;
-	diffcol.rgb = pow(diffcol.rgb, vec3(2.2));
+	vec3 gamma_diff = diffcol.rgb;
+	diffcol.rgb = srgb_to_linear(diffcol.rgb);
 #endif
 
 #if HAS_SPECULAR_MAP
@@ -502,6 +572,9 @@ void main()
     norm.xyz = tnorm;
     norm.xyz = normalize(norm.xyz);
 
+	vec2 abnormal	= encode_normal(norm.xyz);
+		 norm.xyz   = decode_normal(abnormal.xy);
+
 	vec4 final_color = diffcol;
 	
 #if (DIFFUSE_ALPHA_MODE != DIFFUSE_ALPHA_MODE_EMISSIVE)
@@ -597,7 +670,7 @@ void main()
 	vec4 diffuse = final_color;
 	float envIntensity = final_normal.z;
 
-    vec3 col = vec3(0.0f,0.0f,0.0f);
+	vec3 col = vec3(0.0f,0.0f,0.0f);
 
 	float bloom = 0.0;
 	calcAtmospherics(pos.xyz, 1.0);
@@ -605,23 +678,27 @@ void main()
 	vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
 
 	float da =dot(norm.xyz, sun_dir.xyz);
+
     float final_da = da;
           final_da = min(final_da, shadow);
-          final_da = max(final_da, diffuse.a);
+          //final_da = max(final_da, diffuse.a);
           final_da = max(final_da, 0.0f);
+		  final_da = min(final_da, 1.0f);
+		  final_da = pow(final_da, 1.0/1.3);
 
 	col.rgb = atmosAmbient(col);
 	
-	float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
+	float ambient = min(abs(da), 1.0);
 	ambient *= 0.5;
 	ambient *= ambient;
 	ambient = (1.0-ambient);
 
 	col.rgb *= ambient;
 
-	col.rgb = col.rgb + atmosAffectDirectionalLight(pow(final_da, 1.0/1.3));
-	col.rgb *= old_diffcol.rgb;
-	
+	col.rgb = col.rgb + atmosAffectDirectionalLight(final_da);
+
+	col.rgb *= gamma_diff.rgb;
+
 
 	float glare = 0.0;
 
@@ -643,7 +720,8 @@ void main()
 		col += spec_contrib;
 	}
 
-	col = mix(col.rgb, old_diffcol.rgb, diffuse.a);
+
+	col = mix(col.rgb, diffcol.rgb, diffuse.a);
 
 	if (envIntensity > 0.0)
 	{
@@ -661,16 +739,20 @@ void main()
 		glare += cur_glare;
 	}
 
-	col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a);
-	col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a);
+	//col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a);
+	//col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col),  diffuse.a);
 
-	//convert to linear space before adding local lights
-	col = pow(col, vec3(2.2));
+	col = atmosLighting(col);
+	col = scaleSoftClip(col);
 
+	//convert to linear space before adding local lights
+	col = srgb_to_linear(col);
 			
 	vec3 npos = normalize(-pos.xyz);
 
- #define LIGHT_LOOP(i) col.rgb = col.rgb + calcPointLightOrSpotLight(light_diffuse[i].rgb, npos, diffuse.rgb, final_specular, pos.xyz, norm.xyz, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, glare);
+	vec3 light = vec3(0,0,0);
+
+ #define LIGHT_LOOP(i) light.rgb += calcPointLightOrSpotLight(light_diffuse[i].rgb, npos, diffuse.rgb, final_specular, pos.xyz, norm.xyz, light_position[i], light_direction[i].xyz, light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z, glare);
 
 		LIGHT_LOOP(1)
 		LIGHT_LOOP(2)
@@ -680,13 +762,22 @@ void main()
 		LIGHT_LOOP(6)
 		LIGHT_LOOP(7)
 
+	col.rgb += light.rgb;
+
+	glare = min(glare, 1.0);
+	float al = max(diffcol.a,glare)*vertex_color.a;
 
 	//convert to gamma space for display on screen
-	col.rgb = pow(col.rgb, vec3(1.0/2.2));
+	col.rgb = linear_to_srgb(col.rgb);
+
+#ifdef WATER_FOG
+	vec4 temp = applyWaterFogDeferred(pos, vec4(col.rgb, al));
+	col.rgb = temp.rgb;
+	al = temp.a;
+#endif
 
 	frag_color.rgb = col.rgb;
-	glare = min(glare, 1.0);
-	frag_color.a = max(diffcol.a,glare)*vertex_color.a;
+	frag_color.a   = al;
 
 #else
 	frag_data[0] = final_color;
@@ -694,3 +785,4 @@ void main()
 	frag_data[2] = final_normal; // XY = Normal.  Z = Env. intensity.
 #endif
 }
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
index b25032866ba5b7d8a63832a18647f1a9502e36cb..393d1e69da76417d2f2b63f170ac1fff80a13c5f 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
@@ -142,3 +142,4 @@ vary_normal  = n;
 #endif
 #endif
 }
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
index 868526d457eb61e9b22106aec75525ed58b115d5..3ba6de8b764f254473c430abbd8edaa522bb44d8 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -45,9 +45,8 @@ uniform float sun_wash;
 
 uniform int light_count;
 
-#define MAX_LIGHT_COUNT		16
-uniform vec4 light[MAX_LIGHT_COUNT];
-uniform vec4 light_col[MAX_LIGHT_COUNT];
+uniform vec4 light[LIGHT_COUNT];
+uniform vec4 light_col[LIGHT_COUNT];
 
 VARYING vec4 vary_fragcoord;
 uniform vec2 screen_res;
@@ -56,22 +55,6 @@ uniform float far_z;
 
 uniform mat4 inv_proj;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -88,7 +71,6 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 vec4 getPosition(vec2 pos_screen)
 {
@@ -117,78 +99,66 @@ void main()
 	norm = normalize(norm);
 	vec4 spec = texture2DRect(specularRect, frag.xy);
 	vec3 diff = texture2DRect(diffuseRect, frag.xy).rgb;
+	
 	float noise = texture2D(noiseMap, frag.xy/128.0).b;
 	vec3 out_col = vec3(0,0,0);
 	vec3 npos = normalize(-pos);
 
 	// As of OSX 10.6.7 ATI Apple's crash when using a variable size loop
-	for (int i = 0; i < MAX_LIGHT_COUNT; ++i)
+	for (int i = 0; i < LIGHT_COUNT; ++i)
 	{
-		bool light_contrib = (i < light_count);
-		
 		vec3 lv = light[i].xyz-pos;
 		float dist = length(lv);
 		dist /= light[i].w;
-		if (dist > 1.0)
+		if (dist <= 1.0)
 		{
-			light_contrib = false;
-		}
-		
-		float da = dot(norm, lv);
-		if (da < 0.0)
-		{
-			light_contrib = false;
-		}
-		
-		if (light_contrib)
-		{
-			lv = normalize(lv);
-			da = dot(norm, lv);
+			float da = dot(norm, lv);
+			if (da > 0.0)
+			{
+				lv = normalize(lv);
+				da = dot(norm, lv);
 			
-			float fa = light_col[i].a+1.0;
-			float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
-			dist_atten *= dist_atten;
-			dist_atten *= 2.0;
+				float fa = light_col[i].a+1.0;
+				float dist_atten = clamp(1.0-(dist-1.0*(1.0-fa))/fa, 0.0, 1.0);
+				dist_atten *= dist_atten;
+				dist_atten *= 2.0;
 			
-			dist_atten *= noise;
+				dist_atten *= noise;
 
-			float lit = da * dist_atten;
+				float lit = da * dist_atten;
 						
-			vec3 col = light_col[i].rgb*lit*diff;
+				vec3 col = light_col[i].rgb*lit*diff;
 			
-			//vec3 col = vec3(dist2, light_col[i].a, lit);
+				//vec3 col = vec3(dist2, light_col[i].a, lit);
 			
-			if (spec.a > 0.0)
-			{
-				lit = min(da*6.0, 1.0) * dist_atten;
-				//vec3 ref = dot(pos+lv, norm);
-				vec3 h = normalize(lv+npos);
-				float nh = dot(norm, h);
-				float nv = dot(norm, npos);
-				float vh = dot(npos, h);
-				float sa = nh;
-				float fres = pow(1 - dot(h, npos), 5)*0.4+0.5;
-
-				float gtdenom = 2 * nh;
-				float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh));
-								
-				if (nh > 0.0)
+				if (spec.a > 0.0)
 				{
-					float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da);
-					col += lit*scol*light_col[i].rgb*spec.rgb;
-					//col += spec.rgb;
+					lit = min(da*6.0, 1.0) * dist_atten;
+					//vec3 ref = dot(pos+lv, norm);
+					vec3 h = normalize(lv+npos);
+					float nh = dot(norm, h);
+					float nv = dot(norm, npos);
+					float vh = dot(npos, h);
+					float sa = nh;
+					float fres = pow(1 - dot(h, npos), 5)*0.4+0.5;
+
+					float gtdenom = 2 * nh;
+					float gt = max(0, min(gtdenom * nv / vh, gtdenom * da / vh));
+								
+					if (nh > 0.0)
+					{
+						float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da);
+						col += lit*scol*light_col[i].rgb*spec.rgb;
+						//col += spec.rgb;
+					}
 				}
-			}
 			
-			out_col += col;
+				out_col += col;
+			}
 		}
 	}
 	
-	if (dot(out_col, out_col) <= 0.0)
-	{
-		discard;
-	}
-	
+
 	frag_color.rgb = out_col;
 	frag_color.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
index 0443b592e2a2ac29e0bec9879985e875af132494..0e6ab80d4d1f33ace536674d4c9ec353677eb6c2 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
@@ -68,22 +68,6 @@ uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -100,17 +84,48 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
 #endif
 
-vec4 correctWithGamma(vec4 col)
+}
+
+vec3 linear_to_srgb(vec3 cl)
 {
-	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
 }
 
+
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
-	ret = correctWithGamma(ret);
+	ret.rgb = srgb_to_linear(ret.rgb);
 	
 	vec2 dist = tc-vec2(0.5);
 	
@@ -126,7 +141,7 @@ vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
-	ret = correctWithGamma(ret);
+	ret.rgb = srgb_to_linear(ret.rgb);
 	
 	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
 	
@@ -144,7 +159,7 @@ vec4 texture2DLodDiffuse(sampler2D projectionMap, vec2 tc, float lod)
 vec4 texture2DLodAmbient(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
-	ret = correctWithGamma(ret);
+	ret.rgb = srgb_to_linear(ret.rgb);
 	
 	vec2 dist = tc-vec2(0.5);
 	
@@ -296,14 +311,11 @@ void main()
 			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
 			
 			vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
-
+			stc /= stc.w;
 			if (stc.z > 0.0)
 			{
-				stc.xy /= stc.w;
-
-				float fatten = clamp(envIntensity*envIntensity+envIntensity*0.5, 0.25, 1.0);
+				float fatten = clamp(envIntensity*envIntensity+envIntensity*0.25, 0.25, 1.0);
 				
-				//stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
 				stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
 								
 				if (stc.x < 1.0 &&
@@ -311,7 +323,7 @@ void main()
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod-envIntensity*proj_lod).rgb*spec.rgb;										
+					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod).rgb*spec.rgb;										
 				}
 			}
 		}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
index caf20ce707e6b45f5d01f1a1c034e6d3308be014..106d48bd7127064b83b6e75010865359743174b2 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -54,22 +54,6 @@ uniform vec2 screen_res;
 uniform mat4 inv_proj;
 uniform vec4 viewport;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -86,7 +70,6 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 vec4 getPosition(vec2 pos_screen)
 {
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
index 6f2cfae6d2381e416712c2564ab96125dbf0edc8..4e2f98aa29bb6e4fb4dc5255af184a5fcd41b9d6 100644
--- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
@@ -36,11 +36,32 @@ uniform sampler2DRect diffuseRect;
 uniform vec2 screen_res;
 VARYING vec2 vary_fragcoord;
 
-uniform float texture_gamma;
+uniform float display_gamma;
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 
 void main() 
 {
 	vec4 diff = texture2DRect(diffuseRect, vary_fragcoord);
-	frag_color = pow(diff, vec4(texture_gamma, texture_gamma, texture_gamma, 1.0f));
+	diff.rgb = linear_to_srgb(diff.rgb);
+	frag_color = diff;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 58875ff4ead2837ac8c33d336317f5ae7fc67c8a..760d52a9ce47de62351be9eb7905bd54fe591538 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -79,22 +79,43 @@ vec3 vary_AtmosAttenuation;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
+vec3 srgb_to_linear(vec3 cs)
 {
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
 }
 
-vec3 decode_normal (vec2 enc)
+vec3 linear_to_srgb(vec3 cl)
 {
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
 #else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
+
 vec3 decode_normal (vec2 enc)
 {
     vec2 fenc = enc*4-2;
@@ -105,7 +126,6 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 vec4 getPosition_d(vec2 pos_screen, float depth)
 {
@@ -171,6 +191,53 @@ void setAtmosAttenuation(vec3 v)
 	vary_AtmosAttenuation = v;
 }
 
+
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
+
 void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
 
 	vec3 P = inPositionEye;
@@ -325,13 +392,16 @@ void main()
 	float envIntensity = norm.z;
 	norm.xyz = decode_normal(norm.xy); // unpack norm
 		
-	float da = max(dot(norm.xyz, sun_dir.xyz), 0.0);
-	da = pow(da, 1.0/1.3);
+	float da = dot(norm.xyz, sun_dir.xyz);
+
+	float final_da = max(0.0,da);
+          final_da = min(final_da, 1.0f);
+	      final_da = pow(final_da, 1.0/1.3);
 
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
 
 	//convert to gamma space
-	diffuse.rgb = pow(diffuse.rgb, vec3(1.0/2.2));
+	diffuse.rgb = linear_to_srgb(diffuse.rgb);
 
 	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
 	vec3 col;
@@ -347,7 +417,7 @@ void main()
 
 		col.rgb *= ambient;
 
-		col += atmosAffectDirectionalLight(max(min(da, 1.0), 0.0));
+		col += atmosAffectDirectionalLight(final_da);	
 	
 		col *= diffuse.rgb;
 	
@@ -387,13 +457,19 @@ void main()
 			col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a);
 		}
 
-		col = pow(col, vec3(2.2));
+		#ifdef WATER_FOG
+			vec4 fogged = applyWaterFogDeferred(pos,vec4(col, bloom));
+			col = fogged.rgb;
+			bloom = fogged.a;
+		#endif
+
+		col = srgb_to_linear(col);
 
 		//col = vec3(1,0,1);
 		//col.g = envIntensity;
 	}
 
-	frag_color.rgb = col;
-
+	frag_color.rgb = col.rgb;
 	frag_color.a = bloom;
 }
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
index 28432dac9aa7fc202292fdedce6bcf8835388df0..2020e8691bdbf6615d7b3e1275dd6380d5464487 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
@@ -22,7 +22,7 @@
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
-
+ 
 #extension GL_ARB_texture_rectangle : enable
 #extension GL_ARB_shader_texture_lod : enable
 
@@ -68,22 +68,6 @@ uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -100,11 +84,47 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
 #endif
 
+}
+
 vec4 correctWithGamma(vec4 col)
 {
-	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+	return vec4(srgb_to_linear(col.rgb), col.a);
 }
 
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
diff --git a/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl b/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..587f3d5a944587f4166b94b9a68eefff0464d6d5
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/srgb.glsl
@@ -0,0 +1,46 @@
+/** 
+ * @file srgb.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+	return mix(high_range, low_range, lte);
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+	return mix(high_range, low_range, lt);
+
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl b/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..6cc1e6e798d64c31268cac2f4c24a61f7f19cf6c
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/srgb_mac.glsl
@@ -0,0 +1,54 @@
+/** 
+ * @file srgb.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+	return result;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
index 6653f57ee17f083f7c56a8a957aa626005c366ea..c0a5865bef2f50a64a890567d5cd3e91f154a9cc 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
@@ -49,22 +49,6 @@ VARYING vec2 vary_fragcoord;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -81,7 +65,6 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 vec4 getPosition(vec2 pos_screen)
 {
diff --git a/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..78f841c73314ece6b65658efcf9701700339ea87
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/underWaterF.glsl
@@ -0,0 +1,157 @@
+/**
+ * @file underWaterF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2007, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+ 
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_data[3];
+#else
+#define frag_data gl_FragData
+#endif
+
+uniform sampler2D diffuseMap;
+uniform sampler2D bumpMap;   
+uniform sampler2D screenTex;
+uniform sampler2D refTex;
+uniform sampler2D screenDepth;
+
+uniform vec4 fogCol;
+uniform vec3 lightDir;
+uniform vec3 specular;
+uniform float lightExp;
+uniform vec2 fbScale;
+uniform float refScale;
+uniform float znear;
+uniform float zfar;
+uniform float kd;
+uniform vec4 waterPlane;
+uniform vec3 eyeVec;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+uniform vec2 screenRes;
+
+//bigWave is (refCoord.w, view.w);
+VARYING vec4 refCoord;
+VARYING vec4 littleWave;
+VARYING vec4 view;
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
+vec4 applyWaterFog(vec4 color, vec3 viewVec)
+{
+	//normalize view vector
+	vec3 view = normalize(viewVec);
+	float es = -view.z;
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	//get object depth
+	float depth = length(viewVec);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	//return vec4(1.0, 0.0, 1.0, 1.0);
+	return color * D + kc * L;
+	//depth /= 10.0;
+	//return vec4(depth,depth,depth,0.0);
+}
+
+void main() 
+{
+	vec4 color;
+	    
+	//get detail normals
+	vec3 wave1 = texture2D(bumpMap, vec2(refCoord.w, view.w)).xyz*2.0-1.0;
+	vec3 wave2 = texture2D(bumpMap, littleWave.xy).xyz*2.0-1.0;
+	vec3 wave3 = texture2D(bumpMap, littleWave.zw).xyz*2.0-1.0;    
+	vec3 wavef = normalize(wave1+wave2+wave3);
+	
+	//figure out distortion vector (ripply)   
+	vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5;
+	distort = distort+wavef.xy*refScale;
+		
+	vec4 fb = texture2D(screenTex, distort);
+
+	frag_data[0] = vec4(linear_to_srgb(fb.rgb), 1.0); // diffuse
+	frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec
+	frag_data[2] = vec4(encode_normal(wavef), 0.0, 0.0); // normalxyz, displace
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
index daa2fb390adb3ae4cd58689a9482ef93912ae2b3..72c46e240de72815238d8c64fa3b8b3bf6af6d18 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
@@ -67,6 +67,43 @@ VARYING vec4 littleWave;
 VARYING vec4 view;
 VARYING vec4 vary_position;
 
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -121,7 +158,7 @@ void main()
 	refcol *= df1 * 0.333;
 	
 	vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5;
-	//wavef.z *= max(-viewVec.z, 0.1);
+	wavef.z *= max(-viewVec.z, 0.1);
 	wavef = normalize(wavef);
 	
 	float df2 = dot(viewVec, wavef) * fresnelScale+fresnelOffset;
@@ -131,13 +168,14 @@ void main()
 	vec2 refvec4 = distort+refdistort4/dmod;
 	float dweight = min(dist2*blurMultiplier, 1.0);
 	vec4 baseCol = texture2D(refTex, refvec4);
+
 	refcol = mix(baseCol*df2, refcol, dweight);
 
 	//get specular component
-	//float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0);
+	float spec = clamp(dot(lightDir, (reflect(viewVec,wavef))),0.0,1.0);
 		
 	//harden specular
-	//spec = pow(spec, 128.0);
+	spec = pow(spec, 128.0);
 
 	//figure out distortion vector (ripply)   
 	vec2 distort2 = distort+wavef.xy*refScale/max(dmod*df1, 1.0);
@@ -148,24 +186,17 @@ void main()
 	// Note we actually want to use just df1, but multiplying by 0.999999 gets around an nvidia compiler bug
 	color.rgb = mix(fb.rgb, refcol.rgb, df1 * 0.99999);
 	
-	float shadow = 1.0;
 	vec4 pos = vary_position;
-	
-	//vec3 nz = texture2D(noiseMap, gl_FragCoord.xy/128.0).xyz;
-	vec4 spos = pos;
 		
-	//spec *= shadow;
-	//color.rgb += spec * specular;
-	
+	color.rgb += spec * specular;
+
 	color.rgb = atmosTransport(color.rgb);
 	color.rgb = scaleSoftClip(color.rgb);
-	//color.a = spec * sunAngle2;
+	color.a   = spec * sunAngle2;
 
-	//wavef.z *= 0.1f;
-	//wavef = normalize(wavef);
-	vec3 screenspacewavef = (norm_mat*vec4(wavef, 1.0)).xyz;
+	vec3 screenspacewavef = normalize((norm_mat*vec4(wavef, 1.0)).xyz);
 	
-	frag_data[0] = vec4(color.rgb, 0.5); // diffuse
-	frag_data[1] = vec4(0.5,0.5,0.5, 0.95); // speccolor*spec, spec
-	frag_data[2] = vec4(encode_normal(screenspacewavef), 0.0, 0.0); // normalxyz, displace
+	frag_data[0] = vec4(color.rgb, color); // diffuse
+	frag_data[1] = vec4(0);		// speccolor, spec
+	frag_data[2] = vec4(encode_normal(screenspacewavef.xyz*0.5+0.5), 0.05, 0);// normalxy, 0, 0
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
index ece34dcc4edd96efb98617a203386be6517789d5..9734acf005a372378eff057667cb4bfea6033210 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterV.glsl
@@ -85,7 +85,7 @@ void main()
 	pos.w = 1.0;
 	pos = modelview_matrix*pos;
 	
-	calcAtmospherics(view.xyz);
+	calcAtmospherics(pos.xyz);
 		
 	//pass wave parameters to pixel shader
 	vec2 bigWave =  (v.xy) * vec2(0.04,0.04)  + d1 * time * 0.055;
diff --git a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl
index 6523a06d22b6259945e24251c7c8b73fecfba192..f8efd7cb4ae2bbc881def496a9cf58ef08a0ba0b 100644
--- a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl
@@ -31,8 +31,6 @@ out vec4 frag_color;
 
 uniform sampler2D depthMap;
 
-uniform float delta;
-
 VARYING vec2 tc0;
 VARYING vec2 tc1;
 VARYING vec2 tc2;
diff --git a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl
index 0e5dc0818363afffa65038762f0ca726ce3d7069..942c5888e753e2d406a1d0e993f1f4a822aa693c 100644
--- a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl
+++ b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl
@@ -33,8 +33,6 @@ out vec4 frag_color;
 
 uniform sampler2DRect depthMap;
 
-uniform float delta;
-
 VARYING vec2 tc0;
 VARYING vec2 tc1;
 VARYING vec2 tc2;
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl
index eaaa7b208d78773f996106c197687705d936d3fe..cad5b9ff043b63d417eb5870a2f1fab88782d9f3 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl
@@ -41,13 +41,13 @@ void default_lighting()
 {
 	vec4 color = diffuseLookup(vary_texcoord0.xy);
 	
+	color *= vertex_color;
+
 	if (color.a < minimum_alpha)
 	{
 		discard;
 	}
 
-	color.rgb *= vertex_color.rgb;
-
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
deleted file mode 100755
index 13c6ffc607c323c78ca08f6651e71c8ff026a3cf..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
+++ /dev/null
@@ -1,224 +0,0 @@
-/** 
- * @file alphaV.glsl
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2007, Linden Research, Inc.
- * 
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- * 
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- * 
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
- * 
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
- * $/LicenseInfo$
- */
-
-uniform mat3 normal_matrix;
-uniform mat4 texture_matrix0;
-uniform mat4 projection_matrix;
-uniform mat4 modelview_matrix;
-uniform mat4 modelview_projection_matrix;
-
-ATTRIBUTE vec3 position;
-
-#ifdef USE_INDEXED_TEX
-void passTextureIndex();
-#endif
-
-ATTRIBUTE vec3 normal;
-
-#ifdef USE_VERTEX_COLOR
-ATTRIBUTE vec4 diffuse_color;
-#endif
-
-ATTRIBUTE vec2 texcoord0;
-
-#ifdef HAS_SKIN
-mat4 getObjectSkinnedTransform();
-#else
-#ifdef IS_AVATAR_SKIN
-mat4 getSkinnedTransform();
-#endif
-#endif
-
-vec4 calcLighting(vec3 pos, vec3 norm, vec4 color, vec4 baseCol);
-void calcAtmospherics(vec3 inPositionEye);
-
-vec3 calcDirectionalLight(vec3 n, vec3 l);
-
-vec3 atmosAmbient(vec3 light);
-vec3 atmosAffectDirectionalLight(float lightIntensity);
-vec3 scaleDownLight(vec3 light);
-vec3 scaleUpLight(vec3 light);
-
-VARYING vec3 vary_ambient;
-VARYING vec3 vary_directional;
-VARYING vec3 vary_fragcoord;
-VARYING vec3 vary_position;
-VARYING vec3 vary_pointlight_col;
-
-#ifdef USE_VERTEX_COLOR
-VARYING vec4 vertex_color;
-#endif
-
-VARYING vec2 vary_texcoord0;
-VARYING vec3 vary_norm;
-
-uniform float near_clip;
-uniform float shadow_offset;
-uniform float shadow_bias;
-
-uniform vec4 light_position[8];
-uniform vec3 light_direction[8];
-uniform vec3 light_attenuation[8]; 
-uniform vec3 light_diffuse[8];
-
-uniform vec3 sun_dir;
-
-vec3 calcDirectionalLight(vec3 n, vec3 l)
-{
-        float a = max(dot(n,l),0.0);
-        return vec3(a,a,a);
-}
-
-vec3 calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
-{
-	//get light vector
-	vec3 lv = lp.xyz-v;
-	
-	//get distance
-	float d = dot(lv,lv);
-	
-	float da = 0.0;
-
-	if (d > 0.0 && la > 0.0 && fa > 0.0)
-	{
-		//normalize light vector
-		lv = normalize(lv);
-	
-		//distance attenuation
-		float dist2 = d/la;
-		da = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
-
-		// spotlight coefficient.
-		float spot = max(dot(-ln, lv), is_pointlight);
-		da *= spot*spot; // GL_SPOT_EXPONENT=2
-
-		//angular attenuation
-		da *= max(dot(n, lv), 0.0);		
-	}
-
-	return vec3(da,da,da);	
-}
-
-void main()
-{
-	vec4 pos;
-	vec3 norm;
-	
-	//transform vertex
-#ifdef HAS_SKIN
-	mat4 trans = getObjectSkinnedTransform();
-	trans = modelview_matrix * trans;
-	
-	pos = trans * vec4(position.xyz, 1.0);
-	
-	norm = position.xyz + normal.xyz;
-	norm = normalize((trans * vec4(norm, 1.0)).xyz - pos.xyz);
-	vec4 frag_pos = projection_matrix * pos;
-	gl_Position = frag_pos;
-#else
-
-#ifdef IS_AVATAR_SKIN
-	mat4 trans = getSkinnedTransform();
-	vec4 pos_in = vec4(position.xyz, 1.0);
-	pos.x = dot(trans[0], pos_in);
-	pos.y = dot(trans[1], pos_in);
-	pos.z = dot(trans[2], pos_in);
-	pos.w = 1.0;
-	
-	norm.x = dot(trans[0].xyz, normal);
-	norm.y = dot(trans[1].xyz, normal);
-	norm.z = dot(trans[2].xyz, normal);
-	norm = normalize(norm);
-	
-	vec4 frag_pos = projection_matrix * pos;
-	gl_Position = frag_pos;
-#else
-	norm = normalize(normal_matrix * normal);
-	vec4 vert = vec4(position.xyz, 1.0);
-	pos = (modelview_matrix * vert);
-	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
-#endif
-	
-#endif
-
-#ifdef USE_INDEXED_TEX
-	passTextureIndex();
-	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
-#else
-	vary_texcoord0 = texcoord0;
-#endif
-	
-	vary_norm = norm;
-	float dp_directional_light = max(0.0, dot(norm, light_position[0].xyz));
-	vary_position = pos.xyz + light_position[0].xyz * (1.0-dp_directional_light)*shadow_offset;
-	
-	calcAtmospherics(pos.xyz);
-
-#ifndef USE_VERTEX_COLOR
-	vec4 diffuse_color = vec4(1,1,1,1);
-#endif
-
-	//vec4 color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.));
-	vec4 col = vec4(0.0, 0.0, 0.0, diffuse_color.a);
-
-	vec3 dff = pow(diffuse_color.rgb, vec3(2.2f,2.2f,2.2f));
-
-	vary_pointlight_col = dff;
-
-	col.rgb = vec3(0,0,0);
-
-	// Add windlight lights
-	col.rgb = atmosAmbient(col.rgb);
-	
-	float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
-	ambient *= 0.5;
-	ambient *= ambient;
-	ambient = (1.0-ambient);
-
-	col.rgb *= ambient;
-
-	vary_directional.rgb = atmosAffectDirectionalLight(1.0f);
-	vary_ambient = col.rgb*dff;
-	
-	col.rgb = col.rgb*dff;
-	
-#ifdef USE_VERTEX_COLOR
-	vertex_color = col;
-#endif
-	
-#ifdef HAS_SKIN
-	vary_fragcoord.xyz = frag_pos.xyz + vec3(0,0,near_clip);
-#else
-
-#ifdef IS_AVATAR_SKIN
-	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
-#else
-	pos = modelview_projection_matrix * vert;
-	vary_fragcoord.xyz = pos.xyz + vec3(0,0,near_clip);
-#endif
-
-#endif
-
-}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
index 37179c7e1423e41340f08a37d8f15c4310559a30..c20e00163c64ed1649d48fabb88a269baabb7e99 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
@@ -69,22 +69,43 @@ uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
+vec3 srgb_to_linear(vec3 cs)
 {
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
 }
 
-vec3 decode_normal (vec2 enc)
+vec3 linear_to_srgb(vec3 cl)
 {
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
 #else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -101,14 +122,12 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 vec4 correctWithGamma(vec4 col)
 {
-	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+	return vec4(srgb_to_linear(col.rgb), col.a);
 }
 
-
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
@@ -315,14 +334,12 @@ void main()
 			vec3 pfinal = pos + ref * dot(pdelta, proj_n)/ds;
 			
 			vec4 stc = (proj_mat * vec4(pfinal.xyz, 1.0));
+			stc /= stc.w;
 
 			if (stc.z > 0.0)
 			{
-				stc.xy /= stc.w;
+				float fatten = clamp(envIntensity*envIntensity+envIntensity*0.25, 0.25, 1.0);
 
-				float fatten = clamp(envIntensity*envIntensity+envIntensity*0.5, 0.25, 1.0);
-				
-				//stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
 				stc.xy = (stc.xy - vec2(0.5)) * fatten + vec2(0.5);
 								
 				if (stc.x < 1.0 &&
@@ -330,12 +347,16 @@ void main()
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod-envIntensity*proj_lod).rgb*shadow*spec.rgb;										
+					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod).rgb*shadow*spec.rgb;										
 				}
 			}
 		}
 	}
 	
+
+	//not sure why, but this line prevents MATBUG-194
+	col = max(col, vec3(0.0));
+
 	frag_color.rgb = col;	
 	frag_color.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 67bac1f7c2e42079d9ddfa9a5bc932bf20d3fa6a..cc34285d65f2745deb2b73e737821ca432f7632e 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -78,22 +78,43 @@ vec3 vary_AtmosAttenuation;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
+vec3 srgb_to_linear(vec3 cs)
 {
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
 }
 
-vec3 decode_normal (vec2 enc)
+vec3 linear_to_srgb(vec3 cl)
 {
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
 #else
+	return mix(high_range, low_range, lt);
+#endif
+
+}
+
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -110,7 +131,6 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 vec4 getPosition_d(vec2 pos_screen, float depth)
 {
@@ -263,6 +283,52 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
 	setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1));
 }
 
+#ifdef WATER_FOG
+uniform vec4 waterPlane;
+uniform vec4 waterFogColor;
+uniform float waterFogDensity;
+uniform float waterFogKS;
+
+vec4 applyWaterFogDeferred(vec3 pos, vec4 color)
+{
+	//normalize view vector
+	vec3 view = normalize(pos);
+	float es = -(dot(view, waterPlane.xyz));
+
+	//find intersection point with water plane and eye vector
+	
+	//get eye depth
+	float e0 = max(-waterPlane.w, 0.0);
+	
+	vec3 int_v = waterPlane.w > 0.0 ? view * waterPlane.w/es : vec3(0.0, 0.0, 0.0);
+	
+	//get object depth
+	float depth = length(pos - int_v);
+		
+	//get "thickness" of water
+	float l = max(depth, 0.1);
+
+	float kd = waterFogDensity;
+	float ks = waterFogKS;
+	vec4 kc = waterFogColor;
+	
+	float F = 0.98;
+	
+	float t1 = -kd * pow(F, ks * e0);
+	float t2 = kd + ks * es;
+	float t3 = pow(F, t2*l) - 1.0;
+	
+	float L = min(t1/t2*t3, 1.0);
+	
+	float D = pow(0.98, l*kd);
+	
+	color.rgb = color.rgb * D + kc.rgb * L;
+	color.a = kc.a + color.a;
+	
+	return color;
+}
+#endif
+
 vec3 atmosLighting(vec3 light)
 {
 	light *= getAtmosAttenuation().r;
@@ -343,7 +409,7 @@ void main()
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
 
 	//convert to gamma space
-	diffuse.rgb = pow(diffuse.rgb, vec3(1.0/2.2));
+	diffuse.rgb = linear_to_srgb(diffuse.rgb);
 	
 	vec3 col;
 	float bloom = 0.0;
@@ -402,19 +468,25 @@ void main()
 				envIntensity);  
 
 		}
-						
+	
 		if (norm.w < 0.5)
 		{
 			col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a);
 			col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a);
 		}
 
-		col = pow(col, vec3(2.2));
+		#ifdef WATER_FOG
+			vec4 fogged = applyWaterFogDeferred(pos,vec4(col, bloom));
+			col = fogged.rgb;
+			bloom = fogged.a;
+		#endif
+
+		col = srgb_to_linear(col);
 
 		//col = vec3(1,0,1);
 		//col.g = envIntensity;
 	}
-	
+
 	frag_color.rgb = col;
 	frag_color.a = bloom;
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
index 9bdee15541aa6fcb3f0b80ac7539e63c3d29bcca..7689b72d202a72ad343b4f1895ca0deb8d454c6b 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
@@ -69,22 +69,6 @@ uniform vec2 screen_res;
 
 uniform mat4 inv_proj;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -101,11 +85,47 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
+
+vec3 srgb_to_linear(vec3 cs)
+{
+	vec3 low_range = cs / vec3(12.92);
+	vec3 high_range = pow((cs+vec3(0.055))/vec3(1.055), vec3(2.4));
+	bvec3 lte = lessThanEqual(cs,vec3(0.04045));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lte.r ? low_range.r : high_range.r;
+	result.g = lte.g ? low_range.g : high_range.g;
+	result.b = lte.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lte);
+#endif
+
+}
+
+vec3 linear_to_srgb(vec3 cl)
+{
+	cl = clamp(cl, vec3(0), vec3(1));
+	vec3 low_range  = cl * 12.92;
+	vec3 high_range = 1.055 * pow(cl, vec3(0.41666)) - 0.055;
+	bvec3 lt = lessThan(cl,vec3(0.0031308));
+
+#ifdef OLD_SELECT
+	vec3 result;
+	result.r = lt.r ? low_range.r : high_range.r;
+	result.g = lt.g ? low_range.g : high_range.g;
+	result.b = lt.b ? low_range.b : high_range.b;
+    return result;
+#else
+	return mix(high_range, low_range, lt);
 #endif
 
+}
+
 vec4 correctWithGamma(vec4 col)
 {
-	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+	return vec4(srgb_to_linear(col.rgb), col.a);
 }
 
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
@@ -334,6 +354,9 @@ void main()
 		}
 	}
 	
+	//not sure why, but this line prevents MATBUG-194
+	col = max(col, vec3(0.0));
+
 	frag_color.rgb = col;	
 	frag_color.a = 0.0;
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
index 7b09dd29ddec1029163a47badfd5c8afb5335380..95c09d3238e1a338a4bd398ab27c7188f0a66dda 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
@@ -65,22 +65,6 @@ uniform float shadow_offset;
 uniform float spot_shadow_bias;
 uniform float spot_shadow_offset;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -97,7 +81,6 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 vec4 getPosition(vec2 pos_screen)
 {
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
index 01e34ed792547cc994992145db801e27abf3db2a..b5ff6404ea5648f6a219cba4d698952b2c7201f9 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
@@ -66,22 +66,6 @@ uniform float shadow_offset;
 uniform float spot_shadow_bias;
 uniform float spot_shadow_offset;
 
-#ifdef SINGLE_FP_ONLY
-vec2 encode_normal(vec3 n)
-{
-	vec2 sn;
-	sn.xy = (n.xy * vec2(0.5f,0.5f)) + vec2(0.5f,0.5f);
-	return sn;
-}
-
-vec3 decode_normal (vec2 enc)
-{
-	vec3 n;
-	n.xy = (enc.xy * vec2(2.0f,2.0f)) - vec2(1.0f,1.0f);
-	n.z = sqrt(1.0f - dot(n.xy,n.xy));
-	return n;
-}
-#else
 vec2 encode_normal(vec3 n)
 {
 	float f = sqrt(8 * n.z + 8);
@@ -98,7 +82,6 @@ vec3 decode_normal (vec2 enc)
     n.z = 1-f/2;
     return n;
 }
-#endif
 
 vec4 getPosition(vec2 pos_screen)
 {
diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt
index 1c0d45c11badc7023bc45c7ab289ddb3a4409246..0bdd42550474aefa3d931362b65efbea7276ceb3 100755
--- a/indra/newview/featuretable_mac.txt
+++ b/indra/newview/featuretable_mac.txt
@@ -309,8 +309,8 @@ RenderVolumeLODFactor		1	2.0
 VertexShaderEnable			1	1
 WindLightUseAtmosShaders	1	1
 WLSkyDetail					1	128
-RenderDeferred				1	0
-RenderDeferredSSAO			1	0
+RenderDeferred				1	1
+RenderDeferredSSAO			1	1
 RenderShadowDetail			1	2
 RenderFSAASamples			1	2
 
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 8c9fd4152aa1af6f5edfadb42801c1c7a79fe934..9682f3822738e6c79a87d042dea694f6d4f7298f 100755
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -132,10 +132,16 @@ void LLDrawable::destroy()
 		sNumZombieDrawables--;
 	}
 
+	// Attempt to catch violations of this in debug,
+	// knowing that some false alarms may result
+	//
+	llassert(!LLSpatialGroup::sNoDelete);
+
+	/* cannot be guaranteed and causes crashes on false alarms
 	if (LLSpatialGroup::sNoDelete)
 	{
 		llerrs << "Illegal deletion of LLDrawable!" << llendl;
-	}
+	}*/
 
 	std::for_each(mFaces.begin(), mFaces.end(), DeletePointer());
 	mFaces.clear();
@@ -527,6 +533,8 @@ void LLDrawable::makeStatic(BOOL warning_enabled)
 		}
 		updatePartition();
 	}
+
+	llassert(isAvatar() || isRoot() || mParent->isStatic());
 }
 
 // Returns "distance" between target destination and resulting xfrom
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index c832e1401da8076bd92b2a6b484d6a46427a1384..e4ebfea665f72de79bf567e14d389aa5426049be 100755
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -93,15 +93,35 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 
 	if (pass == 0)
 	{
+		if (LLPipeline::sImpostorRender)
+		{
+			simple_shader = &gDeferredAlphaImpostorProgram;
+			fullbright_shader = &gDeferredFullbrightProgram;
+		}
+		else if (LLPipeline::sUnderWaterRender)
+		{
+			simple_shader = &gDeferredAlphaWaterProgram;
+			fullbright_shader = &gDeferredFullbrightWaterProgram;
+		}
+		else
+		{
 		simple_shader = &gDeferredAlphaProgram;
-		fullbright_shader = &gObjectFullbrightProgram;
+			fullbright_shader = &gDeferredFullbrightProgram;
+		}
+		
+		F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+
 		fullbright_shader->bind();
 		fullbright_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); 
+		fullbright_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
 		fullbright_shader->unbind();
+
 		//prime simple shader (loads shadow relevant uniforms)
 		gPipeline.bindDeferredShader(*simple_shader);
+
+		simple_shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
 	}
-	else
+	else if (!LLPipeline::sImpostorRender)
 	{
 		//update depth buffer sampler
 		gPipeline.mScreen.flush();
@@ -113,6 +133,23 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 		gObjectFullbrightAlphaMaskProgram.setMinimumAlpha(0.33f);
 	}
 
+
+    if (LLPipeline::sRenderDeferred)
+    {
+		emissive_shader = &gDeferredEmissiveProgram;
+    }
+    else
+    {
+		if (LLPipeline::sUnderWaterRender)
+		{
+			emissive_shader = &gObjectEmissiveWaterProgram;
+		}
+		else
+		{
+			emissive_shader = &gObjectEmissiveProgram;
+		}
+    }
+
 	deferred_render = TRUE;
 	if (mVertexShaderLevel > 0)
 	{
@@ -124,7 +161,7 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 
 void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) 
 { 
-	if (pass == 1)
+	if (pass == 1 && !LLPipeline::sImpostorRender)
 	{
 		gPipeline.mDeferredDepth.flush();
 		gPipeline.mScreen.bindTarget();
@@ -144,7 +181,13 @@ void LLDrawPoolAlpha::beginRenderPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_ALPHA);
 	
-	if (LLPipeline::sUnderWaterRender)
+	if (LLPipeline::sImpostorRender)
+	{
+		simple_shader = &gObjectSimpleImpostorProgram;
+		fullbright_shader = &gObjectFullbrightProgram;
+		emissive_shader = &gObjectEmissiveProgram;
+	}
+	else if (LLPipeline::sUnderWaterRender)
 	{
 		simple_shader = &gObjectSimpleWaterProgram;
 		fullbright_shader = &gObjectFullbrightWaterProgram;
@@ -192,8 +235,13 @@ void LLDrawPoolAlpha::render(S32 pass)
 		gGL.setColorMask(true, true);
 	}
 	
-	LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy || 
-				(deferred_render && pass == 1) ? GL_TRUE : GL_FALSE);
+	bool write_depth = LLDrawPoolWater::sSkipScreenCopy
+						 || (deferred_render && pass == 1)
+						 // we want depth written so that rendered alpha will
+						 // contribute to the alpha mask used for impostors
+						 || LLPipeline::sImpostorRenderAlphaDepthPass;
+
+	LLGLDepthTest depth(GL_TRUE, write_depth ? GL_TRUE : GL_FALSE);
 
 	if (deferred_render && pass == 1)
 	{
@@ -239,11 +287,11 @@ void LLDrawPoolAlpha::render(S32 pass)
 
 	if (mVertexShaderLevel > 0)
 	{
-		renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
+		renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, pass);
 	}
 	else
 	{
-		renderAlpha(getVertexDataMask());
+		renderAlpha(getVertexDataMask(), pass);
 	}
 
 	gGL.setColorMask(true, false);
@@ -315,7 +363,7 @@ void LLDrawPoolAlpha::renderAlphaHighlight(U32 mask)
 	}
 }
 
-void LLDrawPoolAlpha::renderAlpha(U32 mask)
+void LLDrawPoolAlpha::renderAlpha(U32 mask, S32 pass)
 {
 	BOOL initialized_lighting = FALSE;
 	BOOL light_enabled = TRUE;
@@ -348,11 +396,28 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					continue;
 				}
 
+				// Fix for bug - NORSPEC-271
+				// If the face is more than 90% transparent, then don't update the Depth buffer for Dof
+				// We don't want the nearly invisible objects to cause of DoF effects
+				if(pass == 1 && !LLPipeline::sImpostorRender)
+				{
+					LLFace*	face = params.mFace;
+					if(face)
+					{
+						const LLTextureEntry* tep = face->getTextureEntry();
+						if(tep)
+						{
+							if(tep->getColor().mV[3] < 0.1f)
+								continue;
+						}
+					}
+				}
+
 				LLRenderPass::applyModelMatrix(params);
 				
 				LLMaterial* mat = NULL;
 
-				if (deferred_render && !LLPipeline::sUnderWaterRender)
+				if (deferred_render)
 				{
 					mat = params.mMaterial;
 				}
@@ -396,6 +461,11 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					llassert(mask < LLMaterial::SHADER_COUNT);
 					target_shader = &(gDeferredMaterialProgram[mask]);
 
+					if (LLPipeline::sUnderWaterRender)
+					{
+						target_shader = &(gDeferredMaterialWaterProgram[mask]);
+					}
+
 					if (current_shader != target_shader)
 					{
 						gPipeline.bindDeferredShader(*target_shader);
@@ -500,7 +570,8 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					}
 				}
 
-				params.mVertexBuffer->setBuffer(mask);
+				params.mVertexBuffer->setBuffer(mask & ~(params.mFullbright ? (LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2) : 0));
+                
 				params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
 				gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
 				
@@ -515,7 +586,6 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 
 					emissive_shader->bind();
 					
-					// glow doesn't use vertex colors from the mesh data
 					params.mVertexBuffer->setBuffer((mask & ~LLVertexBuffer::MAP_COLOR) | LLVertexBuffer::MAP_EMISSIVE);
 					
 					// do the actual drawing, again
@@ -545,3 +615,4 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 		gPipeline.enableLightsDynamic();
 	}
 }
+
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index 43122218edadba815be0945cf5911beeb18fd27d..d064a3a324b7522c97b395d86c4e48b125292ec4 100755
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -63,7 +63,7 @@ class LLDrawPoolAlpha: public LLRenderPass
 	/*virtual*/ void prerender();
 
 	void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
-	void renderAlpha(U32 mask);
+	void renderAlpha(U32 mask, S32 pass);
 	void renderAlphaHighlight(U32 mask);
 		
 	static BOOL sShowDebugAlpha;
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index a0024a231c95831909063235be5d16e92118c80c..66bbc6819b4fe6737bcebcb362ae41e01757229f 100755
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -49,6 +49,7 @@
 #include "llappviewer.h"
 #include "llrendersphere.h"
 #include "llviewerpartsim.h"
+#include "llviewercontrol.h" // for gSavedSettings
 
 static U32 sDataMask = LLDrawPoolAvatar::VERTEX_DATA_MASK;
 static U32 sBufferUsage = GL_STREAM_DRAW_ARB;
@@ -309,6 +310,11 @@ void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
 
 	sVertexProgram = &gDeferredMaterialProgram[pass];
 
+	if (LLPipeline::sUnderWaterRender)
+	{
+		sVertexProgram = &(gDeferredMaterialWaterProgram[pass]);
+	}
+
 	gPipeline.bindDeferredShader(*sVertexProgram);
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
 	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
@@ -501,7 +507,7 @@ S32 LLDrawPoolAvatar::getNumDeferredPasses()
 {
 	if (LLPipeline::sImpostorRender)
 	{
-		return 3;
+		return 19;
 	}
 	else
 	{
@@ -687,12 +693,10 @@ void LLDrawPoolAvatar::beginDeferredImpostor()
 	}
 
 	sVertexProgram = &gDeferredImpostorProgram;
-
 	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
 	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
 	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-
-	sVertexProgram->bind();
+	gPipeline.bindDeferredShader(*sVertexProgram);
 	sVertexProgram->setMinimumAlpha(0.01f);
 }
 
@@ -702,8 +706,9 @@ void LLDrawPoolAvatar::endDeferredImpostor()
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL);
 	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
 	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
-	sVertexProgram->unbind();
-	gGL.getTexUnit(0)->activate();
+	gPipeline.unbindDeferredShader(*sVertexProgram);
+   sVertexProgram = NULL;
+   sDiffuseChannel = 0;
 }
 
 void LLDrawPoolAvatar::beginDeferredRigid()
@@ -891,6 +896,8 @@ void LLDrawPoolAvatar::beginRiggedGlow()
 		sVertexProgram->bind();
 
 		sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, LLPipeline::sRenderDeferred ? 2.2f : 1.1f);
+		F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+		sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
 	}
 }
 
@@ -943,6 +950,9 @@ void LLDrawPoolAvatar::beginRiggedFullbright()
 		else 
 		{
 			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+
+			F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+			sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
 		}
 	}
 }
@@ -1044,6 +1054,8 @@ void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
 		else 
 		{
 			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+			F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+			sVertexProgram->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
 		}
 	}
 }
@@ -1103,6 +1115,12 @@ void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
 		return;
 	}
 	sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT];
+
+	if (LLPipeline::sUnderWaterRender)
+	{
+		sVertexProgram = &(gDeferredMaterialWaterProgram[pass+LLMaterial::SHADER_COUNT]);
+	}
+
 	sVertexProgram->bind();
 	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
 	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
@@ -1445,63 +1463,63 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 }
 
 void LLDrawPoolAvatar::getRiggedGeometry(LLFace* face, LLPointer<LLVertexBuffer>& buffer, U32 data_mask, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
-{
-	face->setGeomIndex(0);
-	face->setIndicesIndex(0);
+	{
+		face->setGeomIndex(0);
+		face->setIndicesIndex(0);
 		
-	//rigged faces do not batch textures
-	face->setTextureIndex(255);
+		//rigged faces do not batch textures
+		face->setTextureIndex(255);
 
-	if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable())
-	{ //make a new buffer
-		if (sShaderLevel > 0)
-		{
-			buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB);
+		if (buffer.isNull() || buffer->getTypeMask() != data_mask || !buffer->isWriteable())
+		{ //make a new buffer
+			if (sShaderLevel > 0)
+			{
+				buffer = new LLVertexBuffer(data_mask, GL_DYNAMIC_DRAW_ARB);
+			}
+			else
+			{
+				buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB);
+			}
+			buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true);
 		}
 		else
-		{
-			buffer = new LLVertexBuffer(data_mask, GL_STREAM_DRAW_ARB);
+		{ //resize existing buffer
+			buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices);
 		}
-		buffer->allocateBuffer(vol_face.mNumVertices, vol_face.mNumIndices, true);
-	}
-	else
-	{ //resize existing buffer
-		buffer->resizeBuffer(vol_face.mNumVertices, vol_face.mNumIndices);
-	}
 
-	face->setSize(vol_face.mNumVertices, vol_face.mNumIndices);
-	face->setVertexBuffer(buffer);
+		face->setSize(vol_face.mNumVertices, vol_face.mNumIndices);
+		face->setVertexBuffer(buffer);
 
-	U16 offset = 0;
+		U16 offset = 0;
 		
-	LLMatrix4 mat_vert = skin->mBindShapeMatrix;
-	glh::matrix4f m((F32*) mat_vert.mMatrix);
-	m = m.inverse().transpose();
+		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] };
+		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);				
+		LLMatrix3 mat_normal(mat3);				
 
-	//let getGeometryVolume know if alpha should override shiny
-	U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture());
+		//let getGeometryVolume know if alpha should override shiny
+		U32 type = gPipeline.getPoolTypeFromTE(face->getTextureEntry(), face->getTexture());
 
-	if (type == LLDrawPool::POOL_ALPHA)
-	{
-		face->setPoolType(LLDrawPool::POOL_ALPHA);
-	}
-	else
-	{
-		face->setPoolType(LLDrawPool::POOL_AVATAR);
-	}
+		if (type == LLDrawPool::POOL_ALPHA)
+		{
+			face->setPoolType(LLDrawPool::POOL_ALPHA);
+		}
+		else
+		{
+			face->setPoolType(LLDrawPool::POOL_AVATAR);
+		}
 
 	//llinfos << "Rebuilt face " << face->getTEOffset() << " of " << face->getDrawable() << " at " << gFrameTimeSeconds << llendl;
-	face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
+		face->getGeometryVolume(*volume, face->getTEOffset(), mat_vert, mat_normal, offset, true);
 
-	buffer->flush();
-}
+		buffer->flush();
+	}
 
 void LLDrawPoolAvatar::updateRiggedFaceVertexBuffer(LLVOAvatar* avatar, LLFace* face, const LLMeshSkinInfo* skin, LLVolume* volume, const LLVolumeFace& vol_face)
 {
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
index 08a36bddf181fe7b18666eb18f239218c356fdef..d1b508065036b0d7ea5fd7f12193d5f08198b242 100644
--- a/indra/newview/lldrawpoolmaterials.cpp
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -72,6 +72,12 @@ void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
 	};
 	
 	mShader = &(gDeferredMaterialProgram[shader_idx[pass]]);
+
+	if (LLPipeline::sUnderWaterRender)
+	{
+		mShader = &(gDeferredMaterialWaterProgram[shader_idx[pass]]);
+	}
+
 	mShader->bind();
 
 	diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
@@ -215,3 +221,4 @@ void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture,
 		gGL.matrixMode(LLRender::MM_MODELVIEW);
 	}
 }
+
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 2cf9d833c60520d3f8d0f016c23a1d2394eaabb0..8926f64c64f30ec445c85de0a2b6f97d0601d67f 100755
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -37,6 +37,7 @@
 #include "llviewershadermgr.h"
 #include "llrender.h"
 
+#define GE_FORCE_WORKAROUND LL_DARWIN
 
 static LLGLSLShader* simple_shader = NULL;
 static LLGLSLShader* fullbright_shader = NULL;
@@ -111,7 +112,14 @@ void LLDrawPoolGlow::render(S32 pass)
 	
 	LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
 	shader->bind();
-	shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
+	if (LLPipeline::sRenderDeferred)
+	{
+		shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+	}
+	else
+	{
+		shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
+	}	
 
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 	gGL.setColorMask(false, true);
@@ -148,7 +156,11 @@ void LLDrawPoolSimple::beginRenderPass(S32 pass)
 {
 	LLFastTimer t(FTM_RENDER_SIMPLE);
 
-	if (LLPipeline::sUnderWaterRender)
+	if (LLPipeline::sImpostorRender)
+	{
+		simple_shader = &gObjectSimpleImpostorProgram;
+	}
+	else if (LLPipeline::sUnderWaterRender)
 	{
 		simple_shader = &gObjectSimpleWaterProgram;
 	}
@@ -536,7 +548,15 @@ void LLDrawPoolFullbright::prerender()
 
 void LLDrawPoolFullbright::beginPostDeferredPass(S32 pass)
 {
-	gDeferredFullbrightProgram.bind();
+	if (LLPipeline::sUnderWaterRender)
+	{
+		gDeferredFullbrightWaterProgram.bind();
+	}
+	else
+	{
+		gDeferredFullbrightProgram.bind();
+	}
+	
 }
 
 void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
@@ -550,7 +570,14 @@ void LLDrawPoolFullbright::renderPostDeferred(S32 pass)
 
 void LLDrawPoolFullbright::endPostDeferredPass(S32 pass)
 {
-	gDeferredFullbrightProgram.unbind();
+	if (LLPipeline::sUnderWaterRender)
+	{
+		gDeferredFullbrightWaterProgram.unbind();
+	}
+	else
+	{
+		gDeferredFullbrightProgram.unbind();
+	}
 	LLRenderPass::endRenderPass(pass);
 }
 
@@ -625,15 +652,35 @@ S32 LLDrawPoolFullbright::getNumPasses()
 
 void LLDrawPoolFullbrightAlphaMask::beginPostDeferredPass(S32 pass)
 {
-	gObjectFullbrightAlphaMaskProgram.bind();
+	
 	if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
 	{
+		gObjectFullbrightAlphaMaskProgram.bind();
 		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
 	} 
 	else 
-	{
+	{	
+
+// Work-around until we can figure out why the right shader causes
+// the GeForce driver to go tango uniform on OS X 10.6.8 only
+//
+#if GE_FORCE_WORKAROUND
+		gObjectFullbrightAlphaMaskProgram.bind();
 		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+#else
+		if (LLPipeline::sUnderWaterRender)
+		{
+			gDeferredFullbrightAlphaMaskWaterProgram.bind();
+			gDeferredFullbrightAlphaMaskWaterProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+		}
+		else
+		{
+			gDeferredFullbrightAlphaMaskProgram.bind();
+			gDeferredFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+		}
+#endif
 	}
+
 }
 
 void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
@@ -646,7 +693,30 @@ void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
 
 void LLDrawPoolFullbrightAlphaMask::endPostDeferredPass(S32 pass)
 {
-	gObjectFullbrightAlphaMaskProgram.unbind();
+	if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
+	{
+		gObjectFullbrightAlphaMaskProgram.unbind();
+	}
+	else
+	{
+
+// Work-around until we can figure out why the right shader causes
+// the GeForce driver to go tango uniform on OS X 10.6.8 only
+//
+#if GE_FORCE_WORKAROUND		
+		gObjectFullbrightAlphaMaskProgram.unbind();
+#else
+		if (LLPipeline::sUnderWaterRender)
+		{
+			gDeferredFullbrightAlphaMaskWaterProgram.unbind();
+		}
+		else
+		{
+			gDeferredFullbrightAlphaMaskProgram.unbind();
+		}
+#endif
+
+	}
 	LLRenderPass::endRenderPass(pass);
 }
 
diff --git a/indra/newview/lldrawpoolsky.cpp b/indra/newview/lldrawpoolsky.cpp
index 7f7d9f65c60c048a26d02438e278dd21893f190f..ef8bdc33048e2bc217277ee894203bd8d80b3a9b 100755
--- a/indra/newview/lldrawpoolsky.cpp
+++ b/indra/newview/lldrawpoolsky.cpp
@@ -155,3 +155,4 @@ void LLDrawPoolSky::renderSkyCubeFace(U8 side)
 void LLDrawPoolSky::endRenderPass( S32 pass )
 {
 }
+
diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp
index 5ddc15df42769f22b08dcea0ef1b3a735c6c9f7a..6774926f62a96f80fd117b6efc46560f254e2e1f 100755
--- a/indra/newview/lldrawpoolwater.cpp
+++ b/indra/newview/lldrawpoolwater.cpp
@@ -522,13 +522,20 @@ void LLDrawPoolWater::shade()
 
 	F32 eyedepth = LLViewerCamera::getInstance()->getOrigin().mV[2] - gAgent.getRegion()->getWaterHeight();
 	
-	if (deferred_render)
+	if (eyedepth < 0.f && LLPipeline::sWaterReflections)
 	{
-		shader = &gDeferredWaterProgram;
+		if (deferred_render)
+		{
+			shader = &gDeferredUnderWaterProgram;
+		}
+		else
+		{
+			shader = &gUnderWaterProgram;
+		}		
 	}
-	else if (eyedepth < 0.f && LLPipeline::sWaterReflections)
+	else if (deferred_render)
 	{
-		shader = &gUnderWaterProgram;
+		shader = &gDeferredWaterProgram;
 	}
 	else
 	{
diff --git a/indra/newview/lldrawpoolwlsky.cpp b/indra/newview/lldrawpoolwlsky.cpp
index b5faff7968215f467aabb38a2e2da8a3b674ca6f..53339222ebef409633c033a9b41786b45b6a9e03 100755
--- a/indra/newview/lldrawpoolwlsky.cpp
+++ b/indra/newview/lldrawpoolwlsky.cpp
@@ -420,3 +420,4 @@ void LLDrawPoolWLSky::restoreGL()
 		sCloudNoiseTexture = LLViewerTextureManager::getLocalTexture(sCloudNoiseRawImage.get(), TRUE);
 	}
 }
+
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 9b2b778677aaa7a16f2bbe7f5bfc4fe711697a5c..53e5b55b89507b0d4f0cde108ebf1e0b1c8e3a60 100755
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -821,21 +821,21 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 		{
 			v[i].setSelectWithMask(mask[i], min, max);
 		}
-
+		
 		LLVector4a tv[8];
-
+		
 		//transform bounding box into drawable space
 		for (U32 i = 0; i < 8; ++i)
 		{
 			mat_vert.affineTransform(v[i], tv[i]);
 		}
-	
+
 		//find bounding box
 		LLVector4a& newMin = mExtents[0];
 		LLVector4a& newMax = mExtents[1];
-
+		
 		newMin = newMax = tv[0];
-
+		
 		for (U32 i = 1; i < 8; ++i)
 		{
 			newMin.setMin(newMin, tv[i]);
@@ -851,11 +851,11 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 		}
 
 		LLVector4a t;
-		t.setAdd(newMin,newMax);
+		t.setAdd(newMin, newMax);
 		t.mul(0.5f);
 
 		mCenterLocal.set(t.getF32ptr());
-
+		
 		t.setSub(newMax,newMin);
 		mBoundingSphereRadius = t.getLength3().getF32()*0.5f;
 
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index 763634a3ab53708a66f81458cda06e1fde7d1455..66b5f137401f38379169f7f8ba4d70e4f7b23e5f 100755
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -194,8 +194,7 @@ class LLFace
 
 	void		setSize(S32 numVertices, S32 num_indices = 0, bool align = false);
 	
-	BOOL		genVolumeBBoxes(const LLVolume &volume, S32 f,
-								   const LLMatrix4& mat, BOOL global_volume = FALSE);
+	BOOL		genVolumeBBoxes(const LLVolume &volume, S32 f,const LLMatrix4& mat, BOOL global_volume = FALSE);
 	
 	void		init(LLDrawable* drawablep, LLViewerObject* objp);
 	void		destroy();
diff --git a/indra/newview/llfloatertools.cpp b/indra/newview/llfloatertools.cpp
index 14923eec3c8c10880ca269c71966d94f3ec807b0..7b25291da7df632bda40d86d9f18768c2d859ed0 100755
--- a/indra/newview/llfloatertools.cpp
+++ b/indra/newview/llfloatertools.cpp
@@ -1328,7 +1328,7 @@ void LLFloaterTools::getMediaState()
 		getChildView("media_tex")->setEnabled(bool_has_media && editable);
 		getChildView("edit_media")->setEnabled(bool_has_media && LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo && editable );
 		getChildView("delete_media")->setEnabled(bool_has_media && editable );
-		getChildView("add_media")->setEnabled(( ! bool_has_media ) && editable );
+		getChildView("add_media")->setEnabled(editable);
 			// TODO: display a list of all media on the face - use 'identical' flag
 	}
 	else // not all face has media but at least one does.
@@ -1358,7 +1358,7 @@ void LLFloaterTools::getMediaState()
 		getChildView("media_tex")->setEnabled(TRUE);
 		getChildView("edit_media")->setEnabled(LLFloaterMediaSettings::getInstance()->mIdenticalHasMediaInfo);
 		getChildView("delete_media")->setEnabled(TRUE);
-		getChildView("add_media")->setEnabled(FALSE );
+		getChildView("add_media")->setEnabled(editable);
 	}
 	media_info->setText(media_title);
 	
diff --git a/indra/newview/llfloatertools.h b/indra/newview/llfloatertools.h
index ecb0092a6f092f1a20ba2a3213e7e9b5f8116c7f..189bae46c2ea852939806554ae876573527bd143 100755
--- a/indra/newview/llfloatertools.h
+++ b/indra/newview/llfloatertools.h
@@ -109,6 +109,8 @@ class LLFloaterTools
 
 	static void setGridMode(S32 mode);
 
+	LLPanelFace* getPanelFace() { return mPanelFace; }
+
 private:
 	void refresh();
 	void refreshMedia();
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
index 16871adc4d568fe1522da6227ade681b8003856d..658fea944d0499bff4784ccc693ff78b9eae5dc4 100644
--- a/indra/newview/llmaterialmgr.cpp
+++ b/indra/newview/llmaterialmgr.cpp
@@ -51,12 +51,9 @@
 #define MATERIALS_CAP_OBJECT_ID_FIELD             "ID"
 #define MATERIALS_CAP_MATERIAL_ID_FIELD           "MaterialID"
 
-#define MATERIALS_GET_MAX_ENTRIES                 50
 #define MATERIALS_GET_TIMEOUT                     (60.f * 20)
-#define MATERIALS_POST_MAX_ENTRIES                50
 #define MATERIALS_POST_TIMEOUT                    (60.f * 5)
 #define MATERIALS_PUT_THROTTLE_SECS               1.f
-#define MATERIALS_PUT_MAX_ENTRIES                 50
 
 /**
  * LLMaterialsResponder helper class
@@ -544,11 +541,9 @@ void LLMaterialMgr::onIdle(void*)
 		instancep->processGetAllQueue();
 	}
 
-	static LLFrameTimer mPutTimer;
-	if ( (!instancep->mPutQueue.empty()) && (mPutTimer.hasExpired()) )
+	if (!instancep->mPutQueue.empty())
 	{
 		instancep->processPutQueue();
-		mPutTimer.resetWithExpiry(MATERIALS_PUT_THROTTLE_SECS);
 	}
 }
 
@@ -565,14 +560,14 @@ void LLMaterialMgr::processGetQueue()
 			continue;
 		}
 
-		const LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id);
+		LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id);
 		if (!regionp)
 		{
 			LL_WARNS("Materials") << "Unknown region with id " << region_id.asString() << LL_ENDL;
 			mGetQueue.erase(itRegionQueue);
 			continue;
 		}
-		else if (!regionp->capabilitiesReceived())
+		else if (!regionp->capabilitiesReceived() || regionp->materialsCapThrottled())
 		{
 			continue;
 		}
@@ -595,8 +590,9 @@ void LLMaterialMgr::processGetQueue()
 		LLSD materialsData = LLSD::emptyArray();
 
 		material_queue_t& materials = itRegionQueue->second;
-		material_queue_t::iterator loopMaterial = materials.begin();
-		while ( (materials.end() != loopMaterial) && (materialsData.size() <= MATERIALS_GET_MAX_ENTRIES) )
+		U32 max_entries = regionp->getMaxMaterialsPerTransaction();
+		material_queue_t::iterator loopMaterial = materials.begin();		
+		while ( (materials.end() != loopMaterial) && (materialsData.size() < max_entries) )
 		{
 			material_queue_t::iterator itMaterial = loopMaterial++;
 			materialsData.append((*itMaterial).asLLSD());
@@ -628,6 +624,7 @@ void LLMaterialMgr::processGetQueue()
 		LL_DEBUGS("Materials") << "POSTing to region '" << regionp->getName() << "' at '"<< capURL << " for " << materialsData.size() << " materials." 
 			<< "\ndata: " << ll_pretty_print_sd(materialsData) << LL_ENDL;
 		LLHTTPClient::post(capURL, postData, materialsResponder);
+		regionp->resetMaterialsCapThrottle();
 	}
 }
 
@@ -646,7 +643,7 @@ void LLMaterialMgr::processGetAllQueue()
 			clearGetQueues(region_id);		// Invalidates region_id
 			continue;
 		}
-		else if (!regionp->capabilitiesReceived())
+		else if (!regionp->capabilitiesReceived() || regionp->materialsCapThrottled())
 		{
 			continue;
 		}
@@ -663,6 +660,7 @@ void LLMaterialMgr::processGetAllQueue()
 		LL_DEBUGS("Materials") << "GET all for region " << region_id << "url " << capURL << LL_ENDL;
 		LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("GET", capURL, boost::bind(&LLMaterialMgr::onGetAllResponse, this, _1, _2, *itRegion));
 		LLHTTPClient::get(capURL, materialsResponder);
+		regionp->resetMaterialsCapThrottle();
 		mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));
 		mGetAllQueue.erase(itRegion);	// Invalidates region_id
 	}
@@ -670,7 +668,7 @@ void LLMaterialMgr::processGetAllQueue()
 
 void LLMaterialMgr::processPutQueue()
 {
-	typedef std::map<const LLViewerRegion*, LLSD> regionput_request_map;
+	typedef std::map<LLViewerRegion*, LLSD> regionput_request_map;
 	regionput_request_map requests;
 
 	put_queue_t::iterator loopQueue = mPutQueue.begin();
@@ -680,49 +678,54 @@ void LLMaterialMgr::processPutQueue()
 
 		const LLUUID& object_id = itQueue->first;
 		const LLViewerObject* objectp = gObjectList.findObject(object_id);
-		if ( (!objectp) || (!objectp->getRegion()) )
+		if ( !objectp )
 		{
-			LL_WARNS("Materials") << "Object or object region is NULL" << LL_ENDL;
-
+			LL_WARNS("Materials") << "Object is NULL" << LL_ENDL;
 			mPutQueue.erase(itQueue);
-			continue;
 		}
-
-		const LLViewerRegion* regionp = objectp->getRegion();
-		if (!regionp->capabilitiesReceived())
-		{
-			continue;
-		}
-
-		LLSD& facesData = requests[regionp];
-
-		facematerial_map_t& face_map = itQueue->second;
-		facematerial_map_t::iterator itFace = face_map.begin();
-		while ( (face_map.end() != itFace) && (facesData.size() < MATERIALS_GET_MAX_ENTRIES) )
+		else
 		{
-			LLSD faceData = LLSD::emptyMap();
-			faceData[MATERIALS_CAP_FACE_FIELD] = static_cast<LLSD::Integer>(itFace->first);
-			faceData[MATERIALS_CAP_OBJECT_ID_FIELD] = static_cast<LLSD::Integer>(objectp->getLocalID());
-			if (!itFace->second.isNull())
+			LLViewerRegion* regionp = objectp->getRegion();
+			if ( !regionp )
 			{
-				faceData[MATERIALS_CAP_MATERIAL_FIELD] = itFace->second.asLLSD();
+				LL_WARNS("Materials") << "Object region is NULL" << LL_ENDL;
+				mPutQueue.erase(itQueue);
+			}
+			else if ( regionp->capabilitiesReceived() && !regionp->materialsCapThrottled())
+			{
+				LLSD& facesData = requests[regionp];
+
+				facematerial_map_t& face_map = itQueue->second;
+				U32 max_entries = regionp->getMaxMaterialsPerTransaction();
+				facematerial_map_t::iterator itFace = face_map.begin();
+				while ( (face_map.end() != itFace) && (facesData.size() < max_entries) )
+				{
+					LLSD faceData = LLSD::emptyMap();
+					faceData[MATERIALS_CAP_FACE_FIELD] = static_cast<LLSD::Integer>(itFace->first);
+					faceData[MATERIALS_CAP_OBJECT_ID_FIELD] = static_cast<LLSD::Integer>(objectp->getLocalID());
+					if (!itFace->second.isNull())
+					{
+						faceData[MATERIALS_CAP_MATERIAL_FIELD] = itFace->second.asLLSD();
+					}
+					facesData.append(faceData);
+					face_map.erase(itFace++);
+				}
+				if (face_map.empty())
+				{
+					mPutQueue.erase(itQueue);
+				}
 			}
-			facesData.append(faceData);
-			face_map.erase(itFace++);
-		}
-		if (face_map.empty())
-		{
-			mPutQueue.erase(itQueue);
 		}
 	}
 
 	for (regionput_request_map::const_iterator itRequest = requests.begin(); itRequest != requests.end(); ++itRequest)
 	{
-		std::string capURL = itRequest->first->getCapability(MATERIALS_CAPABILITY_NAME);
+		LLViewerRegion* regionp = itRequest->first;
+		std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
 		if (capURL.empty())
 		{
 			LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
-				<< "' is not defined on region '" << itRequest->first->getName() << "'" << LL_ENDL;
+				<< "' is not defined on region '" << regionp->getName() << "'" << LL_ENDL;
 			continue;
 		}
 
@@ -745,6 +748,7 @@ void LLMaterialMgr::processPutQueue()
 			LL_DEBUGS("Materials") << "put for " << itRequest->second.size() << " faces to region " << itRequest->first->getName() << LL_ENDL;
 			LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("PUT", capURL, boost::bind(&LLMaterialMgr::onPutResponse, this, _1, _2));
 			LLHTTPClient::put(capURL, putData, materialsResponder);
+			regionp->resetMaterialsCapThrottle();
 		}
 		else
 		{
@@ -773,7 +777,6 @@ void LLMaterialMgr::clearGetQueues(const LLUUID& region_id)
 	mGetAllPending.erase(region_id);
 	mGetAllCallbacks.erase(region_id);
 }
-
 void LLMaterialMgr::onRegionRemoved(LLViewerRegion* regionp)
 {
 	clearGetQueues(regionp->getRegionID());
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 911af9df049d4120e7a5ea74359bb0867fb9d189..3869219da699da27c0ea9febacc912ac920ffaaa 100755
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -66,7 +66,7 @@
 #include "llvovolume.h"
 #include "lluictrlfactory.h"
 #include "llpluginclassmedia.h"
-#include "llviewertexturelist.h"
+#include "llviewertexturelist.h"// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI
 
 //
 // Constant definitions for comboboxes
@@ -89,6 +89,19 @@ const S32 SHINY_TEXTURE = 4;		// use supplied specular map
 //
 std::string USE_TEXTURE;
 
+LLRender::eTexIndex LLPanelFace::getTextureChannelToEdit()
+{
+	LLComboBox* combobox_matmedia = getChild<LLComboBox>("combobox matmedia");
+	LLComboBox* combobox_mattype	= getChild<LLComboBox>("combobox mattype");
+
+	LLRender::eTexIndex channel_to_edit = (combobox_matmedia && combobox_matmedia->getCurrentIndex() == MATMEDIA_MATERIAL) ?
+													  (combobox_mattype ? (LLRender::eTexIndex)combobox_mattype->getCurrentIndex() : LLRender::DIFFUSE_MAP) : LLRender::DIFFUSE_MAP;
+
+	channel_to_edit = (channel_to_edit == LLRender::NORMAL_MAP)		? (getCurrentNormalMap().isNull()		? LLRender::DIFFUSE_MAP : channel_to_edit) : channel_to_edit;
+	channel_to_edit = (channel_to_edit == LLRender::SPECULAR_MAP)	? (getCurrentSpecularMap().isNull()		? LLRender::DIFFUSE_MAP : channel_to_edit) : channel_to_edit;
+	return channel_to_edit;
+}
+
 // Things the UI provides...
 //
 LLUUID	LLPanelFace::getCurrentNormalMap()			{ return getChild<LLTextureCtrl>("bumpytexture control")->getImageAssetID();	}
@@ -1194,7 +1207,8 @@ void LLPanelFace::updateUI()
 			getChildView("checkbox fullbright")->setEnabled(editable);
 			getChild<LLUICtrl>("checkbox fullbright")->setTentative(!identical_fullbright);
 		}
-		
+
+
 		// Repeats per meter
 		{
 			F32 repeats_diff = 1.f;
@@ -1218,6 +1232,9 @@ void LLPanelFace::updateUI()
 				F32  repeats = 1.0f;
 
 				U32 material_type = (combobox_matmedia->getCurrentIndex() == MATMEDIA_MATERIAL) ? combobox_mattype->getCurrentIndex() : MATTYPE_DIFFUSE;
+
+				LLSelectMgr::getInstance()->setTextureChannel(LLRender::eTexIndex(material_type));
+
 				switch (material_type)
 				{
 					default:
@@ -1328,18 +1345,6 @@ void LLPanelFace::updateUI()
 					getChild<LLColorSwatchCtrl>("shinycolorswatch")->set(material->getSpecularLightColor(),TRUE);
 				}
 
-				// Update sel manager as to which channel we're editing so it can reflect the correct overlay UI
-				// NORSPEC-103
-				LLRender::eTexIndex channel_to_edit = (combobox_matmedia->getCurrentIndex() == MATMEDIA_MATERIAL) ? (LLRender::eTexIndex)combobox_mattype->getCurrentIndex() : LLRender::DIFFUSE_MAP;
-
-				if ( ((channel_to_edit == LLRender::NORMAL_MAP) && material->getNormalID().isNull())
-					||((channel_to_edit == LLRender::SPECULAR_MAP) && material->getSpecularID().isNull()))
-				{
-					channel_to_edit = LLRender::DIFFUSE_MAP;
-				}
-
-				LLSelectMgr::getInstance()->setTextureChannel(channel_to_edit);
-
 				// Bumpy (normal)
 				texture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
 				texture_ctrl->setImageAssetID(material->getNormalID());
@@ -1365,10 +1370,6 @@ void LLPanelFace::updateUI()
 					updateBumpyControls(!material->getNormalID().isNull(), true);
 				}
 			}
-			else
-			{
-				LLSelectMgr::getInstance()->setTextureChannel(LLRender::DIFFUSE_MAP);
-			}
 		}
 
 		// Set variable values for numeric expressions
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 42c1f6bd4820c086ec946426705ae3cb20bcc3dd..46b3375f64bb69bc948af3934bdf953fe924a547 100755
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -100,6 +100,19 @@ class LLPanelFace : public LLPanel
 	void			setMediaURL(const std::string& url);
 	void			setMediaType(const std::string& mime_type);
 
+	LLMaterialPtr createDefaultMaterial(LLMaterialPtr current_material)
+	{
+		LLMaterialPtr new_material(!current_material.isNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial());
+		llassert_always(new_material);
+
+		// Preserve old diffuse alpha mode or assert correct default blend mode as appropriate for the alpha channel content of the diffuse texture
+		//
+		new_material->setDiffuseAlphaMode(current_material.isNull() ? (isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE) : current_material->getDiffuseAlphaMode());
+		return new_material;
+	}
+
+	LLRender::eTexIndex getTextureChannelToEdit();
+
 protected:
 	void			getState();
 
@@ -178,6 +191,8 @@ class LLPanelFace : public LLPanel
 
 	static F32     valueGlow(LLViewerObject* object, S32 face);
 
+	
+
 private:
 
 	bool		isAlpha() { return mIsAlpha; }
@@ -234,17 +249,32 @@ class LLPanelFace : public LLPanel
 			{
 				if (_edit)
 				{
-					LLMaterialPtr new_material(!current_material.isNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial());
+					LLMaterialPtr new_material = _panel->createDefaultMaterial(current_material);
 					llassert_always(new_material);
 
 					// Determine correct alpha mode for current diffuse texture
 					// (i.e. does it have an alpha channel that makes alpha mode useful)
 					//
-					U8 default_alpha_mode = (_panel->isAlpha() ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
+					// _panel->isAlpha() "lies" when one face has alpha and the rest do not (NORSPEC-329)
+					// need to get per-face answer to this question for sane alpha mode retention on updates.
+					//					
+					bool is_alpha_face = object->isImageAlphaBlended(face);
+					
+					// need to keep this original answer for valid comparisons in logic below
+					//
+					U8 original_default_alpha_mode = is_alpha_face ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+					
+					U8 default_alpha_mode = original_default_alpha_mode;
+
+					if (!current_material.isNull())
+					{
+						default_alpha_mode = current_material->getDiffuseAlphaMode();
+					}
 
-					// Default to matching expected state of UI
+					// Insure we don't inherit the default of blend by accident...
+					// this will be stomped by a legit request to change the alpha mode by the apply() below
 					//
-					new_material->setDiffuseAlphaMode(current_material.isNull() ? default_alpha_mode : current_material->getDiffuseAlphaMode());
+					new_material->setDiffuseAlphaMode(default_alpha_mode);
 
 					// Do "It"!
 					//
@@ -254,7 +284,13 @@ class LLPanelFace : public LLPanel
 					LLUUID	new_normal_map_id		= new_material->getNormalID();
 					LLUUID	new_spec_map_id		= new_material->getSpecularID();
 
-					bool is_default_blend_mode		= (new_alpha_mode == default_alpha_mode);
+					if ((new_alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND) && !is_alpha_face)
+					{
+						new_alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+						new_material->setDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_NONE);
+					}
+
+					bool is_default_blend_mode		= (new_alpha_mode == original_default_alpha_mode);
 					bool is_need_material			= !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull();
 
 					if (!is_need_material)
diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp
index 02d363d7952eb3d99e74feedeef75014b4162dec..a1d60b5b16907350eec4501817bb8f9211123240 100755
--- a/indra/newview/llpanelvolume.cpp
+++ b/indra/newview/llpanelvolume.cpp
@@ -710,9 +710,19 @@ void LLPanelVolume::onLightCancelColor(const LLSD& data)
 void LLPanelVolume::onLightCancelTexture(const LLSD& data)
 {
 	LLTextureCtrl* LightTextureCtrl = getChild<LLTextureCtrl>("light texture control");
+
 	if (LightTextureCtrl)
 	{
-		LightTextureCtrl->setImageAssetID(mLightSavedTexture);
+		LightTextureCtrl->setImageAssetID(LLUUID::null);
+	}
+
+	LLVOVolume *volobjp = (LLVOVolume *) mObject.get();
+	if(volobjp)
+	{
+		// Cancel the light texture as requested
+		// NORSPEC-292
+		//
+		volobjp->setLightTextureID(LLUUID::null);
 	}
 }
 
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 0cbdbe16a39342d21726d44e689536afdc9cce48..7b397d46f31d501393dd497be626cac5b3b2f20c 100755
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -91,7 +91,7 @@
 #include "llvovolume.h"
 #include "pipeline.h"
 #include "llviewershadermgr.h"
-
+#include "llpanelface.h"
 #include "llglheaders.h"
 
 LLViewerObject* getSelectedParentObject(LLViewerObject *object) ;
@@ -2534,7 +2534,7 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch)
 					if (tep && !tep->getMaterialParams().isNull())
 					{
 						LLMaterialPtr orig = tep->getMaterialParams();
-						LLMaterialPtr p = new LLMaterial(orig->asLLSD());
+						LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig);
 						p->setNormalRepeat(normal_scale_s, normal_scale_t);
 						p->setSpecularRepeat(specular_scale_s, specular_scale_t);
 
@@ -2560,8 +2560,8 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch)
 					if (tep && !tep->getMaterialParams().isNull())
 					{
 						LLMaterialPtr orig = tep->getMaterialParams();
+						LLMaterialPtr p = gFloaterTools->getPanelFace()->createDefaultMaterial(orig);
 
-						LLMaterialPtr p = new LLMaterial(orig->asLLSD());
 						p->setNormalRepeat(normal_scale_s, normal_scale_t);
 						p->setSpecularRepeat(specular_scale_s, specular_scale_t);
 
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index 4676f7b251327f250d4a38e73d259559637732d9..2b1ed5858af04e179afafd0901299bc0c7120277 100755
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -133,7 +133,8 @@ class LLFloaterTexturePicker : public LLFloater
 	PermissionMask 	getFilterPermMask();
 	void updateFilterPermMask();
 	void commitIfImmediateSet();
-	
+	void commitCancel();
+
 	void onFilterEdit(const std::string& search_string );
 	
 	void setCanApply(bool can_preview, bool can_apply);
@@ -706,6 +707,14 @@ void LLFloaterTexturePicker::commitIfImmediateSet()
 	}
 }
 
+void LLFloaterTexturePicker::commitCancel()
+{
+	if (!mNoCopyTextureSelected && mOwner && mCanApply)
+	{
+		mOwner->onFloaterCommit(LLTextureCtrl::TEXTURE_CANCEL);
+	}
+}
+
 // static
 void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata)
 {
@@ -733,7 +742,7 @@ void LLFloaterTexturePicker::onBtnNone(void* userdata)
 {
 	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 	self->setImageID( LLUUID::null );
-	self->commitIfImmediateSet();
+	self->commitCancel();
 }
 
 /*
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index e085834326323ac3bc442434f0873c391fefc19a..ef7d0cd81bb13dfd514bc3a526d83c0a38156a45 100755
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -58,6 +58,7 @@
 #include "llviewerwindow.h"
 #include "llvoavatarself.h"
 #include "llworld.h"
+#include "llpanelface.h"
 
 // syntactic sugar
 #define callMemberFunction(object,ptrToMember)  ((object).*(ptrToMember))
@@ -1163,7 +1164,51 @@ void LLToolDragAndDrop::dropTextureOneFace(LLViewerObject* hit_obj,
 	// update viewer side image in anticipation of update from simulator
 	LLViewerTexture* image = LLViewerTextureManager::getFetchedTexture(asset_id);
 	LLViewerStats::getInstance()->incStat(LLViewerStats::ST_EDIT_TEXTURE_COUNT );
-	hit_obj->setTEImage(hit_face, image);
+
+	LLTextureEntry* tep = hit_obj ? (hit_obj->getTE(hit_face)) : NULL;
+
+	LLPanelFace* panel_face = gFloaterTools->getPanelFace();
+
+	if (gFloaterTools->getVisible() && panel_face)
+	{
+		switch (LLSelectMgr::getInstance()->getTextureChannel())
+		{
+
+		case 0:
+		default:
+			{
+				hit_obj->setTEImage(hit_face, image);
+			}
+			break;
+
+		case 1:
+			{
+				LLMaterialPtr old_mat = tep->getMaterialParams();
+				LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat);
+				new_mat->setNormalID(asset_id);
+				tep->setMaterialParams(new_mat);
+				hit_obj->setTENormalMap(hit_face, asset_id);
+				LLMaterialMgr::getInstance()->put(hit_obj->getID(), hit_face, *new_mat);
+			}
+			break;
+
+		case 2:
+			{
+				LLMaterialPtr old_mat = tep->getMaterialParams();
+				LLMaterialPtr new_mat = panel_face->createDefaultMaterial(old_mat);
+				new_mat->setSpecularID(asset_id);
+				tep->setMaterialParams(new_mat);
+				hit_obj->setTESpecularMap(hit_face, asset_id);
+				LLMaterialMgr::getInstance()->put(hit_obj->getID(), hit_face, *new_mat);
+			}
+			break;
+		}
+	}
+	else
+	{
+		hit_obj->setTEImage(hit_face, image);
+	}
+	
 	dialog_refresh_all();
 
 	// send the update to the simulator
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index f90b35a7bddbf65cbe7897110678c795c1262c53..bbebeea3e0e22a5bd2d6e5de5e912224a1681baa 100755
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -890,7 +890,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		{
 			gGL.setColorMask(true, true);
 					
-			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+			if (LLPipeline::sRenderDeferred)
 			{
 				gPipeline.mDeferredScreen.bindTarget();
 				glClearColor(1,0,1,1);
@@ -939,7 +939,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 
 			gGL.setColorMask(true, false);
-			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+			if (LLPipeline::sRenderDeferred)
 			{
 				gPipeline.renderGeomDeferred(*LLViewerCamera::getInstance());
 			}
@@ -976,7 +976,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		
 		if (to_texture)
 		{
-			if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+			if (LLPipeline::sRenderDeferred)
 			{
 				gPipeline.mDeferredScreen.flush();
 				if(LLRenderTarget::sUseFBO)
@@ -1002,7 +1002,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 			}
 		}
 
-		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+		if (LLPipeline::sRenderDeferred)
 		{
 			gPipeline.renderDeferredLighting();
 		}
@@ -1623,3 +1623,4 @@ void display_cleanup()
 {
 	gDisconnectedImagep = NULL;
 }
+
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 6f7b2f40e62d999240141820e4886f60ba45d3b4..0070240803995b15edeb4b9c81568973490151ae 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -4410,12 +4410,10 @@ S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMateri
 
 void LLViewerObject::refreshMaterials()
 {
-	setChanged(ALL_CHANGED);
+	setChanged(TEXTURE);
 	if (mDrawable.notNull())
 	{
 		gPipeline.markTextured(mDrawable);
-		gPipeline.markRebuild(mDrawable,LLDrawable::REBUILD_ALL);
-		dirtySpatialGroup(TRUE);
 	}
 }
 
@@ -4519,6 +4517,30 @@ LLViewerTexture *LLViewerObject::getTEImage(const U8 face) const
 }
 
 
+bool LLViewerObject::isImageAlphaBlended(const U8 te) const
+{
+	LLViewerTexture* image = getTEImage(te);
+	LLGLenum format = image ? image->getPrimaryFormat() : GL_RGB;
+	switch (format)
+	{
+		case GL_RGBA:
+		case GL_ALPHA:
+		{
+			return true;
+		}
+		break;
+
+		case GL_RGB: break;
+		default:
+		{
+			llwarns << "Unexpected tex format in LLViewerObject::isImageAlphaBlended...returning no alpha." << llendl;
+		}
+		break;
+	}
+
+	return false;
+}
+
 LLViewerTexture *LLViewerObject::getTENormalMap(const U8 face) const
 {
 	//	llassert(mTEImages);
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index ea0d55cda53828367bc969fc2912923be61e0a45..16f1f403d3495dbaae55014afad6f09636e29693 100755
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -339,6 +339,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	LLViewerTexture		*getTENormalMap(const U8 te) const;
 	LLViewerTexture		*getTESpecularMap(const U8 te) const;
 	
+	bool						isImageAlphaBlended(const U8 te) const;
+
 	void fitFaceTexture(const U8 face);
 	void sendTEUpdate() const;			// Sends packed representation of all texture entry information
 	
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 8422708addde7bb4da7c27e09868704f1d877dd1..e6fc82f761730dc76c4e8c04d20583c5c3aed408 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -1219,7 +1219,7 @@ void LLViewerRegion::getInfo(LLSD& info)
 	info["Region"]["Handle"]["y"] = (LLSD::Integer)y;
 }
 
-void LLViewerRegion::getSimulatorFeatures(LLSD& sim_features)
+void LLViewerRegion::getSimulatorFeatures(LLSD& sim_features) const
 {
 	sim_features = mSimulatorFeatures;
 
@@ -1944,3 +1944,47 @@ bool LLViewerRegion::dynamicPathfindingEnabled() const
 			 mSimulatorFeatures["DynamicPathfindingEnabled"].asBoolean());
 }
 
+void LLViewerRegion::resetMaterialsCapThrottle()
+{
+	F32 requests_per_sec = 	1.0f; // original default;
+	if (   mSimulatorFeatures.has("RenderMaterialsCapability")
+		&& mSimulatorFeatures["RenderMaterialsCapability"].isReal() )
+	{
+		requests_per_sec = mSimulatorFeatures["RenderMaterialsCapability"].asReal();
+		if ( requests_per_sec == 0.0f )
+		{
+			requests_per_sec = 1.0f;
+			LL_WARNS("Materials")
+				<< "region '" << getName()
+				<< "' returned zero for RenderMaterialsCapability; using default "
+				<< requests_per_sec << " per second"
+				<< LL_ENDL;
+		}
+		LL_DEBUGS("Materials") << "region '" << getName()
+							   << "' RenderMaterialsCapability " << requests_per_sec
+							   << LL_ENDL;
+	}
+	else
+	{
+		LL_DEBUGS("Materials")
+			<< "region '" << getName()
+			<< "' did not return RenderMaterialsCapability, using default "
+			<< requests_per_sec << " per second"
+			<< LL_ENDL;
+	}
+	
+	mMaterialsCapThrottleTimer.resetWithExpiry( 1.0f / requests_per_sec );
+}
+
+U32 LLViewerRegion::getMaxMaterialsPerTransaction() const
+{
+	U32 max_entries = 50; // original hard coded default
+	if (   mSimulatorFeatures.has( "MaxMaterialsPerTransaction" )
+		&& mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].isInteger())
+	{
+		max_entries = mSimulatorFeatures[ "MaxMaterialsPerTransaction" ].asInteger();
+	}
+	return max_entries;
+}
+
+
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index 56cd0c9ea1a204bbb096ce4c12ec01435643eb17..109baccf9adfb91502b0e56dcc37805fb08b979d 100755
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -43,6 +43,7 @@
 #include "llcapabilityprovider.h"
 #include "m4math.h"					// LLMatrix4
 #include "llhttpclient.h"
+#include "llframetimer.h"
 
 // Surface id's
 #define LAND  1
@@ -293,7 +294,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	bool meshRezEnabled() const;
 	bool meshUploadEnabled() const;
 
-	void getSimulatorFeatures(LLSD& info);	
+	void getSimulatorFeatures(LLSD& info) const;	
 	void setSimulatorFeatures(const LLSD& info);
 
 	
@@ -342,7 +343,12 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	void getNeighboringRegionsStatus( std::vector<S32>& regions );
 	const LLViewerRegionImpl * getRegionImpl() const { return mImpl; }
 	LLViewerRegionImpl * getRegionImplNC() { return mImpl; }
+
+	// implements the materials capability throttle
+	bool materialsCapThrottled() const { return !mMaterialsCapThrottleTimer.hasExpired(); }
+	void resetMaterialsCapThrottle();
 	
+	U32 getMaxMaterialsPerTransaction() const;
 public:
 	struct CompareDistance
 	{
@@ -434,6 +440,9 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	BOOL mReleaseNotesRequested;
 	
 	LLSD mSimulatorFeatures;
+
+	// the materials capability throttle
+	LLFrameTimer mMaterialsCapThrottleTimer;
 };
 
 inline BOOL LLViewerRegion::getRegionProtocol(U64 protocol) const
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index e24237522a1adf4301325a79b56049ec8771a84e..995eb599b80ae8b2390c4c1b3086c43c5ecf564e 100755
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -42,22 +42,6 @@
 #include "llvosky.h"
 #include "llrender.h"
 
-#if LL_DARWIN
-#include "OpenGL/OpenGL.h"
-
-// include spec exp clamp to fix older mac rendering artifacts
-//
-#define SINGLE_FP_PERMUTATION(shader)					\
-	if (gGLManager.mIsMobileGF)							\
-	{																\
-		shader.addPermutation("SINGLE_FP_ONLY","1");		\
-	}
-
-
-#else
-#define SINGLE_FP_PERMUTATION(shader)
-#endif
-
 #ifdef LL_RELEASE_FOR_DOWNLOAD
 #define UNIFORM_ERRS LL_WARNS_ONCE("Shader")
 #else
@@ -99,6 +83,7 @@ LLGLSLShader	gAlphaMaskProgram;
 
 //object shaders
 LLGLSLShader		gObjectSimpleProgram;
+LLGLSLShader		gObjectSimpleImpostorProgram;
 LLGLSLShader		gObjectPreviewProgram;
 LLGLSLShader		gObjectSimpleWaterProgram;
 LLGLSLShader		gObjectSimpleAlphaMaskProgram;
@@ -184,6 +169,7 @@ LLGLSLShader			gPostNightVisionProgram;
 // Deferred rendering shaders
 LLGLSLShader			gDeferredImpostorProgram;
 LLGLSLShader			gDeferredWaterProgram;
+LLGLSLShader			gDeferredUnderWaterProgram;
 LLGLSLShader			gDeferredDiffuseProgram;
 LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
 LLGLSLShader			gDeferredNonIndexedDiffuseProgram;
@@ -199,20 +185,26 @@ LLGLSLShader			gDeferredTreeShadowProgram;
 LLGLSLShader			gDeferredAvatarProgram;
 LLGLSLShader			gDeferredAvatarAlphaProgram;
 LLGLSLShader			gDeferredLightProgram;
-LLGLSLShader			gDeferredMultiLightProgram;
+LLGLSLShader			gDeferredMultiLightProgram[16];
 LLGLSLShader			gDeferredSpotLightProgram;
 LLGLSLShader			gDeferredMultiSpotLightProgram;
 LLGLSLShader			gDeferredSunProgram;
 LLGLSLShader			gDeferredBlurLightProgram;
 LLGLSLShader			gDeferredSoftenProgram;
+LLGLSLShader			gDeferredSoftenWaterProgram;
 LLGLSLShader			gDeferredShadowProgram;
 LLGLSLShader			gDeferredShadowCubeProgram;
 LLGLSLShader			gDeferredShadowAlphaMaskProgram;
 LLGLSLShader			gDeferredAvatarShadowProgram;
 LLGLSLShader			gDeferredAttachmentShadowProgram;
 LLGLSLShader			gDeferredAlphaProgram;
+LLGLSLShader			gDeferredAlphaImpostorProgram;
+LLGLSLShader			gDeferredAlphaWaterProgram;
 LLGLSLShader			gDeferredAvatarEyesProgram;
 LLGLSLShader			gDeferredFullbrightProgram;
+LLGLSLShader			gDeferredFullbrightAlphaMaskProgram;
+LLGLSLShader			gDeferredFullbrightWaterProgram;
+LLGLSLShader			gDeferredFullbrightAlphaMaskWaterProgram;
 LLGLSLShader			gDeferredEmissiveProgram;
 LLGLSLShader			gDeferredPostProgram;
 LLGLSLShader			gDeferredCoFProgram;
@@ -230,6 +222,7 @@ LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
 LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
+LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 
 LLViewerShaderMgr::LLViewerShaderMgr() :
 	mVertexShaderLevel(SHADER_COUNT, 0),
@@ -245,6 +238,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gWaterProgram);
 	mShaderList.push_back(&gAvatarEyeballProgram); 
 	mShaderList.push_back(&gObjectSimpleProgram);
+	mShaderList.push_back(&gObjectSimpleImpostorProgram);
 	mShaderList.push_back(&gObjectPreviewProgram);
 	mShaderList.push_back(&gImpostorProgram);
 	mShaderList.push_back(&gObjectFullbrightNoColorProgram);
@@ -295,6 +289,7 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gUnderWaterProgram);
 	mShaderList.push_back(&gDeferredSunProgram);
 	mShaderList.push_back(&gDeferredSoftenProgram);
+	mShaderList.push_back(&gDeferredSoftenWaterProgram);
 	mShaderList.push_back(&gDeferredMaterialProgram[1]);
 	mShaderList.push_back(&gDeferredMaterialProgram[5]);
 	mShaderList.push_back(&gDeferredMaterialProgram[9]);
@@ -303,15 +298,30 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT]);
 	mShaderList.push_back(&gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT]);
 	mShaderList.push_back(&gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT]);	
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[1]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[5]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[9]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[13]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT]);
+	mShaderList.push_back(&gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT]);	
+	mShaderList.push_back(&gDeferredAlphaProgram);
 	mShaderList.push_back(&gDeferredAlphaProgram);
+	mShaderList.push_back(&gDeferredAlphaImpostorProgram);
+	mShaderList.push_back(&gDeferredAlphaWaterProgram);
 	mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
+	mShaderList.push_back(&gDeferredFullbrightAlphaMaskProgram);
+	mShaderList.push_back(&gDeferredFullbrightWaterProgram);
+	mShaderList.push_back(&gDeferredFullbrightAlphaMaskWaterProgram);	
 	mShaderList.push_back(&gDeferredFullbrightShinyProgram);
 	mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram);
 	mShaderList.push_back(&gDeferredSkinnedFullbrightProgram);
 	mShaderList.push_back(&gDeferredEmissiveProgram);
 	mShaderList.push_back(&gDeferredAvatarEyesProgram);
 	mShaderList.push_back(&gDeferredWaterProgram);
+	mShaderList.push_back(&gDeferredUnderWaterProgram);	
 	mShaderList.push_back(&gDeferredAvatarAlphaProgram);
 	mShaderList.push_back(&gDeferredWLSkyProgram);
 	mShaderList.push_back(&gDeferredWLCloudProgram);
@@ -721,6 +731,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gObjectFullbrightNoColorProgram.unload();
 	gObjectFullbrightNoColorWaterProgram.unload();
 	gObjectSimpleProgram.unload();
+	gObjectSimpleImpostorProgram.unload();
 	gObjectPreviewProgram.unload();
 	gImpostorProgram.unload();
 	gObjectSimpleAlphaMaskProgram.unload();
@@ -1128,12 +1139,16 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredImpostorProgram.unload();
 		gDeferredTerrainProgram.unload();
 		gDeferredLightProgram.unload();
-		gDeferredMultiLightProgram.unload();
+		for (U32 i = 0; i < LL_DEFERRED_MULTI_LIGHT_COUNT; ++i)
+		{
+			gDeferredMultiLightProgram[i].unload();
+		}
 		gDeferredSpotLightProgram.unload();
 		gDeferredMultiSpotLightProgram.unload();
 		gDeferredSunProgram.unload();
 		gDeferredBlurLightProgram.unload();
 		gDeferredSoftenProgram.unload();
+		gDeferredSoftenWaterProgram.unload();
 		gDeferredShadowProgram.unload();
 		gDeferredShadowCubeProgram.unload();
 		gDeferredShadowAlphaMaskProgram.unload();
@@ -1142,7 +1157,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarProgram.unload();
 		gDeferredAvatarAlphaProgram.unload();
 		gDeferredAlphaProgram.unload();
+		gDeferredAlphaWaterProgram.unload();
 		gDeferredFullbrightProgram.unload();
+		gDeferredFullbrightAlphaMaskProgram.unload();
+		gDeferredFullbrightWaterProgram.unload();
+		gDeferredFullbrightAlphaMaskWaterProgram.unload();
 		gDeferredEmissiveProgram.unload();
 		gDeferredAvatarEyesProgram.unload();
 		gDeferredPostProgram.unload();		
@@ -1151,6 +1170,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredPostGammaCorrectProgram.unload();
 		gFXAAProgram.unload();
 		gDeferredWaterProgram.unload();
+		gDeferredUnderWaterProgram.unload();
 		gDeferredWLSkyProgram.unload();
 		gDeferredWLCloudProgram.unload();
 		gDeferredStarProgram.unload();
@@ -1162,6 +1182,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
 		{
 			gDeferredMaterialProgram[i].unload();
+			gDeferredMaterialWaterProgram[i].unload();
 		}
 		return TRUE;
 	}
@@ -1170,7 +1191,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 	if (success)
 	{
-		gDeferredDiffuseProgram.mName = "Deferred Diffuse Shader";
+		gDeferredDiffuseProgram.mName = "Deferred Diffuse Shader";		
 		gDeferredDiffuseProgram.mShaderFiles.clear();
 		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredDiffuseProgram.mShaderFiles.push_back(make_pair("deferred/diffuseIndexedF.glsl", GL_FRAGMENT_SHADER_ARB));
@@ -1246,11 +1267,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	if (success)
 	{
 		gDeferredSkinnedAlphaProgram.mName = "Deferred Skinned Alpha Shader";
-		gDeferredSkinnedAlphaProgram.mFeatures.atmosphericHelpers = true;
 		gDeferredSkinnedAlphaProgram.mFeatures.hasObjectSkinning = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasGamma = true;
-		gDeferredSkinnedAlphaProgram.mFeatures.hasAtmospherics = true;
 		gDeferredSkinnedAlphaProgram.mFeatures.calculatesLighting = false;
 		gDeferredSkinnedAlphaProgram.mFeatures.hasLighting = false;
 		gDeferredSkinnedAlphaProgram.mFeatures.isAlphaLighting = true;
@@ -1260,8 +1277,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredSkinnedAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		gDeferredSkinnedAlphaProgram.addPermutation("USE_DIFFUSE_TEX", "1");
-		gDeferredSkinnedAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
 		gDeferredSkinnedAlphaProgram.addPermutation("HAS_SKIN", "1");
+		gDeferredSkinnedAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
 		gDeferredSkinnedAlphaProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
 		success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL);
 		
@@ -1289,6 +1306,15 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
 	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
 
+	gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+
 	for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
 	{
 		if (success)
@@ -1308,8 +1334,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 			bool has_skin = i & 0x10;
 			gDeferredMaterialProgram[i].addPermutation("HAS_SKIN",has_skin ? "1" : "0");
 
-			SINGLE_FP_PERMUTATION(gDeferredMaterialProgram[i]);
-
 			if (has_skin)
 			{
 				gDeferredMaterialProgram[i].mFeatures.hasObjectSkinning = true;
@@ -1317,6 +1341,34 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 			success = gDeferredMaterialProgram[i].createShader(NULL, NULL);
 		}
+
+		if (success)
+		{
+			gDeferredMaterialWaterProgram[i].mName = llformat("Deferred Underwater Material Shader %d", i);
+
+			U32 alpha_mode = i & 0x3;
+
+			gDeferredMaterialWaterProgram[i].mShaderFiles.clear();
+			gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredMaterialWaterProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredMaterialWaterProgram[i].mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			gDeferredMaterialWaterProgram[i].mShaderGroup = LLGLSLShader::SG_WATER;
+
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_NORMAL_MAP", i & 0x8? "1" : "0");
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_SPECULAR_MAP", i & 0x4 ? "1" : "0");
+			gDeferredMaterialWaterProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_SUN_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+			bool has_skin = i & 0x10;
+			gDeferredMaterialWaterProgram[i].addPermutation("HAS_SKIN",has_skin ? "1" : "0");
+			gDeferredMaterialWaterProgram[i].addPermutation("WATER_FOG","1");
+
+			if (has_skin)
+			{
+				gDeferredMaterialWaterProgram[i].mFeatures.hasObjectSkinning = true;
+			}
+
+			success = gDeferredMaterialWaterProgram[i].createShader(NULL, NULL);//&mWLUniforms);
+		}
 	}
 
 	gDeferredMaterialProgram[1].mFeatures.hasLighting = true;
@@ -1328,6 +1380,14 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 
+	gDeferredMaterialWaterProgram[1].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[5].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[9].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[13].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialWaterProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
 
 	
 	if (success)
@@ -1368,22 +1428,21 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
-		SINGLE_FP_PERMUTATION(gDeferredLightProgram);
-
 		success = gDeferredLightProgram.createShader(NULL, NULL);
 	}
 
-	if (success)
+	for (U32 i = 0; i < LL_DEFERRED_MULTI_LIGHT_COUNT; i++)
 	{
-		gDeferredMultiLightProgram.mName = "Deferred MultiLight Shader";
-		gDeferredMultiLightProgram.mShaderFiles.clear();
-		gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredMultiLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightF.glsl", GL_FRAGMENT_SHADER_ARB));
-		gDeferredMultiLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
-
-		SINGLE_FP_PERMUTATION(gDeferredMultiLightProgram);
-
-		success = gDeferredMultiLightProgram.createShader(NULL, NULL);
+		if (success)
+		{
+			gDeferredMultiLightProgram[i].mName = llformat("Deferred MultiLight Shader %d", i);
+			gDeferredMultiLightProgram[i].mShaderFiles.clear();
+			gDeferredMultiLightProgram[i].mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredMultiLightProgram[i].mShaderFiles.push_back(make_pair("deferred/multiPointLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredMultiLightProgram[i].mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			gDeferredMultiLightProgram[i].addPermutation("LIGHT_COUNT", llformat("%d", i+1));
+			success = gDeferredMultiLightProgram[i].createShader(NULL, NULL);
+		}
 	}
 
 	if (success)
@@ -1394,8 +1453,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/spotLightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
-		SINGLE_FP_PERMUTATION(gDeferredSpotLightProgram);
-
 		success = gDeferredSpotLightProgram.createShader(NULL, NULL);
 	}
 
@@ -1407,8 +1464,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiSpotLightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredMultiSpotLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
-		SINGLE_FP_PERMUTATION(gDeferredMultiSpotLightProgram);
-
 		success = gDeferredMultiSpotLightProgram.createShader(NULL, NULL);
 	}
 
@@ -1436,8 +1491,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSunProgram.mShaderFiles.push_back(make_pair(fragment, GL_FRAGMENT_SHADER_ARB));
 		gDeferredSunProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
-		SINGLE_FP_PERMUTATION(gDeferredSunProgram);
-
 		success = gDeferredSunProgram.createShader(NULL, NULL);
 	}
 
@@ -1449,19 +1502,14 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/blurLightF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredBlurLightProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
-		SINGLE_FP_PERMUTATION(gDeferredBlurLightProgram);
-
 		success = gDeferredBlurLightProgram.createShader(NULL, NULL);
 	}
 
 	if (success)
 	{
 		gDeferredAlphaProgram.mName = "Deferred Alpha Shader";
-		gDeferredAlphaProgram.mFeatures.atmosphericHelpers = true;
+
 		gDeferredAlphaProgram.mFeatures.calculatesLighting = false;
-		gDeferredAlphaProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredAlphaProgram.mFeatures.hasGamma = true;
-		gDeferredAlphaProgram.mFeatures.hasAtmospherics = true;
 		gDeferredAlphaProgram.mFeatures.hasLighting = false;
 		gDeferredAlphaProgram.mFeatures.isAlphaLighting = true;
 		gDeferredAlphaProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
@@ -1478,12 +1526,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredAlphaProgram.addPermutation("USE_INDEXED_TEX", "1");
-		gDeferredAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
 		gDeferredAlphaProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+		gDeferredAlphaProgram.addPermutation("USE_VERTEX_COLOR", "1");
 		gDeferredAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
-		SINGLE_FP_PERMUTATION(gDeferredAlphaProgram);
-
 		success = gDeferredAlphaProgram.createShader(NULL, NULL);
 
 		// Hack
@@ -1491,6 +1537,72 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAlphaProgram.mFeatures.hasLighting = true;
 	}
 
+	if (success)
+	{
+		gDeferredAlphaImpostorProgram.mName = "Deferred Alpha Shader";
+
+		gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = false;
+		gDeferredAlphaImpostorProgram.mFeatures.hasLighting = false;
+		gDeferredAlphaImpostorProgram.mFeatures.isAlphaLighting = true;
+		gDeferredAlphaImpostorProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
+		if (mVertexShaderLevel[SHADER_DEFERRED] < 1)
+		{
+			gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		}
+		else
+		{ //shave off some texture units for shadow maps
+			gDeferredAlphaImpostorProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+		}
+
+		gDeferredAlphaImpostorProgram.mShaderFiles.clear();
+		gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAlphaImpostorProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAlphaImpostorProgram.addPermutation("USE_INDEXED_TEX", "1");
+		gDeferredAlphaImpostorProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+		gDeferredAlphaImpostorProgram.addPermutation("USE_VERTEX_COLOR", "1");
+		gDeferredAlphaImpostorProgram.addPermutation("FOR_IMPOSTOR", "1");
+
+		gDeferredAlphaImpostorProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+
+		success = gDeferredAlphaImpostorProgram.createShader(NULL, NULL);
+
+		// Hack
+		gDeferredAlphaImpostorProgram.mFeatures.calculatesLighting = true;
+		gDeferredAlphaImpostorProgram.mFeatures.hasLighting = true;
+	}
+
+	if (success)
+	{
+		gDeferredAlphaWaterProgram.mName = "Deferred Alpha Underwater Shader";
+		gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = false;
+		gDeferredAlphaWaterProgram.mFeatures.hasLighting = false;
+		gDeferredAlphaWaterProgram.mFeatures.isAlphaLighting = true;
+		gDeferredAlphaWaterProgram.mFeatures.disableTextureIndex = true; //hack to disable auto-setup of texture channels
+		if (mVertexShaderLevel[SHADER_DEFERRED] < 1)
+		{
+			gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		}
+		else
+		{ //shave off some texture units for shadow maps
+			gDeferredAlphaWaterProgram.mFeatures.mIndexedTextureChannels = llmax(LLGLSLShader::sIndexedTextureChannels - 6, 1);
+		}
+		gDeferredAlphaWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		gDeferredAlphaWaterProgram.mShaderFiles.clear();
+		gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAlphaWaterProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAlphaWaterProgram.addPermutation("USE_INDEXED_TEX", "1");
+		gDeferredAlphaWaterProgram.addPermutation("WATER_FOG", "1");
+		gDeferredAlphaWaterProgram.addPermutation("USE_VERTEX_COLOR", "1");
+		gDeferredAlphaWaterProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+		gDeferredAlphaWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+
+		success = gDeferredAlphaWaterProgram.createShader(NULL, NULL);
+
+		// Hack
+		gDeferredAlphaWaterProgram.mFeatures.calculatesLighting = true;
+		gDeferredAlphaWaterProgram.mFeatures.hasLighting = true;
+	}
+
 	if (success)
 	{
 		gDeferredAvatarEyesProgram.mName = "Deferred Avatar Eyes Shader";
@@ -1519,6 +1631,54 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredFullbrightProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredFullbrightAlphaMaskProgram.mName = "Deferred Fullbright Alpha Masking Shader";
+		gDeferredFullbrightAlphaMaskProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredFullbrightAlphaMaskProgram.mFeatures.hasGamma = true;
+		gDeferredFullbrightAlphaMaskProgram.mFeatures.hasTransport = true;
+		gDeferredFullbrightAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		gDeferredFullbrightAlphaMaskProgram.mShaderFiles.clear();
+		gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredFullbrightAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredFullbrightAlphaMaskProgram.addPermutation("HAS_ALPHA_MASK","1");
+		gDeferredFullbrightAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredFullbrightAlphaMaskProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredFullbrightWaterProgram.mName = "Deferred Fullbright Underwater Shader";
+		gDeferredFullbrightWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredFullbrightWaterProgram.mFeatures.hasGamma = true;
+		gDeferredFullbrightWaterProgram.mFeatures.hasTransport = true;
+		gDeferredFullbrightWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		gDeferredFullbrightWaterProgram.mShaderFiles.clear();
+		gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredFullbrightWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredFullbrightWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		gDeferredFullbrightWaterProgram.addPermutation("WATER_FOG","1");
+		success = gDeferredFullbrightWaterProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredFullbrightAlphaMaskWaterProgram.mName = "Deferred Fullbright Underwater Alpha Masking Shader";
+		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasGamma = true;
+		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.hasTransport = true;
+		gDeferredFullbrightAlphaMaskWaterProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels;
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.clear();
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredFullbrightAlphaMaskWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("HAS_ALPHA_MASK","1");
+		gDeferredFullbrightAlphaMaskWaterProgram.addPermutation("WATER_FOG","1");
+		success = gDeferredFullbrightAlphaMaskWaterProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gDeferredFullbrightShinyProgram.mName = "Deferred FullbrightShiny Shader";
@@ -1591,6 +1751,20 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredWaterProgram.createShader(NULL, &mWaterUniforms);
 	}
 
+	if (success)
+	{
+		// load water shader
+		gDeferredUnderWaterProgram.mName = "Deferred Under Water Shader";
+		gDeferredUnderWaterProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredUnderWaterProgram.mFeatures.hasGamma = true;
+		gDeferredUnderWaterProgram.mFeatures.hasTransport = true;
+		gDeferredUnderWaterProgram.mShaderFiles.clear();
+		gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/waterV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredUnderWaterProgram.mShaderFiles.push_back(make_pair("deferred/underWaterF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredUnderWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredUnderWaterProgram.createShader(NULL, &mWaterUniforms);
+	}
+
 	if (success)
 	{
 		gDeferredSoftenProgram.mName = "Deferred Soften Shader";
@@ -1600,8 +1774,6 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 
 		gDeferredSoftenProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
-		SINGLE_FP_PERMUTATION(gDeferredSoftenProgram);
-
 		if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
 		{ //if using SSAO, take screen space light map into account as if shadows are enabled
 			gDeferredSoftenProgram.mShaderLevel = llmax(gDeferredSoftenProgram.mShaderLevel, 2);
@@ -1610,6 +1782,25 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredSoftenProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredSoftenWaterProgram.mName = "Deferred Soften Underwater Shader";
+		gDeferredSoftenWaterProgram.mShaderFiles.clear();
+		gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSoftenWaterProgram.mShaderFiles.push_back(make_pair("deferred/softenLightF.glsl", GL_FRAGMENT_SHADER_ARB));
+
+		gDeferredSoftenWaterProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredSoftenWaterProgram.addPermutation("WATER_FOG", "1");
+		gDeferredSoftenWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
+
+		if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
+		{ //if using SSAO, take screen space light map into account as if shadows are enabled
+			gDeferredSoftenWaterProgram.mShaderLevel = llmax(gDeferredSoftenWaterProgram.mShaderLevel, 2);
+		}
+
+		success = gDeferredSoftenWaterProgram.createShader(NULL, &mWLUniforms);
+	}
+
 	if (success)
 	{
 		gDeferredShadowProgram.mName = "Deferred Shadow Shader";
@@ -1692,12 +1883,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 	if (success)
 	{
 		gDeferredAvatarAlphaProgram.mName = "Avatar Alpha Shader";
-		gDeferredAvatarAlphaProgram.mFeatures.atmosphericHelpers = true;
 		gDeferredAvatarAlphaProgram.mFeatures.hasSkinning = true;
 		gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = false;
-		gDeferredAvatarAlphaProgram.mFeatures.calculatesAtmospherics = true;
-		gDeferredAvatarAlphaProgram.mFeatures.hasGamma = true;
-		gDeferredAvatarAlphaProgram.mFeatures.hasAtmospherics = true;
 		gDeferredAvatarAlphaProgram.mFeatures.hasLighting = false;
 		gDeferredAvatarAlphaProgram.mFeatures.isAlphaLighting = true;
 		gDeferredAvatarAlphaProgram.mFeatures.disableTextureIndex = true;
@@ -1836,6 +2023,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		gObjectFullbrightNoColorProgram.unload();
 		gObjectFullbrightNoColorWaterProgram.unload();
 		gObjectSimpleProgram.unload();
+		gObjectSimpleImpostorProgram.unload();
 		gObjectPreviewProgram.unload();
 		gImpostorProgram.unload();
 		gObjectSimpleAlphaMaskProgram.unload();
@@ -2256,6 +2444,27 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 		success = gObjectSimpleProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gObjectSimpleImpostorProgram.mName = "Simple Impostor Shader";
+		gObjectSimpleImpostorProgram.mFeatures.calculatesLighting = true;
+		gObjectSimpleImpostorProgram.mFeatures.calculatesAtmospherics = true;
+		gObjectSimpleImpostorProgram.mFeatures.hasGamma = true;
+		gObjectSimpleImpostorProgram.mFeatures.hasAtmospherics = true;
+		gObjectSimpleImpostorProgram.mFeatures.hasLighting = true;
+		gObjectSimpleImpostorProgram.mFeatures.mIndexedTextureChannels = 0;
+		// force alpha mask version of lighting so we can weed out
+		// transparent pixels from impostor temp buffer
+		//
+		gObjectSimpleImpostorProgram.mFeatures.hasAlphaMask = true; 
+		gObjectSimpleImpostorProgram.mShaderFiles.clear();
+		gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleV.glsl", GL_VERTEX_SHADER_ARB));
+		gObjectSimpleImpostorProgram.mShaderFiles.push_back(make_pair("objects/simpleF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gObjectSimpleImpostorProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		
+		success = gObjectSimpleImpostorProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gObjectSimpleWaterProgram.mName = "Simple Water Shader";
@@ -3191,3 +3400,4 @@ LLViewerShaderMgr::shader_iter LLViewerShaderMgr::endShaders() const
 {
 	return mShaderList.end();
 }
+
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index 438853cd6f7ef46117c5014842945789958e924e..e4684c19d592ee0db17b3b16ee8786e36931118b 100755
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -30,6 +30,8 @@
 #include "llshadermgr.h"
 #include "llmaterial.h"
 
+#define LL_DEFERRED_MULTI_LIGHT_COUNT 16
+
 class LLViewerShaderMgr: public LLShaderMgr
 {
 public:
@@ -240,6 +242,7 @@ extern LLGLSLShader			gOneTextureNoColorProgram;
 
 //object shaders
 extern LLGLSLShader			gObjectSimpleProgram;
+extern LLGLSLShader			gObjectSimpleImpostorProgram;
 extern LLGLSLShader			gObjectPreviewProgram;
 extern LLGLSLShader			gObjectSimpleAlphaMaskProgram;
 extern LLGLSLShader			gObjectSimpleWaterProgram;
@@ -328,6 +331,7 @@ extern LLGLSLShader			gPostNightVisionProgram;
 // Deferred rendering shaders
 extern LLGLSLShader			gDeferredImpostorProgram;
 extern LLGLSLShader			gDeferredWaterProgram;
+extern LLGLSLShader			gDeferredUnderWaterProgram;
 extern LLGLSLShader			gDeferredDiffuseProgram;
 extern LLGLSLShader			gDeferredDiffuseAlphaMaskProgram;
 extern LLGLSLShader			gDeferredNonIndexedDiffuseAlphaMaskProgram;
@@ -341,13 +345,14 @@ extern LLGLSLShader			gDeferredTerrainProgram;
 extern LLGLSLShader			gDeferredTreeProgram;
 extern LLGLSLShader			gDeferredTreeShadowProgram;
 extern LLGLSLShader			gDeferredLightProgram;
-extern LLGLSLShader			gDeferredMultiLightProgram;
+extern LLGLSLShader			gDeferredMultiLightProgram[LL_DEFERRED_MULTI_LIGHT_COUNT];
 extern LLGLSLShader			gDeferredSpotLightProgram;
 extern LLGLSLShader			gDeferredMultiSpotLightProgram;
 extern LLGLSLShader			gDeferredSunProgram;
 extern LLGLSLShader			gDeferredBlurLightProgram;
 extern LLGLSLShader			gDeferredAvatarProgram;
 extern LLGLSLShader			gDeferredSoftenProgram;
+extern LLGLSLShader			gDeferredSoftenWaterProgram;
 extern LLGLSLShader			gDeferredShadowProgram;
 extern LLGLSLShader			gDeferredShadowCubeProgram;
 extern LLGLSLShader			gDeferredShadowAlphaMaskProgram;
@@ -360,7 +365,12 @@ extern LLGLSLShader			gDeferredPostGammaCorrectProgram;
 extern LLGLSLShader			gDeferredAvatarShadowProgram;
 extern LLGLSLShader			gDeferredAttachmentShadowProgram;
 extern LLGLSLShader			gDeferredAlphaProgram;
+extern LLGLSLShader			gDeferredAlphaImpostorProgram;
 extern LLGLSLShader			gDeferredFullbrightProgram;
+extern LLGLSLShader			gDeferredFullbrightAlphaMaskProgram;
+extern LLGLSLShader			gDeferredAlphaWaterProgram;
+extern LLGLSLShader			gDeferredFullbrightWaterProgram;
+extern LLGLSLShader			gDeferredFullbrightAlphaMaskWaterProgram;
 extern LLGLSLShader			gDeferredEmissiveProgram;
 extern LLGLSLShader			gDeferredAvatarEyesProgram;
 extern LLGLSLShader			gDeferredAvatarAlphaProgram;
@@ -374,5 +384,6 @@ extern LLGLSLShader			gNormalMapGenProgram;
 
 // Deferred materials shaders
 extern LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
-
+extern LLGLSLShader			gDeferredMaterialWaterProgram[LLMaterial::SHADER_COUNT*2];
 #endif
+
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index 2de31cae98826574b33304149b777a75ca068335..d64db19733b4e658355dccf3db9e7f0cfb6200af 100755
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -562,11 +562,11 @@ void LLViewerTextureList::addImageToList(LLViewerFetchedTexture *image)
 	llassert(image);
 	if (image->isInImageList())
 	{
-		llerrs << "LLViewerTextureList::addImageToList - Image already in list" << llendl;
+		llinfos << "LLViewerTextureList::addImageToList - Image already in list" << llendl;
 	}
 	if((mImageList.insert(image)).second != true) 
 	{
-		llerrs << "Error happens when insert image to mImageList!" << llendl ;
+		llinfos << "Error happens when insert image to mImageList!" << llendl ;
 	}
 	
 	image->setInImageList(TRUE) ;
@@ -585,14 +585,14 @@ void LLViewerTextureList::removeImageFromList(LLViewerFetchedTexture *image)
 		{
 			llinfos << "Image is not in mUUIDMap!" << llendl ;
 		}
-		llerrs << "LLViewerTextureList::removeImageFromList - Image not in list" << llendl;
+		llinfos << "LLViewerTextureList::removeImageFromList - Image not in list" << llendl;
 	}
 
 	S32 count = mImageList.erase(image) ;
+	llassert(count == 1);
 	if(count != 1) 
 	{
-		llinfos << image->getID() << llendl ;
-		llerrs << "Error happens when remove image from mImageList: " << count << llendl ;
+		llinfos << image->getID() << " removed with non-one count of " << count << llendl;
 	}
       
 	image->setInImageList(FALSE) ;
@@ -602,15 +602,15 @@ void LLViewerTextureList::addImage(LLViewerFetchedTexture *new_image)
 {
 	if (!new_image)
 	{
-		llwarning("No image to add to image list", 0);
 		return;
 	}
+	llassert(new_image);
 	LLUUID image_id = new_image->getID();
 	
 	LLViewerFetchedTexture *image = findImage(image_id);
 	if (image)
 	{
-		llwarns << "Image with ID " << image_id << " already in list" << llendl;
+		llinfos << "Image with ID " << image_id << " already in list" << llendl;
 	}
 	sNumImages++;
 	
@@ -1281,7 +1281,7 @@ S32 LLViewerTextureList::getMaxVideoRamSetting(bool get_recommended, float mem_m
 		max_texmem = llmin(max_texmem, (S32)(system_ram/2));
 	else
 		max_texmem = llmin(max_texmem, (S32)(system_ram));
-    
+		
     // limit the texture memory to a multiple of the default if we've found some cards to behave poorly otherwise
 	max_texmem = llmin(max_texmem, (S32) (mem_multiplier * (F32) max_texmem));
 
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index e6385dceeac8eccb0bad86ce4589c0c014a19b70..6b3611b7965cff12c066f13272f879662729ec22 100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -1114,7 +1114,7 @@ void LLVOVolume::sculpt()
 		S32 max_discard = mSculptTexture->getMaxDiscardLevel();
 		if (discard_level > max_discard)
 		{
-			discard_level = max_discard;    // clamp to the best we can do			
+			discard_level = max_discard;    // clamp to the best we can do
 		}
 		if(discard_level > MAX_DISCARD_LEVEL)
 		{
@@ -1458,7 +1458,7 @@ BOOL LLVOVolume::genBBoxes(BOOL force_global)
 			continue;
 		}
 		res &= face->genVolumeBBoxes(*volume, i,
-										mRelativeXform, 
+										mRelativeXform, /*mRelativeXformInvTrans,*/
 										(mVolumeImpl && mVolumeImpl->isVolumeGlobal()) || force_global);
 		
 		if (rebuild)
@@ -2596,6 +2596,7 @@ void LLVOVolume::setLightTextureID(LLUUID id)
 		if (hasLightTexture())
 		{
 			setParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE, FALSE, true);
+			parameterChanged(LLNetworkData::PARAMS_LIGHT_IMAGE, true);
 			mLightTexture = NULL;
 		}
 	}		
@@ -2613,7 +2614,8 @@ void LLVOVolume::setSpotLightParams(LLVector3 params)
 		
 void LLVOVolume::setIsLight(BOOL is_light)
 {
-	if (is_light != getIsLight())
+	BOOL was_light = getIsLight();
+	if (is_light != was_light)
 	{
 		if (is_light)
 		{
@@ -2798,7 +2800,7 @@ void LLVOVolume::updateSpotLightPriority()
 bool LLVOVolume::isLightSpotlight() const
 {
 	LLLightImageParams* params = (LLLightImageParams*) getParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE);
-	if (params)
+	if (params && getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT_IMAGE))
 	{
 		return params->isLightSpotlight();
 	}
@@ -3728,8 +3730,30 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a&
 			{
 				LLFace* face = mDrawable->getFace(face_hit);				
 
+				bool ignore_alpha = false;
+
+				const LLTextureEntry* te = face->getTextureEntry();
+				if (te)
+				{
+					LLMaterial* mat = te->getMaterialParams();
+					if (mat)
+					{
+						U8 mode = mat->getDiffuseAlphaMode();
+
+						if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE ||
+							mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE)
+						{
+							ignore_alpha = true;
+						}
+					}
+				}
+
 				if (face &&
-					(pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))))
+					(ignore_alpha ||
+					pick_transparent || 
+					!face->getTexture() || 
+					!face->getTexture()->hasGLTexture() || 
+					face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))))
 				{
 					local_end = p;
 					if (face_hitp != NULL)
@@ -4841,7 +4865,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 			{
 				if (!drawablep->isState(LLDrawable::RIGGED))
 				{
-					drawablep->setState(LLDrawable::RIGGED);
+				drawablep->setState(LLDrawable::RIGGED);
 
 					//first time this is drawable is being marked as rigged,
 					// do another LoD update to use avatar bounding box
@@ -5367,19 +5391,24 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 								mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE;
 			}
 
-			bool use_legacy_bump = te->getBumpmap() && (!mat || mat->getNormalID().isNull());
+			bool use_legacy_bump = te->getBumpmap() && (te->getBumpmap() < 18) && (!mat || mat->getNormalID().isNull());
+			bool opaque = te->getColor().mV[3] >= 0.999f;
 
 			if (mat && LLPipeline::sRenderDeferred && !hud_group)
 			{
 				bool material_pass = false;
 
-				if (fullbright)
+				// do NOT use 'fullbright' for this logic or you risk sending
+				// things without normals down the materials pipeline and will
+				// render poorly if not crash NORSPEC-240,314
+				//
+				if (te->getFullbright())
 				{
 					if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
 					{
-						if (te->getColor().mV[3] >= 0.999f)
+						if (opaque)
 						{
-							material_pass = true;
+							registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
 						}
 						else
 						{
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index f49395da349e57ef71a5d39b1b8e452ce1fffb7f..b4e59909db64a9134d790b064d955dd20db6d6c8 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -111,6 +111,8 @@
 #include "llpathinglib.h"
 #include "llfloaterpathfindingconsole.h"
 #include "llfloaterpathfindingcharacters.h"
+#include "llfloatertools.h"
+#include "llpanelface.h"
 #include "llpathfindingpathtool.h"
 
 #ifdef _DEBUG
@@ -120,6 +122,10 @@
 //#define DEBUG_INDICES
 #endif
 
+// Expensive and currently broken
+//
+#define MATERIALS_IN_REFLECTIONS 0
+
 bool gShiftFrame = false;
 
 //cached settings
@@ -374,6 +380,7 @@ BOOL	LLPipeline::sWaterReflections = FALSE;
 BOOL	LLPipeline::sRenderGlow = FALSE;
 BOOL	LLPipeline::sReflectionRender = FALSE;
 BOOL	LLPipeline::sImpostorRender = FALSE;
+BOOL	LLPipeline::sImpostorRenderAlphaDepthPass = FALSE;
 BOOL	LLPipeline::sUnderWaterRender = FALSE;
 BOOL	LLPipeline::sTextureBindTest = FALSE;
 BOOL	LLPipeline::sRenderFrameTest = FALSE;
@@ -789,14 +796,22 @@ void LLPipeline::resizeScreenTexture()
 		GLuint resX = gViewerWindow->getWorldViewWidthRaw();
 		GLuint resY = gViewerWindow->getWorldViewHeightRaw();
 	
-		if (!allocateScreenBuffer(resX,resY))
-		{ //FAILSAFE: screen buffer allocation failed, disable deferred rendering if it's enabled
-			//NOTE: if the session closes successfully after this call, deferred rendering will be 
-			// disabled on future sessions
-			if (LLPipeline::sRenderDeferred)
+		if ((resX != mScreen.getWidth()) || (resY != mScreen.getHeight()))
+		{
+			releaseScreenBuffers();
+			if (!allocateScreenBuffer(resX,resY))
 			{
-				gSavedSettings.setBOOL("RenderDeferred", FALSE);
-				LLPipeline::refreshCachedSettings();
+#if PROBABLE_FALSE_DISABLES_OF_ALM_HERE
+				//FAILSAFE: screen buffer allocation failed, disable deferred rendering if it's enabled
+				//NOTE: if the session closes successfully after this call, deferred rendering will be 
+				// disabled on future sessions
+				if (LLPipeline::sRenderDeferred)
+				{
+					gSavedSettings.setBOOL("RenderDeferred", FALSE);
+					LLPipeline::refreshCachedSettings();
+
+				}
+#endif
 			}
 		}
 	}
@@ -1186,7 +1201,8 @@ void LLPipeline::releaseGLBuffers()
 
 	mWaterRef.release();
 	mWaterDis.release();
-	
+	mHighlight.release();
+
 	for (U32 i = 0; i < 3; i++)
 	{
 		mGlow[i].release();
@@ -1216,12 +1232,12 @@ void LLPipeline::releaseScreenBuffers()
 	mDeferredScreen.release();
 	mDeferredDepth.release();
 	mDeferredLight.release();
-	
-	mHighlight.release();
+	mOcclusionDepth.release();
 		
 	for (U32 i = 0; i < 6; i++)
 	{
 		mShadow[i].release();
+		mShadowOcclusion[i].release();
 	}
 }
 
@@ -1233,14 +1249,31 @@ void LLPipeline::createGLBuffers()
 
 	updateRenderDeferred();
 
+	bool materials_in_water = false;
+
+#if MATERIALS_IN_REFLECTIONS
+	materials_in_water = gSavedSettings.getS32("RenderWaterMaterials");
+#endif
+
 	if (LLPipeline::sWaterReflections)
 	{ //water reflection texture
 		U32 res = (U32) llmax(gSavedSettings.getS32("RenderWaterRefResolution"), 512);
 			
+		// Set up SRGB targets if we're doing deferred-path reflection rendering
+		//
+		if (LLPipeline::sRenderDeferred && materials_in_water)
+		{
+			mWaterRef.allocate(res,res,GL_SRGB8_ALPHA8,TRUE,FALSE);
+			//always use FBO for mWaterDis so it can be used for avatar texture bakes
+			mWaterDis.allocate(res,res,GL_SRGB8_ALPHA8,TRUE,FALSE,LLTexUnit::TT_TEXTURE, true);
+		}
+		else
+		{
 		mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE);
 		//always use FBO for mWaterDis so it can be used for avatar texture bakes
 		mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE,LLTexUnit::TT_TEXTURE, true);
 	}
+	}
 
 	mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE);
 
@@ -1402,9 +1435,15 @@ void LLPipeline::createLUTBuffers()
 				}
 			}
 			
-			LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_R16F, 1, &mLightFunc);
+			U32 pix_format = GL_R16F;
+#if LL_DARWIN
+			// Need to work around limited precision with 10.6.8 and older drivers
+			//
+			pix_format = GL_R32F;
+#endif
+			LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, pix_format, 1, &mLightFunc);
 			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
-			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R16F, lightResX, lightResY, GL_RED, GL_FLOAT, ls, false);
+			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, pix_format, lightResX, lightResY, GL_RED, GL_FLOAT, ls, false);
 			//LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_UNSIGNED_BYTE, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, ls, false);
 			gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
 			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
@@ -2443,7 +2482,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	if (to_texture)
 	{
-		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+		if (LLPipeline::sRenderDeferred)
 		{
 			mOcclusionDepth.bindTarget();
 		}
@@ -2588,7 +2627,7 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	if (to_texture)
 	{
-		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+		if (LLPipeline::sRenderDeferred)
 		{
 			mOcclusionDepth.flush();
 		}
@@ -3959,7 +3998,7 @@ void LLPipeline::postSort(LLCamera& camera)
 	{
 		mSelectedFaces.clear();
 
-		LLPipeline::setRenderHighlightTextureChannel(LLSelectMgr::getInstance()->getTextureChannel());
+		LLPipeline::setRenderHighlightTextureChannel(gFloaterTools->getPanelFace()->getTextureChannelToEdit());
 
 		// Draw face highlights for selected faces.
 		if (LLSelectMgr::getInstance()->getTEMode())
@@ -5383,7 +5422,7 @@ void LLPipeline::renderDebug()
 			if (i > 3)
 			{ //render shadow frusta as volumes
 				if (mShadowFrustPoints[i-4].empty())
-				{
+			{
 					continue;
 				}
 
@@ -8527,7 +8566,7 @@ void LLPipeline::renderDeferredLighting()
 		if (RenderDeferredAtmospheric)
 		{ //apply sunlight contribution 
 			LLFastTimer ftm(FTM_ATMOSPHERICS);
-			bindDeferredShader(gDeferredSoftenProgram);	
+			bindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);	
 			{
 				LLGLDepthTest depth(GL_FALSE);
 				LLGLDisable blend(GL_BLEND);
@@ -8549,7 +8588,7 @@ void LLPipeline::renderDeferredLighting()
 				gGL.popMatrix();
 			}
 
-			unbindDeferredShader(gDeferredSoftenProgram);
+			unbindDeferredShader(LLPipeline::sUnderWaterRender ? gDeferredSoftenWaterProgram : gDeferredSoftenProgram);
 		}
 
 		{ //render non-deferred geometry (fullbright, alpha, etc)
@@ -8742,10 +8781,6 @@ void LLPipeline::renderDeferredLighting()
 			vert[2].set(3,1,0);
 
 			{
-				bindDeferredShader(gDeferredMultiLightProgram);
-			
-				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
-
 				LLGLDepthTest depth(GL_FALSE);
 
 				//full screen blit
@@ -8757,7 +8792,7 @@ void LLPipeline::renderDeferredLighting()
 
 				U32 count = 0;
 
-				const U32 max_count = 8;
+				const U32 max_count = LL_DEFERRED_MULTI_LIGHT_COUNT;
 				LLVector4 light[max_count];
 				LLVector4 col[max_count];
 
@@ -8780,18 +8815,20 @@ void LLPipeline::renderDeferredLighting()
 					count++;
 					if (count == max_count || fullscreen_lights.empty())
 					{
-						gDeferredMultiLightProgram.uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count);
-						gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light);
-						gDeferredMultiLightProgram.uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col);
-						gDeferredMultiLightProgram.uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
+						U32 idx = count-1;
+						bindDeferredShader(gDeferredMultiLightProgram[idx]);
+						gDeferredMultiLightProgram[idx].uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count);
+						gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light);
+						gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col);
+						gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
 						far_z = 0.f;
 						count = 0; 
+      mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
 						mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+						unbindDeferredShader(gDeferredMultiLightProgram[idx]);
 					}
 				}
 				
-				unbindDeferredShader(gDeferredMultiLightProgram);
-
 				bindDeferredShader(gDeferredMultiSpotLightProgram);
 
 				gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
@@ -8872,9 +8909,9 @@ void LLPipeline::renderDeferredLighting()
 		
 		gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mScreen.getWidth(), mScreen.getHeight());
 		
-		F32 gamma = 1.0/2.2;
+		F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
 
-		gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, gamma);
+		gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
 		
 		gGL.begin(LLRender::TRIANGLE_STRIP);
 		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
@@ -8953,134 +8990,665 @@ void LLPipeline::renderDeferredLighting()
 						
 }
 
-void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
+void LLPipeline::renderDeferredLightingToRT(LLRenderTarget* target)
 {
-	//construct frustum
-	LLVOVolume* volume = drawablep->getVOVolume();
-	LLVector3 params = volume->getSpotLightParams();
-
-	F32 fov = params.mV[0];
-	F32 focus = params.mV[1];
+	if (!sCull)
+	{
+		return;
+	}
 
-	LLVector3 pos = drawablep->getPositionAgent();
-	LLQuaternion quat = volume->getRenderRotation();
-	LLVector3 scale = volume->getScale();
-	
-	//get near clip plane
-	LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
-	at_axis *= quat;
+	{
+		LLFastTimer ftm(FTM_RENDER_DEFERRED);
 
-	LLVector3 np = pos+at_axis;
-	at_axis.normVec();
+		LLViewerCamera* camera = LLViewerCamera::getInstance();
 
-	//get origin that has given fov for plane np, at_axis, and given scale
-	F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+		{
+			LLGLDepthTest depth(GL_TRUE);
+			mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+							0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);	
+		}
 
-	LLVector3 origin = np - at_axis*dist;
+		LLGLEnable multisample(RenderFSAASamples > 0 ? GL_MULTISAMPLE_ARB : 0);
 
-	//matrix from volume space to agent space
-	LLMatrix4 light_mat(quat, LLVector4(origin,1.f));
+		if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+		{
+			gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+		}
 
-	glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
-	glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
+		//ati doesn't seem to love actually using the stencil buffer on FBO's
+		LLGLDisable stencil(GL_STENCIL_TEST);
+		//glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
+		//glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
 
-	glh::matrix4f screen_to_light = light_to_screen.inverse();
+		gGL.setColorMask(true, true);
+		
+		//draw a cube around every light
+		LLVertexBuffer::unbind();
 
-	F32 s = volume->getLightRadius()*1.5f;
-	F32 near_clip = dist;
-	F32 width = scale.mV[VX];
-	F32 height = scale.mV[VY];
-	F32 far_clip = s+dist-scale.mV[VZ];
+		LLGLEnable cull(GL_CULL_FACE);
+		LLGLEnable blend(GL_BLEND);
 
-	F32 fovy = fov * RAD_TO_DEG;
-	F32 aspect = width/height;
+		glh::matrix4f mat = glh_copy_matrix(gGLModelView);
 
-	glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
-				0.f, 0.5f, 0.f, 0.5f,
-				0.f, 0.f, 0.5f, 0.5f,
-				0.f, 0.f, 0.f, 1.f);
+		LLStrider<LLVector3> vert; 
+		mDeferredVB->getVertexStrider(vert);
+		
+		vert[0].set(-1,1,0);
+		vert[1].set(-1,-3,0);
+		vert[2].set(3,1,0);
+		
+		{
+			setupHWLights(NULL); //to set mSunDir;
+			LLVector4 dir(mSunDir, 0.f);
+			glh::vec4f tc(dir.mV);
+			mat.mult_matrix_vec(tc);
+			mTransformedSunDir.set(tc.v);
+		}
 
-	glh::vec3f p1(0, 0, -(near_clip+0.01f));
-	glh::vec3f p2(0, 0, -(near_clip+1.f));
+		gGL.pushMatrix();
+		gGL.loadIdentity();
+		gGL.matrixMode(LLRender::MM_PROJECTION);
+		gGL.pushMatrix();
+		gGL.loadIdentity();
 
-	glh::vec3f screen_origin(0, 0, 0);
+		if (RenderDeferredSSAO || RenderShadowDetail > 0)
+		{
+			mDeferredLight.bindTarget();
+			{ //paint shadow/SSAO light map (direct lighting lightmap)
+				LLFastTimer ftm(FTM_SUN_SHADOW);
+				bindDeferredShader(gDeferredSunProgram);
+				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+				glClearColor(1,1,1,1);
+				mDeferredLight.clear(GL_COLOR_BUFFER_BIT);
+				glClearColor(0,0,0,0);
 
-	light_to_screen.mult_matrix_vec(p1);
-	light_to_screen.mult_matrix_vec(p2);
-	light_to_screen.mult_matrix_vec(screen_origin);
+				glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
 
-	glh::vec3f n = p2-p1;
-	n.normalize();
-	
-	F32 proj_range = far_clip - near_clip;
-	glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip);
-	screen_to_light = trans * light_proj * screen_to_light;
-	shader.uniformMatrix4fv(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.m);
-	shader.uniform1f(LLShaderMgr::PROJECTOR_NEAR, near_clip);
-	shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.v);
-	shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.v);
-	shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.v);
-	shader.uniform1f(LLShaderMgr::PROJECTOR_RANGE, proj_range);
-	shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIANCE, params.mV[2]);
-	S32 s_idx = -1;
+				const U32 slice = 32;
+				F32 offset[slice*3];
+				for (U32 i = 0; i < 4; i++)
+				{
+					for (U32 j = 0; j < 8; j++)
+					{
+						glh::vec3f v;
+						v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
+						v.normalize();
+						inv_trans.mult_matrix_vec(v);
+						v.normalize();
+						offset[(i*8+j)*3+0] = v.v[0];
+						offset[(i*8+j)*3+1] = v.v[2];
+						offset[(i*8+j)*3+2] = v.v[1];
+					}
+				}
 
-	for (U32 i = 0; i < 2; i++)
-	{
-		if (mShadowSpotLight[i] == drawablep)
-		{
-			s_idx = i;
+				gDeferredSunProgram.uniform3fv("offset", slice, offset);
+				gDeferredSunProgram.uniform2f("screenRes", mDeferredLight.getWidth(), mDeferredLight.getHeight());
+				
+				{
+					LLGLDisable blend(GL_BLEND);
+					LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+					stop_glerror();
+					mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+					stop_glerror();
+				}
+				
+				unbindDeferredShader(gDeferredSunProgram);
+			}
+			mDeferredLight.flush();
 		}
-	}
+				
+		stop_glerror();
+		gGL.popMatrix();
+		stop_glerror();
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+		stop_glerror();
+		gGL.popMatrix();
+		stop_glerror();
 
-	shader.uniform1i(LLShaderMgr::PROJECTOR_SHADOW_INDEX, s_idx);
+		target->bindTarget();
 
-	if (s_idx >= 0)
-	{
-		shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f-mSpotLightFade[s_idx]);
-	}
-	else
-	{
-		shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f);
-	}
+		//clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky
+		glClearColor(0,0,0,0);
+		target->clear(GL_COLOR_BUFFER_BIT);
+		
+		if (RenderDeferredAtmospheric)
+		{ //apply sunlight contribution 
+			LLFastTimer ftm(FTM_ATMOSPHERICS);
+			bindDeferredShader(gDeferredSoftenProgram);	
+			{
+				LLGLDepthTest depth(GL_FALSE);
+				LLGLDisable blend(GL_BLEND);
+				LLGLDisable test(GL_ALPHA_TEST);
 
-	{
-		LLDrawable* potential = drawablep;
-		//determine if this is a good light for casting shadows
-		F32 m_pri = volume->getSpotLightPriority();
+				//full screen blit
+				gGL.pushMatrix();
+				gGL.loadIdentity();
+				gGL.matrixMode(LLRender::MM_PROJECTION);
+				gGL.pushMatrix();
+				gGL.loadIdentity();
 
-		for (U32 i = 0; i < 2; i++)
-		{
-			F32 pri = 0.f;
+				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+				
+				mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
 
-			if (mTargetShadowSpotLight[i].notNull())
-			{
-				pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();			
+				gGL.popMatrix();
+				gGL.matrixMode(LLRender::MM_MODELVIEW);
+				gGL.popMatrix();
 			}
 
-			if (m_pri > pri)
-			{
-				LLDrawable* temp = mTargetShadowSpotLight[i];
-				mTargetShadowSpotLight[i] = potential;
-				potential = temp;
-				m_pri = pri;
-			}
+			unbindDeferredShader(gDeferredSoftenProgram);
 		}
-	}
-
-	LLViewerTexture* img = volume->getLightTexture();
-
-	if (img == NULL)
-	{
-		img = LLViewerFetchedTexture::sWhiteImagep;
-	}
 
-	S32 channel = shader.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+		{ //render non-deferred geometry (fullbright, alpha, etc)
+			LLGLDisable blend(GL_BLEND);
+			LLGLDisable stencil(GL_STENCIL_TEST);
+			gGL.setSceneBlendType(LLRender::BT_ALPHA);
 
-	if (channel > -1)
-	{
-		if (img)
-		{
-			gGL.getTexUnit(channel)->bind(img);
+			gPipeline.pushRenderTypeMask();
+			
+			gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+										LLPipeline::RENDER_TYPE_CLOUDS,
+										LLPipeline::RENDER_TYPE_WL_SKY,
+										LLPipeline::END_RENDER_TYPES);
+								
+			
+			renderGeomPostDeferred(*LLViewerCamera::getInstance(), false);
+			gPipeline.popRenderTypeMask();
+		}
+
+		BOOL render_local = RenderLocalLights;
+				
+		if (render_local)
+		{
+			gGL.setSceneBlendType(LLRender::BT_ADD);
+			std::list<LLVector4> fullscreen_lights;
+			LLDrawable::drawable_list_t spot_lights;
+			LLDrawable::drawable_list_t fullscreen_spot_lights;
+
+			for (U32 i = 0; i < 2; i++)
+			{
+				mTargetShadowSpotLight[i] = NULL;
+			}
+
+			std::list<LLVector4> light_colors;
+
+			LLVertexBuffer::unbind();
+
+			{
+				bindDeferredShader(gDeferredLightProgram);
+				
+				if (mCubeVB.isNull())
+				{
+					mCubeVB = ll_create_cube_vb(LLVertexBuffer::MAP_VERTEX, GL_STATIC_DRAW_ARB);
+				}
+
+				mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+				
+				LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+				for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
+				{
+					LLDrawable* drawablep = *iter;
+					
+					LLVOVolume* volume = drawablep->getVOVolume();
+					if (!volume)
+					{
+						continue;
+					}
+
+					if (volume->isAttachment())
+					{
+						if (!sRenderAttachedLights)
+						{
+							continue;
+						}
+					}
+
+
+					LLVector4a center;
+					center.load3(drawablep->getPositionAgent().mV);
+					const F32* c = center.getF32ptr();
+					F32 s = volume->getLightRadius()*1.5f;
+
+					LLColor3 col = volume->getLightColor();
+					
+					if (col.magVecSquared() < 0.001f)
+					{
+						continue;
+					}
+
+					if (s <= 0.001f)
+					{
+						continue;
+					}
+
+					LLVector4a sa;
+					sa.splat(s);
+					if (camera->AABBInFrustumNoFarClip(center, sa) == 0)
+					{
+						continue;
+					}
+
+					sVisibleLightCount++;
+										
+					if (camera->getOrigin().mV[0] > c[0] + s + 0.2f ||
+						camera->getOrigin().mV[0] < c[0] - s - 0.2f ||
+						camera->getOrigin().mV[1] > c[1] + s + 0.2f ||
+						camera->getOrigin().mV[1] < c[1] - s - 0.2f ||
+						camera->getOrigin().mV[2] > c[2] + s + 0.2f ||
+						camera->getOrigin().mV[2] < c[2] - s - 0.2f)
+					{ //draw box if camera is outside box
+						if (render_local)
+						{
+							if (volume->isLightSpotlight())
+							{
+								drawablep->getVOVolume()->updateSpotLightPriority();
+								spot_lights.push_back(drawablep);
+								continue;
+							}
+							
+							/*col.mV[0] = powf(col.mV[0], 2.2f);
+							col.mV[1] = powf(col.mV[1], 2.2f);
+							col.mV[2] = powf(col.mV[2], 2.2f);*/
+							
+							LLFastTimer ftm(FTM_LOCAL_LIGHTS);
+							gDeferredLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
+							gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
+							gDeferredLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
+							gDeferredLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
+							gGL.syncMatrices();
+							
+							mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center));
+							stop_glerror();
+						}
+					}
+					else
+					{	
+						if (volume->isLightSpotlight())
+						{
+							drawablep->getVOVolume()->updateSpotLightPriority();
+							fullscreen_spot_lights.push_back(drawablep);
+							continue;
+						}
+
+						glh::vec3f tc(c);
+						mat.mult_matrix_vec(tc);
+					
+						fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s));
+						light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
+					}
+				}
+				unbindDeferredShader(gDeferredLightProgram);
+			}
+
+			if (!spot_lights.empty())
+			{
+				LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+				bindDeferredShader(gDeferredSpotLightProgram);
+
+				mCubeVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+				gDeferredSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+
+				for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
+				{
+					LLFastTimer ftm(FTM_PROJECTORS);
+					LLDrawable* drawablep = *iter;
+
+					LLVOVolume* volume = drawablep->getVOVolume();
+
+					LLVector4a center;
+					center.load3(drawablep->getPositionAgent().mV);
+					const F32* c = center.getF32ptr();
+					F32 s = volume->getLightRadius()*1.5f;
+
+					sVisibleLightCount++;
+
+					setupSpotLight(gDeferredSpotLightProgram, drawablep);
+					
+					LLColor3 col = volume->getLightColor();
+					/*col.mV[0] = powf(col.mV[0], 2.2f);
+					col.mV[1] = powf(col.mV[1], 2.2f);
+					col.mV[2] = powf(col.mV[2], 2.2f);*/
+					
+					gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, c);
+					gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
+					gDeferredSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
+					gDeferredSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
+					gGL.syncMatrices();
+										
+					mCubeVB->drawRange(LLRender::TRIANGLE_FAN, 0, 7, 8, get_box_fan_indices(camera, center));
+				}
+				gDeferredSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+				unbindDeferredShader(gDeferredSpotLightProgram);
+			}
+
+			//reset mDeferredVB to fullscreen triangle
+			mDeferredVB->getVertexStrider(vert);
+			vert[0].set(-1,1,0);
+			vert[1].set(-1,-3,0);
+			vert[2].set(3,1,0);
+
+			{
+				LLGLDepthTest depth(GL_FALSE);
+
+				//full screen blit
+				gGL.pushMatrix();
+				gGL.loadIdentity();
+				gGL.matrixMode(LLRender::MM_PROJECTION);
+				gGL.pushMatrix();
+				gGL.loadIdentity();
+
+				U32 count = 0;
+
+				const U32 max_count = LL_DEFERRED_MULTI_LIGHT_COUNT;
+				LLVector4 light[max_count];
+				LLVector4 col[max_count];
+
+				F32 far_z = 0.f;
+
+				while (!fullscreen_lights.empty())
+				{
+					LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS);
+					light[count] = fullscreen_lights.front();
+					fullscreen_lights.pop_front();
+					col[count] = light_colors.front();
+					light_colors.pop_front();
+					
+					/*col[count].mV[0] = powf(col[count].mV[0], 2.2f);
+					col[count].mV[1] = powf(col[count].mV[1], 2.2f);
+					col[count].mV[2] = powf(col[count].mV[2], 2.2f);*/
+					
+					far_z = llmin(light[count].mV[2]-light[count].mV[3], far_z);
+					//col[count] = pow4fsrgb(col[count], 2.2f);
+					count++;
+					if (count == max_count || fullscreen_lights.empty())
+					{
+						U32 idx = count-1;
+						bindDeferredShader(gDeferredMultiLightProgram[idx]);
+						gDeferredMultiLightProgram[idx].uniform1i(LLShaderMgr::MULTI_LIGHT_COUNT, count);
+						gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT, count, (GLfloat*) light);
+						gDeferredMultiLightProgram[idx].uniform4fv(LLShaderMgr::MULTI_LIGHT_COL, count, (GLfloat*) col);
+						gDeferredMultiLightProgram[idx].uniform1f(LLShaderMgr::MULTI_LIGHT_FAR_Z, far_z);
+						far_z = 0.f;
+						count = 0; 
+						mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+						mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+					}
+				}
+				
+				unbindDeferredShader(gDeferredMultiLightProgram[0]);
+
+				bindDeferredShader(gDeferredMultiSpotLightProgram);
+
+				gDeferredMultiSpotLightProgram.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+
+				mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+
+				for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
+				{
+					LLFastTimer ftm(FTM_PROJECTORS);
+					LLDrawable* drawablep = *iter;
+					
+					LLVOVolume* volume = drawablep->getVOVolume();
+
+					LLVector3 center = drawablep->getPositionAgent();
+					F32* c = center.mV;
+					F32 s = volume->getLightRadius()*1.5f;
+
+					sVisibleLightCount++;
+
+					glh::vec3f tc(c);
+					mat.mult_matrix_vec(tc);
+					
+					setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
+
+					LLColor3 col = volume->getLightColor();
+					
+					/*col.mV[0] = powf(col.mV[0], 2.2f);
+					col.mV[1] = powf(col.mV[1], 2.2f);
+					col.mV[2] = powf(col.mV[2], 2.2f);*/
+					
+					gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::LIGHT_CENTER, 1, tc.v);
+					gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_SIZE, s);
+					gDeferredMultiSpotLightProgram.uniform3fv(LLShaderMgr::DIFFUSE_COLOR, 1, col.mV);
+					gDeferredMultiSpotLightProgram.uniform1f(LLShaderMgr::LIGHT_FALLOFF, volume->getLightFalloff()*0.5f);
+					mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+				}
+
+				gDeferredMultiSpotLightProgram.disableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+				unbindDeferredShader(gDeferredMultiSpotLightProgram);
+
+				gGL.popMatrix();
+				gGL.matrixMode(LLRender::MM_MODELVIEW);
+				gGL.popMatrix();
+			}
+		}
+
+		gGL.setColorMask(true, true);
+	}
+
+	/*target->flush();
+
+	//gamma correct lighting
+	gGL.matrixMode(LLRender::MM_PROJECTION);
+	gGL.pushMatrix();
+	gGL.loadIdentity();
+	gGL.matrixMode(LLRender::MM_MODELVIEW);
+	gGL.pushMatrix();
+	gGL.loadIdentity();
+
+	{
+		LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+
+		LLVector2 tc1(0,0);
+		LLVector2 tc2((F32) target->getWidth()*2,
+				  (F32) target->getHeight()*2);
+
+		target->bindTarget();
+		// Apply gamma correction to the frame here.
+		gDeferredPostGammaCorrectProgram.bind();
+		//mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+		S32 channel = 0;
+		channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, target->getUsage());
+		if (channel > -1)
+		{
+			target->bindTexture(0,channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+		}
+		
+		gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, target->getWidth(), target->getHeight());
+		
+		F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma");
+
+		gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f/2.2f));
+		
+		gGL.begin(LLRender::TRIANGLE_STRIP);
+		gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+		gGL.vertex2f(-1,-1);
+		
+		gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+		gGL.vertex2f(-1,3);
+		
+		gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+		gGL.vertex2f(3,-1);
+		
+		gGL.end();
+		
+		gGL.getTexUnit(channel)->unbind(target->getUsage());
+		gDeferredPostGammaCorrectProgram.unbind();
+		target->flush();
+	}
+
+	gGL.matrixMode(LLRender::MM_PROJECTION);
+	gGL.popMatrix();
+	gGL.matrixMode(LLRender::MM_MODELVIEW);
+	gGL.popMatrix();	
+
+	target->bindTarget();*/
+
+	{ //render non-deferred geometry (alpha, fullbright, glow)
+		LLGLDisable blend(GL_BLEND);
+		LLGLDisable stencil(GL_STENCIL_TEST);
+
+		pushRenderTypeMask();
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+						 LLPipeline::RENDER_TYPE_FULLBRIGHT,
+						 LLPipeline::RENDER_TYPE_VOLUME,
+						 LLPipeline::RENDER_TYPE_GLOW,
+						 LLPipeline::RENDER_TYPE_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+						 LLPipeline::RENDER_TYPE_PASS_ALPHA,
+						 LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_PASS_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+						 LLPipeline::RENDER_TYPE_PASS_GLOW,
+						 LLPipeline::RENDER_TYPE_PASS_GRASS,
+						 LLPipeline::RENDER_TYPE_PASS_SHINY,
+						 LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+						 LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+						 LLPipeline::RENDER_TYPE_AVATAR,
+						 LLPipeline::RENDER_TYPE_ALPHA_MASK,
+						 LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK,
+						 END_RENDER_TYPES);
+		
+		renderGeomPostDeferred(*LLViewerCamera::getInstance());
+		popRenderTypeMask();
+	}
+
+	//target->flush();				
+}
+
+void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
+{
+	//construct frustum
+	LLVOVolume* volume = drawablep->getVOVolume();
+	LLVector3 params = volume->getSpotLightParams();
+
+	F32 fov = params.mV[0];
+	F32 focus = params.mV[1];
+
+	LLVector3 pos = drawablep->getPositionAgent();
+	LLQuaternion quat = volume->getRenderRotation();
+	LLVector3 scale = volume->getScale();
+	
+	//get near clip plane
+	LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+	at_axis *= quat;
+
+	LLVector3 np = pos+at_axis;
+	at_axis.normVec();
+
+	//get origin that has given fov for plane np, at_axis, and given scale
+	F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+
+	LLVector3 origin = np - at_axis*dist;
+
+	//matrix from volume space to agent space
+	LLMatrix4 light_mat(quat, LLVector4(origin,1.f));
+
+	glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
+	glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
+
+	glh::matrix4f screen_to_light = light_to_screen.inverse();
+
+	F32 s = volume->getLightRadius()*1.5f;
+	F32 near_clip = dist;
+	F32 width = scale.mV[VX];
+	F32 height = scale.mV[VY];
+	F32 far_clip = s+dist-scale.mV[VZ];
+
+	F32 fovy = fov * RAD_TO_DEG;
+	F32 aspect = width/height;
+
+	glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+				0.f, 0.5f, 0.f, 0.5f,
+				0.f, 0.f, 0.5f, 0.5f,
+				0.f, 0.f, 0.f, 1.f);
+
+	glh::vec3f p1(0, 0, -(near_clip+0.01f));
+	glh::vec3f p2(0, 0, -(near_clip+1.f));
+
+	glh::vec3f screen_origin(0, 0, 0);
+
+	light_to_screen.mult_matrix_vec(p1);
+	light_to_screen.mult_matrix_vec(p2);
+	light_to_screen.mult_matrix_vec(screen_origin);
+
+	glh::vec3f n = p2-p1;
+	n.normalize();
+	
+	F32 proj_range = far_clip - near_clip;
+	glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip);
+	screen_to_light = trans * light_proj * screen_to_light;
+	shader.uniformMatrix4fv(LLShaderMgr::PROJECTOR_MATRIX, 1, FALSE, screen_to_light.m);
+	shader.uniform1f(LLShaderMgr::PROJECTOR_NEAR, near_clip);
+	shader.uniform3fv(LLShaderMgr::PROJECTOR_P, 1, p1.v);
+	shader.uniform3fv(LLShaderMgr::PROJECTOR_N, 1, n.v);
+	shader.uniform3fv(LLShaderMgr::PROJECTOR_ORIGIN, 1, screen_origin.v);
+	shader.uniform1f(LLShaderMgr::PROJECTOR_RANGE, proj_range);
+	shader.uniform1f(LLShaderMgr::PROJECTOR_AMBIANCE, params.mV[2]);
+	S32 s_idx = -1;
+
+	for (U32 i = 0; i < 2; i++)
+	{
+		if (mShadowSpotLight[i] == drawablep)
+		{
+			s_idx = i;
+		}
+	}
+
+	shader.uniform1i(LLShaderMgr::PROJECTOR_SHADOW_INDEX, s_idx);
+
+	if (s_idx >= 0)
+	{
+		shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f-mSpotLightFade[s_idx]);
+	}
+	else
+	{
+		shader.uniform1f(LLShaderMgr::PROJECTOR_SHADOW_FADE, 1.f);
+	}
+
+	{
+		LLDrawable* potential = drawablep;
+		//determine if this is a good light for casting shadows
+		F32 m_pri = volume->getSpotLightPriority();
+
+		for (U32 i = 0; i < 2; i++)
+		{
+			F32 pri = 0.f;
+
+			if (mTargetShadowSpotLight[i].notNull())
+			{
+				pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();			
+			}
+
+			if (m_pri > pri)
+			{
+				LLDrawable* temp = mTargetShadowSpotLight[i];
+				mTargetShadowSpotLight[i] = potential;
+				potential = temp;
+				m_pri = pri;
+			}
+		}
+	}
+
+	LLViewerTexture* img = volume->getLightTexture();
+
+	if (img == NULL)
+	{
+		img = LLViewerFetchedTexture::sWhiteImagep;
+	}
+
+	S32 channel = shader.enableTexture(LLShaderMgr::DEFERRED_PROJECTION);
+
+	if (channel > -1)
+	{
+		if (img)
+		{
+			gGL.getTexUnit(channel)->bind(img);
 
 			F32 lod_range = logf(img->getWidth())/logf(2.f);
 
@@ -9199,6 +9767,12 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			water_clip = 1;
 		}
 
+		bool materials_in_water = false;
+
+#if MATERIALS_IN_REFLECTIONS
+		materials_in_water = gSavedSettings.getS32("RenderWaterMaterials");
+#endif
+
 		if (!LLViewerCamera::getInstance()->cameraUnderWater())
 		{	//generate planar reflection map
 
@@ -9207,7 +9781,9 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			LLPipeline::sUseOcclusion = 0;
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 			glClearColor(0,0,0,0);
+
 			mWaterRef.bindTarget();
+
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER0;
 			gGL.setColorMask(true, true);
 			mWaterRef.clear();
@@ -9256,11 +9832,27 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 					updateCull(camera, result);
 					stateSort(camera, result);
 
+					if (LLPipeline::sRenderDeferred && materials_in_water)
+					{
+						mWaterRef.flush();
+
+						gPipeline.grabReferences(result);
+						gPipeline.mDeferredScreen.bindTarget();
+						gGL.setColorMask(true, true);						
+						glClearColor(0,0,0,0);
+						gPipeline.mDeferredScreen.clear();
+
+						renderGeomDeferred(camera);						
+					}
+					else
+					{
 					renderGeom(camera, TRUE);
+					}					
 
 					gPipeline.popRenderTypeMask();
 				}
 
+				gGL.setColorMask(true, false);
 				gPipeline.pushRenderTypeMask();
 
 				clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
@@ -9298,9 +9890,23 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 					{
 						gPipeline.grabReferences(ref_result);
 						LLGLUserClipPlane clip_plane(plane, mat, projection);
+
+						if (LLPipeline::sRenderDeferred && materials_in_water)
+						{							
+							renderGeomDeferred(camera);
+						}
+						else
+						{
 						renderGeom(camera);
 					}
 				}	
+				}	
+
+				if (LLPipeline::sRenderDeferred && materials_in_water)
+				{
+					gPipeline.mDeferredScreen.flush();
+					renderDeferredLightingToRT(&mWaterRef);
+				}
 
 				gPipeline.popRenderTypeMask();
 			}	
@@ -9336,10 +9942,12 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 			LLViewerCamera::updateFrustumPlanes(camera);
 
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+			
 			LLColor4& col = LLDrawPoolWater::sWaterFogColor;
 			glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
 			mWaterDis.bindTarget();
 			LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WATER1;
+			
 			mWaterDis.getViewport(gGLViewport);
 			
 			if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate)
@@ -9355,14 +9963,36 @@ void LLPipeline::generateWaterReflection(LLCamera& camera_in)
 
 				gGL.setColorMask(true, true);
 				mWaterDis.clear();
+				
+
 				gGL.setColorMask(true, false);
 
+				
+				if (LLPipeline::sRenderDeferred && materials_in_water)
+				{										
+					mWaterDis.flush();
+					gPipeline.mDeferredScreen.bindTarget();
+					gGL.setColorMask(true, true);
+					glClearColor(0,0,0,0);
+					gPipeline.mDeferredScreen.clear();
+					gPipeline.grabReferences(result);
+					renderGeomDeferred(camera);					
+				}
+				else
+				{
 				renderGeom(camera);
+				}
 
+				if (LLPipeline::sRenderDeferred && materials_in_water)
+				{
+					gPipeline.mDeferredScreen.flush();
+					renderDeferredLightingToRT(&mWaterDis);
+				}
 			}
 
-			LLPipeline::sUnderWaterRender = FALSE;
 			mWaterDis.flush();
+			LLPipeline::sUnderWaterRender = FALSE;
+			
 		}
 		last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate;
 
@@ -9769,14 +10399,14 @@ BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector
 			const LLPlane& cp = camera.getAgentPlane(j);
 			F32 dist = cp.dist(pp[i]);
 			if (dist > 0.05f) //point is above some plane, not contained
-			{
+					{
 				found = false;
 				break;
-			}
-		}
+						}
+					}
 
-		if (found)
-		{
+					if (found)
+					{
 			fp.push_back(pp[i]);
 		}
 	}
@@ -10688,29 +11318,37 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	}
 	else
 	{
-		andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
-						LLPipeline::RENDER_TYPE_AVATAR,
+		andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+			LLPipeline::RENDER_TYPE_FULLBRIGHT,
+			LLPipeline::RENDER_TYPE_VOLUME,
+			LLPipeline::RENDER_TYPE_GLOW,
 						LLPipeline::RENDER_TYPE_BUMP,
-						LLPipeline::RENDER_TYPE_GRASS,
-						LLPipeline::RENDER_TYPE_SIMPLE,
-						LLPipeline::RENDER_TYPE_FULLBRIGHT,
-						LLPipeline::RENDER_TYPE_ALPHA, 
-						LLPipeline::RENDER_TYPE_INVISIBLE,
 						LLPipeline::RENDER_TYPE_PASS_SIMPLE,
 						LLPipeline::RENDER_TYPE_PASS_ALPHA,
 						LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+			LLPipeline::RENDER_TYPE_PASS_BUMP,
+			LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
 						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
 						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
 						LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+			LLPipeline::RENDER_TYPE_PASS_GLOW,
+			LLPipeline::RENDER_TYPE_PASS_GRASS,
 						LLPipeline::RENDER_TYPE_PASS_SHINY,
 						LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
 						LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+			LLPipeline::RENDER_TYPE_AVATAR,
+			LLPipeline::RENDER_TYPE_ALPHA_MASK,
+			LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK,
+			LLPipeline::RENDER_TYPE_INVISIBLE,
+			LLPipeline::RENDER_TYPE_SIMPLE,
 						END_RENDER_TYPES);
 	}
 	
 	S32 occlusion = sUseOcclusion;
 	sUseOcclusion = 0;
+
 	sReflectionRender = sRenderDeferred ? FALSE : TRUE;
+
 	sShadowRender = TRUE;
 	sImpostorRender = TRUE;
 
@@ -10805,22 +11443,26 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		if (!avatar->mImpostor.isComplete())
 		{
 			LLFastTimer t(FTM_IMPOSTOR_ALLOCATE);
-			avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
+			
 
 			if (LLPipeline::sRenderDeferred)
 			{
+				avatar->mImpostor.allocate(resX,resY,GL_SRGB8_ALPHA8,TRUE,FALSE);
 				addDeferredAttachments(avatar->mImpostor);
 			}
+			else
+			{
+				avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,FALSE);
+			}
 		
 			gGL.getTexUnit(0)->bind(&avatar->mImpostor);
 			gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
 			gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
 		}
-		else if(resX != avatar->mImpostor.getWidth() ||
-			resY != avatar->mImpostor.getHeight())
+		else if(resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight())
 		{
 			LLFastTimer t(FTM_IMPOSTOR_RESIZE);
-			avatar->mImpostor.resize(resX,resY,GL_RGBA);
+			avatar->mImpostor.resize(resX,resY);
 		}
 
 		avatar->mImpostor.bindTarget();
@@ -10830,7 +11472,23 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 	{
 		avatar->mImpostor.clear();
 		renderGeomDeferred(camera);
+
+		renderGeomPostDeferred(camera);		
+
+		// Shameless hack time: render it all again,
+		// this time writing the depth
+		// values we need to generate the alpha mask below
+		// while preserving the alpha-sorted color rendering
+		// from the previous pass
+		//
+		sImpostorRenderAlphaDepthPass = true;
+		// depth-only here...
+		//
+		gGL.setColorMask(false,false);
 		renderGeomPostDeferred(camera);
+
+		sImpostorRenderAlphaDepthPass = false;
+
 	}
 	else
 	{
@@ -10838,10 +11496,26 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		glScissor(0, 0, resX, resY);
 		avatar->mImpostor.clear();
 		renderGeom(camera);
+
+		// Shameless hack time: render it all again,
+		// this time writing the depth
+		// values we need to generate the alpha mask below
+		// while preserving the alpha-sorted color rendering
+		// from the previous pass
+		//
+		sImpostorRenderAlphaDepthPass = true;
+
+		// depth-only here...
+		//
+		gGL.setColorMask(false,false);
+		renderGeom(camera);
+
+		sImpostorRenderAlphaDepthPass = false;
 	}
 	
 	{ //create alpha mask based on depth buffer (grey out if muted)
 		LLFastTimer t(FTM_IMPOSTOR_BACKGROUND);
+
 		if (LLPipeline::sRenderDeferred)
 		{
 			GLuint buff = GL_COLOR_ATTACHMENT0;
@@ -11226,6 +11900,3 @@ void LLPipeline::restoreHiddenObject( const LLUUID& id )
 	}
 }
 
-
-
-
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index f0bebbe20d869d1421ad8411375d3ec2ffe45da1..fbbcf8f06da1b5dcaba67fe2d81617fe9178e5a8 100755
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -295,7 +295,8 @@ class LLPipeline
 
 	void unbindDeferredShader(LLGLSLShader& shader);
 	void renderDeferredLighting();
-	
+	void renderDeferredLightingToRT(LLRenderTarget* target);
+
 	void generateWaterReflection(LLCamera& camera);
 	void generateSunShadow(LLCamera& camera);
 	void generateHighlight(LLCamera& camera);
@@ -594,6 +595,7 @@ class LLPipeline
 	static BOOL				sPickAvatar;
 	static BOOL				sReflectionRender;
 	static BOOL				sImpostorRender;
+	static BOOL				sImpostorRenderAlphaDepthPass;
 	static BOOL				sUnderWaterRender;
 	static BOOL				sRenderGlow;
 	static BOOL				sTextureBindTest;
diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
index 5ac2ec2b206bbccc4f9e302334dd49c0826e6370..426c0c491554501f57c83ea423603a4605eb8dbc 100644
--- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -663,7 +663,7 @@
              label_width="205"
              layout="topleft"
              left="10"
-             min_val="-1"
+             min_val="0"
              name="bumpyOffsetU"
              width="265" />
             <spinner
@@ -674,7 +674,7 @@
              label_width="205"
              layout="topleft"
              left="10"
-             min_val="-1"
+             min_val="0"
              name="bumpyOffsetV"
              width="265" />
             <spinner
@@ -726,7 +726,7 @@
              label_width="205"
              layout="topleft"
              left="10"
-             min_val="-1"
+             min_val="0"
              name="shinyOffsetU"
              width="265" />
             <spinner
@@ -737,7 +737,7 @@
              label_width="205"
              layout="topleft"
              left="10"
-             min_val="-1"
+             min_val="0"
              name="shinyOffsetV"
              width="265" />
             <check_box